aboutsummaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/AccountMgr.cpp24
-rw-r--r--src/game/AccountMgr.h6
-rw-r--r--src/game/AchievementMgr.cpp1989
-rw-r--r--src/game/AchievementMgr.h270
-rw-r--r--src/game/AddonHandler.cpp69
-rw-r--r--src/game/AddonHandler.h4
-rw-r--r--src/game/AggressorAI.cpp116
-rw-r--r--src/game/AggressorAI.h39
-rw-r--r--src/game/AnimalRandomMovementGenerator.h4
-rw-r--r--src/game/ArenaTeam.cpp78
-rw-r--r--src/game/ArenaTeam.h20
-rw-r--r--src/game/ArenaTeamHandler.cpp9
-rw-r--r--src/game/AuctionHouseBot.cpp54
-rw-r--r--src/game/AuctionHouseHandler.cpp53
-rw-r--r--src/game/AuctionHouseMgr.cpp126
-rw-r--r--src/game/Bag.cpp14
-rw-r--r--src/game/Bag.h7
-rw-r--r--src/game/BattleGround.cpp1108
-rw-r--r--src/game/BattleGround.h234
-rw-r--r--src/game/BattleGroundAA.cpp24
-rw-r--r--src/game/BattleGroundAA.h9
-rw-r--r--src/game/BattleGroundAB.cpp387
-rw-r--r--src/game/BattleGroundAB.h78
-rw-r--r--src/game/BattleGroundAV.cpp50
-rw-r--r--src/game/BattleGroundAV.h8
-rw-r--r--src/game/BattleGroundBE.cpp133
-rw-r--r--src/game/BattleGroundBE.h10
-rw-r--r--src/game/BattleGroundDS.cpp81
-rw-r--r--src/game/BattleGroundDS.h50
-rw-r--r--src/game/BattleGroundEY.cpp369
-rw-r--r--src/game/BattleGroundEY.h81
-rw-r--r--src/game/BattleGroundHandler.cpp511
-rw-r--r--src/game/BattleGroundMgr.cpp1995
-rw-r--r--src/game/BattleGroundMgr.h220
-rw-r--r--src/game/BattleGroundNA.cpp127
-rw-r--r--src/game/BattleGroundNA.h10
-rw-r--r--src/game/BattleGroundRL.cpp128
-rw-r--r--src/game/BattleGroundRL.h12
-rw-r--r--src/game/BattleGroundRV.cpp81
-rw-r--r--src/game/BattleGroundRV.h50
-rw-r--r--src/game/BattleGroundSA.cpp81
-rw-r--r--src/game/BattleGroundSA.h54
-rw-r--r--src/game/BattleGroundWS.cpp344
-rw-r--r--src/game/BattleGroundWS.h31
-rw-r--r--src/game/CMakeLists.txt44
-rw-r--r--src/game/Calendar.cpp (renamed from src/game/PossessedAI.cpp)9
-rw-r--r--src/game/Calendar.h (renamed from src/game/PossessedAI.h)15
-rw-r--r--src/game/CalendarHandler.cpp159
-rw-r--r--src/game/Cell.h8
-rw-r--r--src/game/CellImpl.h4
-rw-r--r--src/game/Channel.cpp34
-rw-r--r--src/game/Channel.h180
-rw-r--r--src/game/ChannelHandler.cpp4
-rw-r--r--src/game/ChannelMgr.h8
-rw-r--r--src/game/CharacterHandler.cpp418
-rw-r--r--src/game/Chat.cpp1165
-rw-r--r--src/game/Chat.h426
-rw-r--r--src/game/ChatHandler.cpp229
-rw-r--r--src/game/CombatHandler.cpp5
-rw-r--r--src/game/ConfusedMovementGenerator.cpp7
-rw-r--r--src/game/ConfusedMovementGenerator.h4
-rw-r--r--src/game/Corpse.cpp69
-rw-r--r--src/game/Corpse.h11
-rw-r--r--src/game/Creature.cpp353
-rw-r--r--src/game/Creature.h161
-rw-r--r--src/game/CreatureAI.cpp175
-rw-r--r--src/game/CreatureAI.h133
-rw-r--r--src/game/CreatureAIFactory.h53
-rw-r--r--src/game/CreatureAIImpl.h162
-rw-r--r--src/game/CreatureAIRegistry.cpp14
-rw-r--r--src/game/CreatureAIRegistry.h4
-rw-r--r--src/game/CreatureAISelector.cpp50
-rw-r--r--src/game/CreatureAISelector.h4
-rw-r--r--src/game/CreatureEventAI.cpp1365
-rw-r--r--src/game/CreatureEventAI.h598
-rw-r--r--src/game/CreatureEventAIMgr.cpp707
-rw-r--r--src/game/CreatureEventAIMgr.h46
-rw-r--r--src/game/CreatureGroups.cpp4
-rw-r--r--src/game/DBCEnums.h331
-rw-r--r--src/game/DBCStores.cpp763
-rw-r--r--src/game/DBCStores.h163
-rw-r--r--src/game/DBCStructure.h1813
-rw-r--r--src/game/DBCfmt.h111
-rw-r--r--src/game/Debugcmds.cpp413
-rw-r--r--src/game/DestinationHolder.cpp4
-rw-r--r--src/game/DestinationHolder.h4
-rw-r--r--src/game/DestinationHolderImp.h24
-rw-r--r--src/game/DuelHandler.cpp6
-rw-r--r--src/game/DynamicObject.cpp35
-rw-r--r--src/game/DynamicObject.h9
-rw-r--r--src/game/FleeingMovementGenerator.cpp57
-rw-r--r--src/game/FleeingMovementGenerator.h24
-rw-r--r--src/game/FollowerRefManager.h4
-rw-r--r--src/game/FollowerReference.cpp4
-rw-r--r--src/game/FollowerReference.h4
-rw-r--r--src/game/Formulas.h79
-rw-r--r--src/game/GameEventMgr.cpp (renamed from src/game/GameEvent.cpp)301
-rw-r--r--src/game/GameEventMgr.h (renamed from src/game/GameEvent.h)40
-rw-r--r--src/game/GameObject.cpp476
-rw-r--r--src/game/GameObject.h115
-rw-r--r--src/game/GlobalEvents.cpp4
-rw-r--r--src/game/GlobalEvents.h4
-rw-r--r--src/game/GossipDef.cpp154
-rw-r--r--src/game/GossipDef.h43
-rw-r--r--src/game/GridDefines.h8
-rw-r--r--src/game/GridNotifiers.cpp55
-rw-r--r--src/game/GridNotifiers.h427
-rw-r--r--src/game/GridNotifiersImpl.h159
-rw-r--r--src/game/GridStates.h4
-rw-r--r--src/game/Group.cpp174
-rw-r--r--src/game/Group.h22
-rw-r--r--src/game/GroupHandler.cpp125
-rw-r--r--src/game/GroupRefManager.h4
-rw-r--r--src/game/GroupReference.cpp4
-rw-r--r--src/game/GroupReference.h4
-rw-r--r--src/game/GuardAI.cpp70
-rw-r--r--src/game/GuardAI.h7
-rw-r--r--src/game/Guild.cpp95
-rw-r--r--src/game/Guild.h42
-rw-r--r--src/game/GuildHandler.cpp33
-rw-r--r--src/game/HomeMovementGenerator.cpp10
-rw-r--r--src/game/HomeMovementGenerator.h5
-rw-r--r--src/game/HostilRefManager.cpp6
-rw-r--r--src/game/HostilRefManager.h4
-rw-r--r--src/game/IdleMovementGenerator.cpp11
-rw-r--r--src/game/IdleMovementGenerator.h14
-rw-r--r--src/game/InstanceData.cpp235
-rw-r--r--src/game/InstanceData.h116
-rw-r--r--src/game/InstanceSaveMgr.cpp61
-rw-r--r--src/game/InstanceSaveMgr.h8
-rw-r--r--src/game/Item.cpp81
-rw-r--r--src/game/Item.h60
-rw-r--r--src/game/ItemEnchantmentMgr.cpp12
-rw-r--r--src/game/ItemEnchantmentMgr.h4
-rw-r--r--src/game/ItemHandler.cpp242
-rw-r--r--src/game/ItemPrototype.h112
-rw-r--r--src/game/LFGHandler.cpp4
-rw-r--r--src/game/Language.h255
-rw-r--r--src/game/Level0.cpp28
-rw-r--r--src/game/Level1.cpp811
-rw-r--r--src/game/Level2.cpp2784
-rw-r--r--src/game/Level3.cpp1924
-rw-r--r--src/game/LootHandler.cpp58
-rw-r--r--src/game/LootMgr.cpp258
-rw-r--r--src/game/LootMgr.h93
-rw-r--r--src/game/Mail.cpp52
-rw-r--r--src/game/Mail.h8
-rw-r--r--src/game/Makefile.am850
-rw-r--r--src/game/Map.cpp1375
-rw-r--r--src/game/Map.h233
-rw-r--r--src/game/MapInstanced.cpp133
-rw-r--r--src/game/MapInstanced.h6
-rw-r--r--src/game/MapManager.cpp21
-rw-r--r--src/game/MapManager.h41
-rw-r--r--src/game/MapRefManager.h2
-rw-r--r--src/game/MapReference.h2
-rw-r--r--src/game/MiscHandler.cpp273
-rw-r--r--src/game/MotionMaster.cpp137
-rw-r--r--src/game/MotionMaster.h22
-rw-r--r--src/game/MovementGenerator.cpp4
-rw-r--r--src/game/MovementGenerator.h4
-rw-r--r--src/game/MovementGeneratorImpl.h4
-rw-r--r--src/game/MovementHandler.cpp478
-rw-r--r--src/game/NPCHandler.cpp190
-rw-r--r--src/game/NPCHandler.h5
-rw-r--r--src/game/NullCreatureAI.cpp4
-rw-r--r--src/game/NullCreatureAI.h27
-rw-r--r--src/game/Object.cpp1011
-rw-r--r--src/game/Object.h92
-rw-r--r--src/game/ObjectAccessor.cpp224
-rw-r--r--src/game/ObjectAccessor.h71
-rw-r--r--src/game/ObjectDefines.h8
-rw-r--r--src/game/ObjectGridLoader.cpp34
-rw-r--r--src/game/ObjectMgr.cpp1572
-rw-r--r--src/game/ObjectMgr.h139
-rw-r--r--src/game/ObjectPosSelector.cpp157
-rw-r--r--src/game/ObjectPosSelector.h155
-rw-r--r--src/game/Opcodes.cpp2261
-rw-r--r--src/game/Opcodes.h407
-rw-r--r--src/game/OutdoorPvP.cpp79
-rw-r--r--src/game/OutdoorPvP.h55
-rw-r--r--src/game/OutdoorPvPEP.cpp22
-rw-r--r--src/game/OutdoorPvPEP.h6
-rw-r--r--src/game/OutdoorPvPHP.cpp56
-rw-r--r--src/game/OutdoorPvPHP.h9
-rw-r--r--src/game/OutdoorPvPImpl.h39
-rw-r--r--src/game/OutdoorPvPMgr.cpp36
-rw-r--r--src/game/OutdoorPvPMgr.h2
-rw-r--r--src/game/OutdoorPvPNA.cpp49
-rw-r--r--src/game/OutdoorPvPNA.h5
-rw-r--r--src/game/OutdoorPvPObjectiveAI.cpp3
-rw-r--r--src/game/OutdoorPvPObjectiveAI.h4
-rw-r--r--src/game/OutdoorPvPSI.cpp72
-rw-r--r--src/game/OutdoorPvPSI.h5
-rw-r--r--src/game/OutdoorPvPTF.cpp56
-rw-r--r--src/game/OutdoorPvPTF.h5
-rw-r--r--src/game/OutdoorPvPZM.cpp55
-rw-r--r--src/game/OutdoorPvPZM.h7
-rw-r--r--src/game/Path.h4
-rw-r--r--src/game/Pet.cpp1685
-rw-r--r--src/game/Pet.h131
-rw-r--r--src/game/PetAI.cpp98
-rw-r--r--src/game/PetAI.h8
-rw-r--r--src/game/PetHandler.cpp305
-rw-r--r--src/game/PetitionsHandler.cpp41
-rw-r--r--src/game/Player.cpp7758
-rw-r--r--src/game/Player.h823
-rw-r--r--src/game/PlayerDump.cpp103
-rw-r--r--src/game/PlayerDump.h13
-rw-r--r--src/game/PointMovementGenerator.cpp19
-rw-r--r--src/game/PointMovementGenerator.h20
-rw-r--r--src/game/PoolHandler.cpp720
-rw-r--r--src/game/PoolHandler.h104
-rw-r--r--src/game/QueryHandler.cpp121
-rw-r--r--src/game/QuestDef.cpp121
-rw-r--r--src/game/QuestDef.h54
-rw-r--r--src/game/QuestHandler.cpp31
-rw-r--r--src/game/RandomMovementGenerator.cpp33
-rw-r--r--src/game/RandomMovementGenerator.h4
-rw-r--r--src/game/ReactorAI.cpp73
-rw-r--r--src/game/ReactorAI.h12
-rw-r--r--src/game/ReputationMgr.cpp473
-rw-r--r--src/game/ReputationMgr.h146
-rw-r--r--src/game/ScriptCalls.cpp11
-rw-r--r--src/game/ScriptCalls.h12
-rw-r--r--src/game/SharedDefines.h790
-rw-r--r--src/game/SkillDiscovery.cpp89
-rw-r--r--src/game/SkillDiscovery.h5
-rw-r--r--src/game/SkillExtraItems.cpp4
-rw-r--r--src/game/SkillExtraItems.h4
-rw-r--r--src/game/SkillHandler.cpp112
-rw-r--r--src/game/SocialMgr.cpp36
-rw-r--r--src/game/SocialMgr.h7
-rw-r--r--src/game/Spell.cpp2961
-rw-r--r--src/game/Spell.h220
-rw-r--r--src/game/SpellAuraDefines.h130
-rw-r--r--src/game/SpellAuras.cpp5708
-rw-r--r--src/game/SpellAuras.h587
-rw-r--r--src/game/SpellEffects.cpp3963
-rw-r--r--src/game/SpellHandler.cpp245
-rw-r--r--src/game/SpellMgr.cpp2622
-rw-r--r--src/game/SpellMgr.h563
-rw-r--r--src/game/StatSystem.cpp228
-rw-r--r--src/game/TargetedMovementGenerator.cpp42
-rw-r--r--src/game/TargetedMovementGenerator.h6
-rw-r--r--src/game/TaxiHandler.cpp47
-rw-r--r--src/game/TemporarySummon.cpp166
-rw-r--r--src/game/TemporarySummon.h49
-rw-r--r--src/game/ThreatManager.cpp89
-rw-r--r--src/game/ThreatManager.h53
-rw-r--r--src/game/TicketHandler.cpp4
-rw-r--r--src/game/TicketMgr.cpp4
-rw-r--r--src/game/TicketMgr.h4
-rw-r--r--src/game/Tools.cpp4
-rw-r--r--src/game/Tools.h4
-rw-r--r--src/game/Totem.cpp153
-rw-r--r--src/game/Totem.h20
-rw-r--r--src/game/TotemAI.cpp67
-rw-r--r--src/game/TotemAI.h8
-rw-r--r--src/game/TradeHandler.cpp42
-rw-r--r--src/game/Transports.cpp125
-rw-r--r--src/game/Transports.h26
-rw-r--r--src/game/Traveller.h71
-rw-r--r--src/game/Unit.cpp10034
-rw-r--r--src/game/Unit.h612
-rw-r--r--src/game/UnitAI.cpp356
-rw-r--r--src/game/UnitAI.h93
-rw-r--r--src/game/UnitEvents.h4
-rw-r--r--src/game/UpdateData.cpp10
-rw-r--r--src/game/UpdateData.h9
-rw-r--r--src/game/UpdateFields.h535
-rw-r--r--src/game/UpdateMask.h36
-rw-r--r--src/game/Vehicle.cpp390
-rw-r--r--src/game/Vehicle.h81
-rw-r--r--src/game/VoiceChatHandler.cpp5
-rw-r--r--src/game/WaypointManager.cpp25
-rw-r--r--src/game/WaypointManager.h15
-rw-r--r--src/game/WaypointMovementGenerator.cpp51
-rw-r--r--src/game/WaypointMovementGenerator.h12
-rw-r--r--src/game/Weather.cpp9
-rw-r--r--src/game/Weather.h6
-rw-r--r--src/game/Wintergrasp.cpp134
-rw-r--r--src/game/Wintergrasp.h75
-rw-r--r--src/game/World.cpp700
-rw-r--r--src/game/World.h96
-rw-r--r--src/game/WorldLog.cpp78
-rw-r--r--src/game/WorldLog.h38
-rw-r--r--src/game/WorldSession.cpp259
-rw-r--r--src/game/WorldSession.h96
-rw-r--r--src/game/WorldSocket.cpp137
-rw-r--r--src/game/WorldSocket.h4
-rw-r--r--src/game/WorldSocketMgr.cpp8
-rw-r--r--src/game/WorldSocketMgr.h4
-rw-r--r--src/game/pchdef.cpp1
-rw-r--r--src/game/pchdef.h16
295 files changed, 55511 insertions, 30356 deletions
diff --git a/src/game/AccountMgr.cpp b/src/game/AccountMgr.cpp
index 6d27df2cb73..86de06a30e0 100644
--- a/src/game/AccountMgr.cpp
+++ b/src/game/AccountMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,11 +25,7 @@
#include "Policies/SingletonImp.h"
#include "Util.h"
-#ifdef DO_POSTGRESQL
-extern DatabasePostgre LoginDatabase;
-#else
-extern DatabaseMysql LoginDatabase;
-#endif
+extern DatabaseType LoginDatabase;
INSTANTIATE_SINGLETON_1(AccountMgr);
@@ -44,8 +40,8 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
if(utf8length(username) > MAX_ACCOUNT_STR)
return AOR_NAME_TOO_LONG; // username's too long
- normilizeString(username);
- normilizeString(password);
+ normalizeString(username);
+ normalizeString(password);
LoginDatabase.escape_string(username);
LoginDatabase.escape_string(password);
@@ -124,8 +120,8 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname,
if(utf8length(new_passwd) > MAX_ACCOUNT_STR)
return AOR_PASS_TOO_LONG;
- normilizeString(new_uname);
- normilizeString(new_passwd);
+ normalizeString(new_uname);
+ normalizeString(new_passwd);
LoginDatabase.escape_string(new_uname);
LoginDatabase.escape_string(new_passwd);
@@ -145,7 +141,7 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
if (utf8length(new_passwd) > MAX_ACCOUNT_STR)
return AOR_PASS_TOO_LONG;
- normilizeString(new_passwd);
+ normalizeString(new_passwd);
LoginDatabase.escape_string(new_passwd);
if(!LoginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid))
@@ -196,7 +192,7 @@ bool AccountMgr::GetName(uint32 acc_id, std::string &name)
bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
{
- normilizeString(passwd);
+ normalizeString(passwd);
LoginDatabase.escape_string(passwd);
QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", accid, passwd.c_str());
@@ -209,7 +205,7 @@ bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
return false;
}
-bool AccountMgr::normilizeString(std::string& utf8str)
+bool AccountMgr::normalizeString(std::string& utf8str)
{
wchar_t wstr_buf[MAX_ACCOUNT_STR+1];
diff --git a/src/game/AccountMgr.h b/src/game/AccountMgr.h
index febd5c6216b..a402b48ad4f 100644
--- a/src/game/AccountMgr.h
+++ b/src/game/AccountMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,7 +53,7 @@ class AccountMgr
uint32 GetSecurity(uint32 acc_id);
bool GetName(uint32 acc_id, std::string &name);
- static bool normilizeString(std::string& utf8str);
+ static bool normalizeString(std::string& utf8str);
};
#define accmgr Trinity::Singleton<AccountMgr>::Instance()
diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp
new file mode 100644
index 00000000000..dad2a5eb488
--- /dev/null
+++ b/src/game/AchievementMgr.cpp
@@ -0,0 +1,1989 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "AchievementMgr.h"
+#include "Common.h"
+#include "Player.h"
+#include "WorldPacket.h"
+#include "DBCEnums.h"
+#include "GameEventMgr.h"
+#include "ObjectMgr.h"
+#include "Guild.h"
+#include "Database/DatabaseEnv.h"
+#include "World.h"
+#include "SpellMgr.h"
+#include "ArenaTeam.h"
+#include "ProgressBar.h"
+#include "GridNotifiersImpl.h"
+#include "CellImpl.h"
+#include "Language.h"
+
+#include "Policies/SingletonImp.h"
+
+INSTANTIATE_SINGLETON_1(AchievementGlobalMgr);
+
+namespace MaNGOS
+{
+ class AchievementChatBuilder
+ {
+ public:
+ AchievementChatBuilder(Player const& pl, ChatMsg msgtype, int32 textId, uint32 ach_id)
+ : i_player(pl), i_msgtype(msgtype), i_textId(textId), i_achievementId(ach_id) {}
+ void operator()(WorldPacket& data, int32 loc_idx)
+ {
+ char const* text = objmgr.GetMangosString(i_textId,loc_idx);
+
+ data << uint8(i_msgtype);
+ data << uint32(LANG_UNIVERSAL);
+ data << uint64(i_player.GetGUID());
+ data << uint32(5);
+ data << uint64(i_player.GetGUID());
+ data << uint32(strlen(text)+1);
+ data << text;
+ data << uint8(0);
+ data << uint32(i_achievementId);
+ }
+
+ private:
+ Player const& i_player;
+ ChatMsg i_msgtype;
+ int32 i_textId;
+ uint32 i_achievementId;
+ };
+} // namespace MaNGOS
+
+
+bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
+{
+ if(dataType >= MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE)
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` for criteria (Entry: %u) have wrong data type (%u), ignore.", criteria->ID,dataType);
+ return false;
+ }
+
+ switch(criteria->requiredType)
+ {
+ case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
+ break;
+ default:
+ sLog.outErrorDb( "Table `achievement_criteria_data` have data for not supported criteria type (Entry: %u Type: %u), ignore.", criteria->ID, criteria->requiredType);
+ return false;
+ }
+
+ switch(dataType)
+ {
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE:
+ return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE:
+ if(!creature.id || !objmgr.GetCreatureTemplate(creature.id))
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) have not existed creature id in value1 (%u), ignore.",
+ criteria->ID, criteria->requiredType,dataType,creature.id);
+ return false;
+ }
+ return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE:
+ if(!classRace.class_id && !classRace.race_id)
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE (%u) must have not 0 in one from value fields, ignore.",
+ criteria->ID, criteria->requiredType,dataType);
+ return false;
+ }
+ 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) have not existed class in value1 (%u), ignore.",
+ 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) have not existed race in value2 (%u), ignore.",
+ criteria->ID, criteria->requiredType,dataType,classRace.race_id);
+ return false;
+ }
+ return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH:
+ if(health.percent < 1 || health.percent > 100)
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) have wrong percent value in value1 (%u), ignore.",
+ criteria->ID, criteria->requiredType,dataType,health.percent);
+ return false;
+ }
+ return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD:
+ if(player_dead.own_team_flag > 1)
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong boolean value1 (%u).",
+ criteria->ID, criteria->requiredType,dataType,player_dead.own_team_flag);
+ return false;
+ }
+ return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA:
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA:
+ {
+ SpellEntry const* spellEntry = sSpellStore.LookupEntry(aura.spell_id);
+ if(!spellEntry)
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong spell id in value1 (%u), ignore.",
+ criteria->ID, criteria->requiredType,(dataType==ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"),dataType,aura.spell_id);
+ return false;
+ }
+ if(aura.effect_idx >= 3)
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong spell effect index in value2 (%u), ignore.",
+ criteria->ID, criteria->requiredType,(dataType==ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"),dataType,aura.effect_idx);
+ return false;
+ }
+ if(!spellEntry->EffectApplyAuraName[aura.effect_idx])
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have non-aura spell effect (ID: %u Effect: %u), ignore.",
+ criteria->ID, criteria->requiredType,(dataType==ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"),dataType,aura.spell_id,aura.effect_idx);
+ return false;
+ }
+ return true;
+ }
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
+ if(!GetAreaEntryByAreaID(area.id))
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) have wrong area id in value1 (%u), ignore.",
+ criteria->ID, criteria->requiredType,dataType,area.id);
+ return false;
+ }
+ return true;
+ default:
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) have data for not supported data type (%u), ignore.", criteria->ID, criteria->requiredType,dataType);
+ return false;
+ }
+ return false;
+}
+
+bool AchievementCriteriaData::Meets(Player const* source, Unit const* target) const
+{
+ switch(dataType)
+ {
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE:
+ return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE:
+ if (!target || target->GetTypeId()!=TYPEID_UNIT)
+ return false;
+ if (target->GetEntry() != creature.id)
+ return false;
+ return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE:
+ if (!target || target->GetTypeId()!=TYPEID_PLAYER)
+ return false;
+ if(classRace.class_id && classRace.class_id != ((Player*)target)->getClass())
+ return false;
+ if(classRace.race_id && classRace.race_id != ((Player*)target)->getRace())
+ return false;
+ return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH:
+ if (!target || target->GetTypeId()!=TYPEID_PLAYER)
+ return false;
+ return target->GetHealth()*100 <= health.percent*target->GetMaxHealth();
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD:
+ if (!target || target->GetTypeId() != TYPEID_PLAYER || target->isAlive() || ((Player*)target)->GetDeathTimer() == 0)
+ return false;
+ // flag set == must be same team, not set == different team
+ return (((Player*)target)->GetTeam() == source->GetTeam()) == (player_dead.own_team_flag != 0);
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA:
+ return source->HasAuraEffect(aura.spell_id,aura.effect_idx);
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
+ {
+ uint32 zone_id,area_id;
+ source->GetZoneAndAreaId(zone_id,area_id);
+ return area.id==zone_id || area.id==area_id;
+ }
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA:
+ return target && target->HasAuraEffect(aura.spell_id,aura.effect_idx);
+ }
+
+ return false;
+}
+
+bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target) const
+{
+ for(Storage::const_iterator itr = storage.begin(); itr != storage.end(); ++itr)
+ if(!itr->Meets(source,target))
+ return false;
+
+ return true;
+}
+
+AchievementMgr::AchievementMgr(Player *player)
+{
+ m_player = player;
+}
+
+AchievementMgr::~AchievementMgr()
+{
+}
+
+void AchievementMgr::Reset()
+{
+ for(CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter!=m_completedAchievements.end(); ++iter)
+ {
+ WorldPacket data(SMSG_ACHIEVEMENT_DELETED,4);
+ data << uint32(iter->first);
+ m_player->SendDirectMessage(&data);
+ }
+
+ for(CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter)
+ {
+ WorldPacket data(SMSG_CRITERIA_DELETED,4);
+ data << uint32(iter->first);
+ m_player->SendDirectMessage(&data);
+ }
+
+ m_completedAchievements.clear();
+ m_criteriaProgress.clear();
+ DeleteFromDB(m_player->GetGUIDLow());
+
+ // re-fill data
+ CheckAllAchievementCriteria();
+}
+
+void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1, uint32 miscvalue2)
+{
+ if((sLog.getLogFilter() & LOG_FILTER_ACHIEVEMENT_UPDATES)==0)
+ sLog.outDetail("AchievementMgr::ResetAchievementCriteria(%u, %u, %u)", type, miscvalue1, miscvalue2);
+
+ if (!sWorld.getConfig(CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS) && m_player->GetSession()->GetSecurity() > SEC_PLAYER)
+ return;
+
+ AchievementCriteriaEntryList const& achievementCriteriaList = achievementmgr.GetAchievementCriteriaByType(type);
+ for(AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i)
+ {
+ AchievementCriteriaEntry const *achievementCriteria = (*i);
+
+ AchievementEntry const *achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
+ if (!achievement)
+ continue;
+
+ // don't update already completed criteria
+ if (IsCompletedCriteria(achievementCriteria,achievement))
+ continue;
+
+ switch (type)
+ {
+ case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: // have total statistic also not expected to be reset
+ case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: // have total statistic also not expected to be reset
+ if (achievementCriteria->healing_done.flag == miscvalue1 &&
+ achievementCriteria->healing_done.mapid == miscvalue2)
+ SetCriteriaProgress(achievementCriteria, 0, PROGRESS_SET);
+ break;
+ default: // reset all cases
+ break;
+ }
+ }
+}
+
+void AchievementMgr::DeleteFromDB(uint32 lowguid)
+{
+ CharacterDatabase.BeginTransaction ();
+ CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE guid = %u",lowguid);
+ CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE guid = %u",lowguid);
+ CharacterDatabase.CommitTransaction ();
+}
+
+void AchievementMgr::SaveToDB()
+{
+ if(!m_completedAchievements.empty())
+ {
+ bool need_execute = false;
+ std::ostringstream ssdel;
+ std::ostringstream ssins;
+ for(CompletedAchievementMap::iterator iter = m_completedAchievements.begin(); iter!=m_completedAchievements.end(); ++iter)
+ {
+ if(!iter->second.changed)
+ continue;
+
+ /// first new/changed record prefix
+ if(!need_execute)
+ {
+ ssdel << "DELETE FROM character_achievement WHERE guid = " << GetPlayer()->GetGUIDLow() << " AND achievement IN (";
+ ssins << "INSERT INTO character_achievement (guid, achievement, date) VALUES ";
+ need_execute = true;
+ }
+ /// next new/changed record prefix
+ else
+ {
+ ssdel << ", ";
+ ssins << ", ";
+ }
+
+ // new/changed record data
+ ssdel << iter->first;
+ ssins << "("<<GetPlayer()->GetGUIDLow() << ", " << iter->first << ", " << uint64(iter->second.date) << ")";
+
+ /// mark as saved in db
+ iter->second.changed = false;
+ }
+
+ if(need_execute)
+ ssdel << ")";
+
+ if(need_execute)
+ {
+ CharacterDatabase.Execute( ssdel.str().c_str() );
+ CharacterDatabase.Execute( ssins.str().c_str() );
+ }
+ }
+
+ if(!m_criteriaProgress.empty())
+ {
+ /// prepare deleting and insert
+ bool need_execute_del = false;
+ bool need_execute_ins = false;
+ std::ostringstream ssdel;
+ std::ostringstream ssins;
+ for(CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter)
+ {
+ if(!iter->second.changed)
+ continue;
+
+ // deleted data (including 0 progress state)
+ {
+ /// first new/changed record prefix (for any counter value)
+ if(!need_execute_del)
+ {
+ ssdel << "DELETE FROM character_achievement_progress WHERE guid = " << GetPlayer()->GetGUIDLow() << " AND criteria IN (";
+ need_execute_del = true;
+ }
+ /// next new/changed record prefix
+ else
+ ssdel << ", ";
+
+ // new/changed record data
+ ssdel << iter->first;
+ }
+
+ // store data only for real progress
+ if(iter->second.counter != 0)
+ {
+ /// first new/changed record prefix
+ if(!need_execute_ins)
+ {
+ ssins << "INSERT INTO character_achievement_progress (guid, criteria, counter, date) VALUES ";
+ need_execute_ins = true;
+ }
+ /// next new/changed record prefix
+ else
+ ssins << ", ";
+
+ // new/changed record data
+ ssins << "(" << GetPlayer()->GetGUIDLow() << ", " << iter->first << ", " << iter->second.counter << ", " << iter->second.date << ")";
+ }
+
+ /// mark as updated in db
+ iter->second.changed = false;
+ }
+
+ if(need_execute_del) // DELETE ... IN (.... _)_
+ ssdel << ")";
+
+ if(need_execute_del || need_execute_ins)
+ {
+ if(need_execute_del)
+ CharacterDatabase.Execute( ssdel.str().c_str() );
+ if(need_execute_ins)
+ CharacterDatabase.Execute( ssins.str().c_str() );
+ }
+ }
+}
+
+void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *criteriaResult)
+{
+ if(achievementResult)
+ {
+ do
+ {
+ Field *fields = achievementResult->Fetch();
+
+ uint32 achievement_id = fields[0].GetUInt32();
+
+ // don't must happen: cleanup at server startup in achievementmgr.LoadCompletedAchievements()
+ if(!sAchievementStore.LookupEntry(achievement_id))
+ continue;
+
+ CompletedAchievementData& ca = m_completedAchievements[achievement_id];
+ ca.date = time_t(fields[1].GetUInt64());
+ ca.changed = false;
+ } while(achievementResult->NextRow());
+ delete achievementResult;
+ }
+
+ if(criteriaResult)
+ {
+ do
+ {
+ Field *fields = criteriaResult->Fetch();
+
+ uint32 id = fields[0].GetUInt32();
+ uint32 counter = fields[1].GetUInt32();
+ time_t date = time_t(fields[2].GetUInt64());
+
+ AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(id);
+ if (!criteria)
+ {
+ // we will remove not existed criteria for all characters
+ sLog.outError("Not existed achievement creataria %u data removed from table `character_achievement_progress`.",id);
+ CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE criteria = %u",id);
+ continue;
+ }
+
+ if (criteria->timeLimit && time_t(date + criteria->timeLimit) < time(NULL))
+ continue;
+
+ CriteriaProgress& progress = m_criteriaProgress[id];
+ progress.counter = counter;
+ progress.date = date;
+ progress.changed = false;
+ } while(criteriaResult->NextRow());
+ delete criteriaResult;
+ }
+
+}
+
+void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement)
+{
+ if(GetPlayer()->GetSession()->PlayerLoading())
+ return;
+
+ #ifdef TRINITY_DEBUG
+ if((sLog.getLogFilter() & LOG_FILTER_ACHIEVEMENT_UPDATES)==0)
+ sLog.outDebug("AchievementMgr::SendAchievementEarned(%u)", achievement->ID);
+ #endif
+
+ if(Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()))
+ {
+ MaNGOS::AchievementChatBuilder say_builder(*GetPlayer(), CHAT_MSG_GUILD_ACHIEVEMENT, LANG_ACHIEVEMENT_EARNED,achievement->ID);
+ MaNGOS::LocalizedPacketDo<MaNGOS::AchievementChatBuilder> say_do(say_builder);
+ guild->BroadcastWorker(say_do,GetPlayer());
+ }
+
+ if(achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_KILL|ACHIEVEMENT_FLAG_REALM_FIRST_REACH))
+ {
+ // broadcast realm first reached
+ WorldPacket data(SMSG_SERVER_FIRST_ACHIEVEMENT, strlen(GetPlayer()->GetName())+1+8+4+4);
+ data << GetPlayer()->GetName();
+ data << uint64(GetPlayer()->GetGUID());
+ data << uint32(achievement->ID);
+ data << uint32(0); // 1=link supplied string as player name, 0=display plain string
+ sWorld.SendGlobalMessage(&data);
+ }
+ else
+ {
+ CellPair p = MaNGOS::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
+
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::AchievementChatBuilder say_builder(*GetPlayer(), CHAT_MSG_ACHIEVEMENT, LANG_ACHIEVEMENT_EARNED,achievement->ID);
+ MaNGOS::LocalizedPacketDo<MaNGOS::AchievementChatBuilder> say_do(say_builder);
+ MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::AchievementChatBuilder> > say_worker(GetPlayer(),sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),say_do);
+ TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::AchievementChatBuilder> >, WorldTypeMapContainer > message(say_worker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, message, *GetPlayer()->GetMap());
+ }
+
+ WorldPacket data(SMSG_ACHIEVEMENT_EARNED, 8+4+8);
+ data.append(GetPlayer()->GetPackGUID());
+ data << uint32(achievement->ID);
+ data << uint32(secsToTimeBitFields(time(NULL)));
+ data << uint32(0);
+ GetPlayer()->SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY), true);
+}
+
+void AchievementMgr::SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress)
+{
+ WorldPacket data(SMSG_CRITERIA_UPDATE, 8+4+8);
+ data << uint32(id);
+
+ // the counter is packed like a packed Guid
+ data.appendPackGUID(progress->counter);
+
+ data.append(GetPlayer()->GetPackGUID());
+ data << uint32(0);
+ data << uint32(secsToTimeBitFields(progress->date));
+ data << uint32(0); // timer 1
+ data << uint32(0); // timer 2
+ GetPlayer()->SendDirectMessage(&data);
+}
+
+/**
+ * called at player login. The player might have fulfilled some achievements when the achievement system wasn't working yet
+ */
+void AchievementMgr::CheckAllAchievementCriteria()
+{
+ // suppress sending packets
+ for(uint32 i=0; i<ACHIEVEMENT_CRITERIA_TYPE_TOTAL; ++i)
+ UpdateAchievementCriteria(AchievementCriteriaTypes(i));
+}
+
+static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = { 1057, 1107, 1108 };
+static const uint32 achievIdForDangeon[][4] =
+{
+ // ach_cr_id,is_dungeon,is_raid,is_heroic_dungeon
+ { 321, true, true, true },
+ { 916, false, true, false },
+ { 917, false, true, false },
+ { 918, true, false, false },
+ { 2219, false, false, true },
+ { 0, false, false, false }
+};
+
+/**
+ * this function will be called whenever the user might have done a criteria relevant action
+ */
+void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1, uint32 miscvalue2, Unit *unit, uint32 time)
+{
+ if((sLog.getLogFilter() & LOG_FILTER_ACHIEVEMENT_UPDATES)==0)
+ sLog.outDetail("AchievementMgr::UpdateAchievementCriteria(%u, %u, %u, %u)", type, miscvalue1, miscvalue2, time);
+
+ if (!sWorld.getConfig(CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS) && m_player->GetSession()->GetSecurity() > SEC_PLAYER)
+ return;
+
+ AchievementCriteriaEntryList const& achievementCriteriaList = achievementmgr.GetAchievementCriteriaByType(type);
+ for(AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i)
+ {
+ AchievementCriteriaEntry const *achievementCriteria = (*i);
+
+ if (achievementCriteria->groupFlag & ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP && GetPlayer()->GetGroup())
+ continue;
+
+ AchievementEntry const *achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
+ if (!achievement)
+ continue;
+
+ if ((achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_HORDE && GetPlayer()->GetTeam() != HORDE) ||
+ (achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE))
+ continue;
+
+ // don't update already completed criteria
+ if (IsCompletedCriteria(achievementCriteria,achievement))
+ continue;
+
+ switch (type)
+ {
+ // std. case: increment at 1
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
+ case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
+ case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
+ case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
+ case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ // std case: increment at miscvalue1
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
+ case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
+ case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED:
+ case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_ACCUMULATE);
+ break;
+ // std case: high value at miscvalue1
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_HIGHEST);
+ break;
+
+ // specialized cases
+
+ case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ if(achievementCriteria->kill_creature.creatureID != miscvalue1)
+ continue;
+
+ // LOT achievement->ID required special custom checks
+ switch(achievement->ID)
+ {
+ // Just heroic
+ case 489: case 490: case 491: case 492: case 493: case 494: case 495:
+ case 496: case 497: case 498: case 499: case 500: case 563: case 565:
+ case 567: case 569: case 573: case 575: case 577: case 623: case 625:
+ case 667: case 668: case 669: case 670: case 671: case 672: case 673:
+ case 674: case 675: case 676: case 677: case 678: case 679: case 680:
+ case 681: case 682: case 1367: case 1368: case 1378: case 1379:
+ case 1380: case 1381: case 1382: case 1383: case 1384: case 1385:
+ case 1386: case 1387: case 1388: case 1389: case 1390: case 1393:
+ case 1394: case 1400: case 1402: case 1504: case 1505: case 1506:
+ case 1507: case 1508: case 1509: case 1510: case 1511: case 1512:
+ case 1513: case 1514: case 1515: case 1721: case 1754: case 1756:
+ case 1768: case 1817: case 1865:
+ if(GetPlayer()->GetDifficulty()!=DIFFICULTY_HEROIC)
+ continue;
+ break;
+ // Heroic + other
+ case 579: case 1296: case 1297: case 1816: case 1834: case 1857: case 1859:
+ case 1860: case 1861: case 1862: case 1864: case 1866: case 1867: case 1868:
+ case 1870: case 1871: case 1872: case 1873: case 1875: case 1877: case 1919:
+ case 2036: case 2037: case 2038: case 2039: case 2040: case 2041: case 2042:
+ case 2043: case 2044: case 2045: case 2046: case 2048: case 2052: case 2053:
+ case 2054: case 2056: case 2057: case 2058: case 2139: case 2140: case 2147:
+ case 2149: case 2150: case 2151: case 2152: case 2154: case 2155: case 2156:
+ case 2157: case 2179: case 2181: case 2183: case 2185: case 2186:
+ if(GetPlayer()->GetDifficulty()!=DIFFICULTY_HEROIC)
+ continue;
+ // FIX ME: mark as fail always until implement
+ continue;
+ // Normal + other
+ case 578: case 624: case 1790: case 1856: case 1858: case 1869: case 1874:
+ case 1996: case 1997: case 2047: case 2049: case 2050: case 2051: case 2146:
+ case 2148: case 2153: case 2178: case 2180: case 2182: case 2184: case 2187:
+ if(GetPlayer()->GetDifficulty()!=DIFFICULTY_NORMAL)
+ continue;
+ // FIX ME: mark as fail always until implement
+ continue;
+ // Just Normal
+ default:
+ if(GetPlayer()->GetDifficulty()!=DIFFICULTY_NORMAL)
+ continue;
+ break;
+ };
+
+ SetCriteriaProgress(achievementCriteria, miscvalue2, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->getLevel());
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
+ // update at loading or specific skill update
+ if(miscvalue1 && miscvalue1 != achievementCriteria->reach_skill_level.skillID)
+ continue;
+ if(uint32 skillvalue = GetPlayer()->GetBaseSkillValue(achievementCriteria->reach_skill_level.skillID))
+ SetCriteriaProgress(achievementCriteria, skillvalue);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
+ // update at loading or specific skill update
+ if(miscvalue1 && miscvalue1 != achievementCriteria->learn_skill_level.skillID)
+ continue;
+ if(uint32 maxSkillvalue = GetPlayer()->GetPureMaxSkillValue(achievementCriteria->learn_skill_level.skillID))
+ SetCriteriaProgress(achievementCriteria, maxSkillvalue);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
+ if(m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) != m_completedAchievements.end())
+ SetCriteriaProgress(achievementCriteria, 1);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
+ {
+ uint32 counter =0;
+ for(QuestStatusMap::const_iterator itr = GetPlayer()->getQuestStatusMap().begin(); itr!=GetPlayer()->getQuestStatusMap().end(); itr++)
+ if(itr->second.m_rewarded)
+ counter++;
+ SetCriteriaProgress(achievementCriteria, counter);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
+ {
+ // speedup for non-login case
+ if(miscvalue1 && miscvalue1 != achievementCriteria->complete_quests_in_zone.zoneID)
+ continue;
+
+ uint32 counter =0;
+ for(QuestStatusMap::const_iterator itr = GetPlayer()->getQuestStatusMap().begin(); itr!=GetPlayer()->getQuestStatusMap().end(); itr++)
+ {
+ Quest const* quest = objmgr.GetQuestTemplate(itr->first);
+ if(itr->second.m_rewarded && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->complete_quests_in_zone.zoneID)
+ counter++;
+ }
+ SetCriteriaProgress(achievementCriteria, counter);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ if(GetPlayer()->GetMapId() != achievementCriteria->complete_battleground.mapID)
+ continue;
+ SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ if(GetPlayer()->GetMapId() != achievementCriteria->death_at_map.mapID)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
+ {
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ // skip wrong arena achievements, if not achievIdByArenaSlot then normal total death counter
+ bool notfit = false;
+ for(int j = 0; j < MAX_ARENA_SLOT; ++j)
+ {
+ if(achievIdByArenaSlot[j] == achievement->ID)
+ {
+ BattleGround* bg = GetPlayer()->GetBattleGround();
+ if(!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j)
+ notfit = true;
+
+ break;
+ }
+ }
+ if(notfit)
+ continue;
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
+ {
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+
+ Map const* map = GetPlayer()->GetMap();
+ if(!map->IsDungeon())
+ continue;
+
+ // search case
+ bool found = false;
+ for(int j = 0; achievIdForDangeon[j][0]; ++j)
+ {
+ if(achievIdForDangeon[j][0] == achievement->ID)
+ {
+ if(map->IsRaid())
+ {
+ // if raid accepted (ignore difficulty)
+ if(!achievIdForDangeon[j][2])
+ break; // for
+ }
+ else if(GetPlayer()->GetDifficulty()==DIFFICULTY_NORMAL)
+ {
+ // dungeon in normal mode accepted
+ if(!achievIdForDangeon[j][1])
+ break; // for
+ }
+ else
+ {
+ // dungeon in heroic mode accepted
+ if(!achievIdForDangeon[j][3])
+ break; // for
+ }
+
+ found = true;
+ break; // for
+ }
+ }
+ if(!found)
+ continue;
+
+ //FIXME: work only for instances where max==min for players
+ if(((InstanceMap*)map)->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ if(miscvalue1 != achievementCriteria->killed_by_creature.creatureEntry)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+
+ // if team check required: must kill by opposition faction
+ if(achievement->ID==318 && miscvalue2==GetPlayer()->GetTeam())
+ continue;
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
+ {
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ if(achievement->ID == 1260)
+ {
+ if(Player::GetDrunkenstateByValue(GetPlayer()->GetDrunkValue()) != DRUNKEN_SMASHED)
+ continue;
+ if(!IsHolidayActive(HOLIDAY_BREWFEST))
+ continue;
+ }
+ // miscvalue1 is the ingame fallheight*100 as stored in dbc
+ SetCriteriaProgress(achievementCriteria, miscvalue1);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ if(miscvalue2 != achievementCriteria->death_from.type)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
+ // if miscvalues != 0, it contains the questID.
+ if (miscvalue1)
+ {
+ if (miscvalue1 == achievementCriteria->complete_quest.questID)
+ SetCriteriaProgress(achievementCriteria, 1);
+ }
+ else
+ {
+ // login case.
+ if(GetPlayer()->GetQuestRewardStatus(achievementCriteria->complete_quest.questID))
+ SetCriteriaProgress(achievementCriteria, 1);
+ }
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
+ if (!miscvalue1 || miscvalue1 != achievementCriteria->be_spell_target.spellID)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
+ if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
+ if(miscvalue1 && miscvalue1!=achievementCriteria->learn_spell.spellID)
+ continue;
+
+ if(GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID))
+ SetCriteriaProgress(achievementCriteria, 1);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
+ {
+ // miscvalue1=loot_type (note: 0 = LOOT_CORSPE and then it ignored)
+ // miscvalue2=count of item loot
+ if (!miscvalue1 || !miscvalue2)
+ continue;
+ if (miscvalue1 != achievementCriteria->loot_type.lootType)
+ continue;
+
+ // zone specific
+ if(achievementCriteria->loot_type.lootTypeCount==1)
+ {
+ // those requirements couldn't be found in the dbc
+ AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria);
+ if(!data)
+ continue;
+
+ if(!data->Meets(GetPlayer(),unit))
+ continue;
+ }
+
+ SetCriteriaProgress(achievementCriteria, miscvalue2, PROGRESS_ACCUMULATE);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
+ // speedup for non-login case
+ if(miscvalue1 && achievementCriteria->own_item.itemID != miscvalue1)
+ continue;
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->GetItemCount(achievementCriteria->own_item.itemID, true));
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+ if(achievementCriteria->use_item.itemID != miscvalue1)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
+ // You _have_ to loot that item, just owning it when logging in does _not_ count!
+ if(!miscvalue1)
+ continue;
+ if(miscvalue1 != achievementCriteria->own_item.itemID)
+ continue;
+ SetCriteriaProgress(achievementCriteria, miscvalue2, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
+ {
+ WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference);
+ if(!worldOverlayEntry)
+ break;
+
+ bool matchFound = false;
+ for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)
+ {
+ uint32 area_id = worldOverlayEntry->areatableID[j];
+ if(!area_id) // array have 0 only in empty tail
+ break;
+
+ int32 exploreFlag = GetAreaFlagByAreaID(area_id);
+ if(exploreFlag < 0)
+ continue;
+
+ uint32 playerIndexOffset = uint32(exploreFlag) / 32;
+ uint32 mask = 1<< (uint32(exploreFlag) % 32);
+
+ if(GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
+ {
+ matchFound = true;
+ break;
+ }
+ }
+
+ if(matchFound)
+ SetCriteriaProgress(achievementCriteria, 1);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->GetBankBagSlotCount());
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
+ {
+ // skip faction check only at loading
+ if (miscvalue1 && miscvalue1 != achievementCriteria->gain_reputation.factionID)
+ continue;
+
+ int32 reputation = GetPlayer()->GetReputationMgr().GetReputation(achievementCriteria->gain_reputation.factionID);
+ if (reputation > 0)
+ SetCriteriaProgress(achievementCriteria, reputation);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
+ {
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetExaltedFactionCount());
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
+ {
+ // skip for login case
+ if(!miscvalue1)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
+ {
+ // miscvalue1 = itemid
+ // miscvalue2 = diced value
+ if(!miscvalue1)
+ continue;
+ if(miscvalue2 != achievementCriteria->roll_greed_on_loot.rollValue)
+ continue;
+ ItemPrototype const *pProto = objmgr.GetItemPrototype( miscvalue1 );
+
+ uint32 requiredItemLevel = 0;
+ if (achievementCriteria->ID == 2412 || achievementCriteria->ID == 2358)
+ requiredItemLevel = 185;
+
+ if(!pProto || pProto->ItemLevel <requiredItemLevel)
+ continue;
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
+ {
+ // miscvalue1 = emote
+ if(!miscvalue1)
+ continue;
+ if(miscvalue1 != achievementCriteria->do_emote.emoteID)
+ continue;
+ if(achievementCriteria->do_emote.count)
+ {
+ // those requirements couldn't be found in the dbc
+ AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria);
+ if(!data)
+ continue;
+
+ if(!data->Meets(GetPlayer(),unit))
+ continue;
+ }
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
+ case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
+ {
+ if (!miscvalue1)
+ continue;
+
+ if (achievementCriteria->healing_done.flag == ACHIEVEMENT_CRITERIA_CONDITION_MAP)
+ {
+ if(GetPlayer()->GetMapId() != achievementCriteria->healing_done.mapid)
+ continue;
+
+ // map specific case (BG in fact) expected player targeted damage/heal
+ if(!unit || unit->GetTypeId()!=TYPEID_PLAYER)
+ continue;
+ }
+
+ SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_ACCUMULATE);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
+ // miscvalue1 = item_id
+ if(!miscvalue1)
+ continue;
+ if(miscvalue1 != achievementCriteria->equip_item.itemID)
+ continue;
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
+ // miscvalue1 = go entry
+ if(!miscvalue1)
+ continue;
+ if(miscvalue1 != achievementCriteria->use_gameobject.goEntry)
+ continue;
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
+ if (!miscvalue1)
+ continue;
+ if (miscvalue1 != achievementCriteria->fish_in_gameobject.goEntry)
+ continue;
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
+ {
+ if(miscvalue1 && miscvalue1 != achievementCriteria->learn_skillline_spell.skillLine)
+ continue;
+
+ uint32 spellCount = 0;
+ for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
+ spellIter != GetPlayer()->GetSpellMap().end();
+ ++spellIter)
+ {
+ for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
+ skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
+ ++skillIter)
+ {
+ if(skillIter->second->skillId == achievementCriteria->learn_skillline_spell.skillLine)
+ spellCount++;
+ }
+ }
+ SetCriteriaProgress(achievementCriteria, spellCount);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION:
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetReveredFactionCount());
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION:
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetHonoredFactionCount());
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS:
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetVisibleFactionCount());
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
+ {
+ if (!miscvalue1)
+ continue;
+
+ if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID)
+ continue;
+
+ // those requirements couldn't be found in the dbc
+ AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria);
+ if(!data)
+ continue;
+
+ if(!data->Meets(GetPlayer(),unit))
+ continue;
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
+ {
+ if(miscvalue1 && miscvalue1 != achievementCriteria->learn_skill_line.skillLine)
+ continue;
+
+ uint32 spellCount = 0;
+ for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
+ spellIter != GetPlayer()->GetSpellMap().end();
+ ++spellIter)
+ {
+ for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
+ skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
+ ++skillIter)
+ {
+ if(skillIter->second->skillId == achievementCriteria->learn_skill_line.skillLine)
+ spellCount++;
+ }
+ }
+ SetCriteriaProgress(achievementCriteria, spellCount);
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS));
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
+ if (!miscvalue1 || miscvalue1 != achievementCriteria->hk_class.classID)
+ continue;
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
+ if (!miscvalue1 || miscvalue1 != achievementCriteria->hk_race.raceID)
+ continue;
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED:
+ SetCriteriaProgress(achievementCriteria, GetPlayer()->GetMoney(), PROGRESS_HIGHEST);
+ break;
+ // std case: not exist in DBC, not triggered in code as result
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING:
+ break;
+ // FIXME: not triggered in code as result, need to implement
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
+ case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
+ case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
+ case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
+ case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING:
+ case ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING:
+ case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
+ case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS:
+ case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
+ case ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE:
+ case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:
+ case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION:
+ case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
+ case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
+ break; // Not implemented yet :(
+ }
+ if(IsCompletedCriteria(achievementCriteria,achievement))
+ CompletedCriteriaFor(achievement);
+
+ // check again the completeness for SUMM and REQ COUNT achievements,
+ // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria
+ if (achievement->flags & ACHIEVEMENT_FLAG_SUMM)
+ {
+ if (IsCompletedAchievement(achievement))
+ CompletedAchievement(achievement);
+ }
+
+ if(AchievementEntryList const* achRefList = achievementmgr.GetAchievementByReferencedId(achievement->ID))
+ {
+ for(AchievementEntryList::const_iterator itr = achRefList->begin(); itr != achRefList->end(); ++itr)
+ if(IsCompletedAchievement(*itr))
+ CompletedAchievement(*itr);
+ }
+ }
+}
+
+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
+ if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER)
+ return false;
+
+ if(achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
+ {
+ // someone on this realm has already completed that achievement
+ if(achievementmgr.IsRealmCompleted(achievement))
+ return false;
+ }
+
+ CriteriaProgressMap::const_iterator itr = m_criteriaProgress.find(achievementCriteria->ID);
+ if(itr == m_criteriaProgress.end())
+ return false;
+
+ CriteriaProgress const* progress = &itr->second;
+
+ switch(achievementCriteria->requiredType)
+ {
+ 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:
+ return progress->counter >= 1;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
+ return progress->counter >= achievementCriteria->complete_quest_count.totalQuestCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
+ return progress->counter >= achievementCriteria->complete_quests_in_zone.questCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
+ case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
+ return progress->counter >= achievementCriteria->healing_done.count;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
+ return progress->counter >= achievementCriteria->complete_daily_quest.questCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
+ return progress->counter >= achievementCriteria->fall_without_dying.fallHeight;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
+ return progress->counter >= 1;
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
+ return progress->counter >= achievementCriteria->be_spell_target.spellCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
+ return progress->counter >= achievementCriteria->cast_spell.castCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
+ return progress->counter >= 1;
+ case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
+ return progress->counter >= achievementCriteria->own_item.itemCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
+ return progress->counter >= (achievementCriteria->learn_skill_level.skillLevel * 75);
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
+ return progress->counter >= achievementCriteria->use_item.itemCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
+ return progress->counter >= achievementCriteria->loot_item.itemCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
+ return progress->counter >= 1;
+ case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
+ return progress->counter >= achievementCriteria->buy_bank_slot.numberOfSlots;
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
+ return progress->counter >= achievementCriteria->gain_reputation.reputationAmount;
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
+ return progress->counter >= achievementCriteria->gain_exalted_reputation.numberOfExaltedFactions;
+ case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
+ return progress->counter >= achievementCriteria->visit_barber.numberOfVisits;
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
+ return progress->counter >= achievementCriteria->roll_greed_on_loot.count;
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
+ return progress->counter >= achievementCriteria->hk_class.count;
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
+ return progress->counter >= achievementCriteria->hk_race.count;
+ case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
+ return progress->counter >= achievementCriteria->do_emote.count;
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
+ return progress->counter >= achievementCriteria->equip_item.count;
+ case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
+ return progress->counter >= achievementCriteria->quest_reward_money.goldInCopper;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
+ return progress->counter >= achievementCriteria->loot_money.goldInCopper;
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
+ return progress->counter >= achievementCriteria->use_gameobject.useCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
+ return progress->counter >= achievementCriteria->fish_in_gameobject.lootCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
+ return progress->counter >= achievementCriteria->learn_skillline_spell.spellCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
+ return progress->counter >= achievementCriteria->win_duel.duelCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
+ return progress->counter >= achievementCriteria->loot_type.lootTypeCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
+ return progress->counter >= achievementCriteria->learn_skill_line.spellCount;
+ case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
+ return progress->counter >= achievementCriteria->honorable_kill.killCount;
+
+ // handle all statistic-only criteria here
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
+ case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED:
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION:
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION:
+ case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR:
+ case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
+ case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
+ case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
+ return false;
+ }
+ return false;
+}
+
+void AchievementMgr::CompletedCriteriaFor(AchievementEntry const* achievement)
+{
+ // counter can never complete
+ if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER)
+ return;
+
+ // already completed and stored
+ if (m_completedAchievements.find(achievement->ID)!=m_completedAchievements.end())
+ return;
+
+ if (IsCompletedAchievement(achievement))
+ CompletedAchievement(achievement);
+}
+
+bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry)
+{
+ // counter can never complete
+ if(entry->flags & ACHIEVEMENT_FLAG_COUNTER)
+ return false;
+
+ // for achievement with referenced achievement criterias get from referenced and counter from self
+ uint32 achievmentForTestId = entry->refAchievement ? entry->refAchievement : entry->ID;
+ uint32 achievmentForTestCount = entry->count;
+
+ AchievementCriteriaEntryList const* cList = achievementmgr.GetAchievementCriteriaByAchievement(achievmentForTestId);
+ if(!cList)
+ return false;
+ uint32 count = 0;
+
+ // For SUMM achievements, we have to count the progress of each criteria of the achievement.
+ // Oddly, the target count is NOT countained in the achievement, but in each individual criteria
+ if (entry->flags & ACHIEVEMENT_FLAG_SUMM)
+ {
+ for(AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr)
+ {
+ AchievementCriteriaEntry const* criteria = *itr;
+
+ CriteriaProgressMap::const_iterator itrProgress = m_criteriaProgress.find(criteria->ID);
+ if(itrProgress == m_criteriaProgress.end())
+ continue;
+
+ CriteriaProgress const* progress = &itrProgress->second;
+ count += progress->counter;
+
+ // for counters, field4 contains the main count requirement
+ if (count >= criteria->raw.count)
+ return true;
+ }
+ return false;
+ }
+
+ // Default case - need complete all or
+ bool completed_all = true;
+ for(AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr)
+ {
+ AchievementCriteriaEntry const* criteria = *itr;
+
+ bool completed = IsCompletedCriteria(criteria,entry);
+
+ // found an uncompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL
+ if(completed)
+ ++count;
+ else
+ completed_all = false;
+
+ // completed as have req. count of completed criterias
+ if(achievmentForTestCount > 0 && achievmentForTestCount <= count)
+ return true;
+ }
+
+ // all criterias completed requirement
+ if(completed_all && achievmentForTestCount==0)
+ return true;
+
+ return false;
+}
+
+void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype)
+{
+ if((sLog.getLogFilter() & LOG_FILTER_ACHIEVEMENT_UPDATES)==0)
+ sLog.outDetail("AchievementMgr::SetCriteriaProgress(%u, %u) for (GUID:%u)", entry->ID, changeValue, m_player->GetGUIDLow());
+
+ CriteriaProgress *progress = NULL;
+
+ CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID);
+
+ if(iter == m_criteriaProgress.end())
+ {
+ // not create record for 0 counter
+ if(changeValue == 0)
+ return;
+
+ progress = &m_criteriaProgress[entry->ID];
+ progress->counter = changeValue;
+ progress->date = time(NULL);
+ }
+ else
+ {
+ progress = &iter->second;
+
+ uint32 newValue = 0;
+ switch(ptype)
+ {
+ case PROGRESS_SET:
+ newValue = changeValue;
+ break;
+ case PROGRESS_ACCUMULATE:
+ {
+ // avoid overflow
+ uint32 max_value = std::numeric_limits<uint32>::max();
+ newValue = max_value - progress->counter > changeValue ? progress->counter + changeValue : max_value;
+ break;
+ }
+ case PROGRESS_HIGHEST:
+ newValue = progress->counter < changeValue ? changeValue : progress->counter;
+ break;
+ }
+
+ // not update (not mark as changed) if counter will have same value
+ if(progress->counter == newValue)
+ return;
+
+ progress->counter = newValue;
+ }
+
+ progress->changed = true;
+
+ if(entry->timeLimit)
+ {
+ time_t now = time(NULL);
+ if(time_t(progress->date + entry->timeLimit) < now)
+ progress->counter = 1;
+
+ // also it seems illogical, the timeframe will be extended at every criteria update
+ progress->date = now;
+ }
+ SendCriteriaUpdate(entry->ID,progress);
+}
+
+void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
+{
+ sLog.outDetail("AchievementMgr::CompletedAchievement(%u)", achievement->ID);
+ if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER || m_completedAchievements.find(achievement->ID)!=m_completedAchievements.end())
+ return;
+
+ SendAchievementEarned(achievement);
+ CompletedAchievementData& ca = m_completedAchievements[achievement->ID];
+ ca.date = time(NULL);
+ ca.changed = true;
+
+ // don't insert for ACHIEVEMENT_FLAG_REALM_FIRST_KILL since otherwise only the first group member would reach that achievement
+ // TODO: where do set this instead?
+ if(!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
+ achievementmgr.SetRealmCompleted(achievement);
+
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT);
+
+ // reward items and titles if any
+ AchievementReward const* reward = achievementmgr.GetAchievementReward(achievement);
+
+ // no rewards
+ if(!reward)
+ return;
+
+ // titles
+ if(uint32 titleId = reward->titleId[GetPlayer()->GetTeam() == HORDE?0:1])
+ {
+ if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId))
+ GetPlayer()->SetTitle(titleEntry);
+ }
+
+ // mail
+ if(reward->sender)
+ {
+ Item* item = reward->itemId ? Item::CreateItem(reward->itemId,1,GetPlayer ()) : NULL;
+
+ MailItemsInfo mi;
+ if(item)
+ {
+ // save new item before send
+ item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
+
+ // item
+ mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
+ }
+
+ int loc_idx = GetPlayer()->GetSession()->GetSessionDbLocaleIndex();
+
+ // subject and text
+ std::string subject = reward->subject;
+ std::string text = reward->text;
+ if ( loc_idx >= 0 )
+ {
+ if(AchievementRewardLocale const* loc = achievementmgr.GetAchievementRewardLocale(achievement))
+ {
+ if (loc->subject.size() > size_t(loc_idx) && !loc->subject[loc_idx].empty())
+ subject = loc->subject[loc_idx];
+ if (loc->text.size() > size_t(loc_idx) && !loc->text[loc_idx].empty())
+ text = loc->text[loc_idx];
+ }
+ }
+
+ uint32 itemTextId = objmgr.CreateItemText( text );
+
+ WorldSession::SendMailTo(GetPlayer(), MAIL_CREATURE, MAIL_STATIONERY_NORMAL, reward->sender, GetPlayer()->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
+ }
+}
+
+void AchievementMgr::SendAllAchievementData()
+{
+ // since we don't know the exact size of the packed GUIDs this is just an approximation
+ WorldPacket data(SMSG_ALL_ACHIEVEMENT_DATA, 4*2+m_completedAchievements.size()*4*2+m_completedAchievements.size()*7*4);
+ BuildAllDataPacket(&data);
+ GetPlayer()->GetSession()->SendPacket(&data);
+}
+
+void AchievementMgr::SendRespondInspectAchievements(Player* player)
+{
+ // since we don't know the exact size of the packed GUIDs this is just an approximation
+ WorldPacket data(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, 4+4*2+m_completedAchievements.size()*4*2+m_completedAchievements.size()*7*4);
+ data.append(GetPlayer()->GetPackGUID());
+ BuildAllDataPacket(&data);
+ player->GetSession()->SendPacket(&data);
+}
+
+/**
+ * used by both SMSG_ALL_ACHIEVEMENT_DATA and SMSG_RESPOND_INSPECT_ACHIEVEMENT
+ */
+void AchievementMgr::BuildAllDataPacket(WorldPacket *data)
+{
+ for(CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter!=m_completedAchievements.end(); ++iter)
+ {
+ *data << uint32(iter->first);
+ *data << uint32(secsToTimeBitFields(iter->second.date));
+ }
+ *data << int32(-1);
+
+ for(CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter)
+ {
+ *data << uint32(iter->first);
+ data->appendPackGUID(iter->second.counter);
+ data->append(GetPlayer()->GetPackGUID());
+ *data << uint32(0);
+ *data << uint32(secsToTimeBitFields(iter->second.date));
+ *data << uint32(0);
+ *data << uint32(0);
+ }
+
+ *data << int32(-1);
+}
+
+//==========================================================
+AchievementCriteriaEntryList const& AchievementGlobalMgr::GetAchievementCriteriaByType(AchievementCriteriaTypes type)
+{
+ return m_AchievementCriteriasByType[type];
+}
+
+void AchievementGlobalMgr::LoadAchievementCriteriaList()
+{
+ if(sAchievementCriteriaStore.GetNumRows()==0)
+ {
+ barGoLink bar(1);
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 achievement criteria.");
+ return;
+ }
+
+ barGoLink bar( sAchievementCriteriaStore.GetNumRows() );
+ for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId)
+ {
+ bar.step();
+
+ AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId);
+ if(!criteria)
+ continue;
+
+ m_AchievementCriteriasByType[criteria->requiredType].push_back(criteria);
+ m_AchievementCriteriaListByAchievement[criteria->referredAchievement].push_back(criteria);
+ }
+
+ sLog.outString();
+ sLog.outString(">> Loaded %lu achievement criteria.",(unsigned long)m_AchievementCriteriasByType->size());
+}
+
+void AchievementGlobalMgr::LoadAchievementReferenceList()
+{
+ if(sAchievementStore.GetNumRows()==0)
+ {
+ barGoLink bar(1);
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 achievement references.");
+ return;
+ }
+
+ uint32 count = 0;
+ barGoLink bar( sAchievementStore.GetNumRows() );
+ for (uint32 entryId = 0; entryId < sAchievementStore.GetNumRows(); ++entryId)
+ {
+ bar.step();
+
+ AchievementEntry const* achievement = sAchievementStore.LookupEntry(entryId);
+ if(!achievement || !achievement->refAchievement)
+ continue;
+
+ m_AchievementListByReferencedId[achievement->refAchievement].push_back(achievement);
+ ++count;
+ }
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u achievement references.",count);
+}
+
+void AchievementGlobalMgr::LoadAchievementCriteriaData()
+{
+ m_criteriaDataMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2 FROM achievement_criteria_data");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+ bar.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded 0 additional achievement criteria data. DB table `achievement_criteria_data` is empty.");
+ return;
+ }
+
+ uint32 count = 0;
+ barGoLink bar(result->GetRowCount());
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+ uint32 criteria_id = fields[0].GetUInt32();
+
+ AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(criteria_id);
+
+ if (!criteria)
+ {
+ sLog.outErrorDb( "Table `achievement_criteria_data` have data for not existed criteria (Entry: %u), ignore.", criteria_id);
+ continue;
+ }
+
+ AchievementCriteriaData data(fields[1].GetUInt32(),fields[2].GetUInt32(),fields[3].GetUInt32());
+
+ if(!data.IsValid(criteria))
+ continue;
+
+ // this will allocate empty data set storage
+ AchievementCriteriaDataSet& dataSet = m_criteriaDataMap[criteria_id];
+
+ // add real data only for not NONE data types
+ if(data.dataType!=ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE)
+ dataSet.Add(data);
+
+ // counting data by and data types
+ ++count;
+ } while(result->NextRow());
+
+ delete result;
+
+ // post loading checks
+ for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId)
+ {
+ AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId);
+ if(!criteria)
+ continue;
+
+ switch(criteria->requiredType)
+ {
+ case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: // need skip generic cases
+ if(criteria->do_emote.count==0)
+ continue;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: // any cases
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: // need skip generic cases
+ if(criteria->loot_type.lootTypeCount!=1)
+ continue;
+ break;
+ default: // type not use DB data, ignore
+ continue;
+ }
+
+ if(!GetCriteriaDataSet(criteria))
+ sLog.outErrorDb( "Table `achievement_criteria_data` not have expected data for for criteria (Entry: %u Type: %u).", criteria->ID, criteria->requiredType);
+ }
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u additional achievement criteria data.",count);
+}
+
+void AchievementGlobalMgr::LoadCompletedAchievements()
+{
+ QueryResult *result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+ bar.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded 0 realm completed achievements . DB table `character_achievement` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+
+ uint32 achievement_id = fields[0].GetUInt32();
+ if(!sAchievementStore.LookupEntry(achievement_id))
+ {
+ // we will remove not existed achievement for all characters
+ sLog.outError("Not existed achievement %u data removed from table `character_achievement`.",achievement_id);
+ CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE achievement = %u",achievement_id);
+ continue;
+ }
+
+ m_allCompletedAchievements.insert(achievement_id);
+ } while(result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %lu realm completed achievements.",(unsigned long)m_allCompletedAchievements.size());
+}
+
+void AchievementGlobalMgr::LoadRewards()
+{
+ m_achievementRewards.clear(); // need for reload case
+
+ // 0 1 2 3 4 5 6
+ QueryResult *result = WorldDatabase.Query("SELECT entry, title_A, title_H, item, sender, subject, text FROM achievement_reward");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 achievement rewards. DB table `achievement_reward` is empty.");
+ return;
+ }
+
+ uint32 count = 0;
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+ uint32 entry = fields[0].GetUInt32();
+ if (!sAchievementStore.LookupEntry(entry))
+ {
+ sLog.outErrorDb( "Table `achievement_reward` has wrong achievement (Entry: %u), ignore", entry);
+ continue;
+ }
+
+ AchievementReward reward;
+ reward.titleId[0] = fields[1].GetUInt32();
+ reward.titleId[1] = fields[2].GetUInt32();
+ reward.itemId = fields[3].GetUInt32();
+ reward.sender = fields[4].GetUInt32();
+ reward.subject = fields[5].GetCppString();
+ reward.text = fields[6].GetCppString();
+
+ if ((reward.titleId[0]==0)!=(reward.titleId[1]==0))
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has title (A: %u H: %u) only for one from teams.", entry, reward.titleId[0], reward.titleId[1]);
+
+ // must be title or mail at least
+ if (!reward.titleId[0] && !reward.titleId[1] && !reward.sender)
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) not have title or item reward data, ignore.", entry);
+ continue;
+ }
+
+ if (reward.titleId[0])
+ {
+ CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.titleId[0]);
+ if (!titleEntry)
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has invalid title id (%u) in `title_A`, set to 0", entry, reward.titleId[0]);
+ reward.titleId[0] = 0;
+ }
+ }
+
+ if (reward.titleId[1])
+ {
+ CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.titleId[1]);
+ if (!titleEntry)
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has invalid title id (%u) in `title_A`, set to 0", entry, reward.titleId[1]);
+ reward.titleId[1] = 0;
+ }
+ }
+
+ //check mail data before item for report including wrong item case
+ if (reward.sender)
+ {
+ if (!objmgr.GetCreatureTemplate(reward.sender))
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has invalid creature entry %u as sender, mail reward skipped.", entry, reward.sender);
+ reward.sender = 0;
+ }
+ }
+ else
+ {
+ if (reward.itemId)
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) not have sender data but have item reward, item will not rewarded", entry);
+
+ if (!reward.subject.empty())
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) not have sender data but have mail subject.", entry);
+
+ if (!reward.text.empty())
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) not have sender data but have mail text.", entry);
+ }
+
+ if (reward.itemId)
+ {
+ if (!objmgr.GetItemPrototype(reward.itemId))
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has invalid item id %u, reward mail will be without item.", entry, reward.itemId);
+ reward.itemId = 0;
+ }
+ }
+
+ m_achievementRewards[entry] = reward;
+ ++count;
+
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u achievement rewards", count );
+}
+
+void AchievementGlobalMgr::LoadRewardLocales()
+{
+ m_achievementRewardLocales.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,subject_loc1,text_loc1,subject_loc2,text_loc2,subject_loc3,text_loc3,subject_loc4,text_loc4,subject_loc5,text_loc5,subject_loc6,text_loc6,subject_loc7,text_loc7,subject_loc8,text_loc8 FROM locales_achievement_reward");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded 0 achievement reward locale strings. DB table `locales_achievement_reward` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ if(m_achievementRewards.find(entry)==m_achievementRewards.end())
+ {
+ sLog.outErrorDb( "Table `locales_achievement_reward` (Entry: %u) has locale strings for not existed achievement reward .", entry);
+ continue;
+ }
+
+ AchievementRewardLocale& data = m_achievementRewardLocales[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[1+2*(i-1)].GetCppString();
+ if(!str.empty())
+ {
+ int idx = objmgr.GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.subject.size() <= size_t(idx))
+ data.subject.resize(idx+1);
+
+ data.subject[idx] = str;
+ }
+ }
+ str = fields[1+2*(i-1)+1].GetCppString();
+ if(!str.empty())
+ {
+ int idx = objmgr.GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.text.size() <= size_t(idx))
+ data.text.resize(idx+1);
+
+ data.text[idx] = str;
+ }
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %lu achievement reward locale strings", (unsigned long)m_achievementRewardLocales.size() );
+}
diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h
new file mode 100644
index 00000000000..ecda3dcdc4d
--- /dev/null
+++ b/src/game/AchievementMgr.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __MANGOS_ACHIEVEMENTMGR_H
+#define __MANGOS_ACHIEVEMENTMGR_H
+
+#include "Common.h"
+#include "Policies/Singleton.h"
+#include "Database/DatabaseEnv.h"
+#include "DBCEnums.h"
+#include "DBCStores.h"
+
+#include <map>
+#include <string>
+
+typedef std::list<AchievementCriteriaEntry const*> AchievementCriteriaEntryList;
+typedef std::list<AchievementEntry const*> AchievementEntryList;
+
+typedef std::map<uint32,AchievementCriteriaEntryList> AchievementCriteriaListByAchievement;
+typedef std::map<uint32,AchievementEntryList> AchievementListByReferencedId;
+
+struct CriteriaProgress
+{
+ uint32 counter;
+ time_t date;
+ bool changed;
+};
+
+enum AchievementCriteriaDataType
+{ // value1 value2 comment
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1, // creature_id 0
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2, // class_id race_id
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH= 3, // health_percent 0
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD = 4, // own_team 0 not corpse (not released body), own_team==false if enemy team expected
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5, // spell_id effect_idx
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6, // area id 0
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx
+};
+
+#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 8 // maximum value in AchievementCriteriaDataType enum
+
+class Player;
+class Unit;
+
+struct AchievementCriteriaData
+{
+ AchievementCriteriaDataType dataType;
+ union
+ {
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE
+ struct
+ {
+ uint32 id;
+ } creature;
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE
+ struct
+ {
+ uint32 class_id;
+ uint32 race_id;
+ } classRace;
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH
+ struct
+ {
+ uint32 percent;
+ } health;
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD
+ struct
+ {
+ uint32 own_team_flag;
+ } player_dead;
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA
+ struct
+ {
+ uint32 spell_id;
+ uint32 effect_idx;
+ } aura;
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA
+ struct
+ {
+ uint32 id;
+ } area;
+ // ...
+ struct
+ {
+ uint32 value1;
+ uint32 value2;
+ } raw;
+ };
+
+ AchievementCriteriaData() : dataType(ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE)
+ {
+ raw.value1 = 0;
+ raw.value2 = 0;
+ }
+
+ AchievementCriteriaData(uint32 _dataType, uint32 _value1, uint32 _value2) : dataType(AchievementCriteriaDataType(_dataType))
+ {
+ raw.value1 = _value1;
+ raw.value2 = _value2;
+ }
+
+ bool IsValid(AchievementCriteriaEntry const* criteria);
+ bool Meets(Player const* source, Unit const* target) const;
+};
+
+struct AchievementCriteriaDataSet
+{
+ typedef std::vector<AchievementCriteriaData> Storage;
+ void Add(AchievementCriteriaData const& data) { storage.push_back(data); }
+ bool Meets(Player const* source, Unit const* target) const;
+ private:
+ Storage storage;
+};
+
+
+typedef std::map<uint32,AchievementCriteriaDataSet> AchievementCriteriaDataMap;
+
+struct AchievementReward
+{
+ uint32 titleId[2];
+ uint32 itemId;
+ uint32 sender;
+ std::string subject;
+ std::string text;
+};
+
+typedef std::map<uint32,AchievementReward> AchievementRewards;
+
+struct AchievementRewardLocale
+{
+ std::vector<std::string> subject;
+ std::vector<std::string> text;
+};
+
+typedef std::map<uint32,AchievementRewardLocale> AchievementRewardLocales;
+
+
+struct CompletedAchievementData
+{
+ time_t date;
+ bool changed;
+};
+
+typedef UNORDERED_MAP<uint32, CriteriaProgress> CriteriaProgressMap;
+typedef UNORDERED_MAP<uint32, CompletedAchievementData> CompletedAchievementMap;
+
+class Unit;
+class Player;
+class WorldPacket;
+
+class AchievementMgr
+{
+ public:
+ AchievementMgr(Player* pl);
+ ~AchievementMgr();
+
+ void Reset();
+ static void DeleteFromDB(uint32 lowguid);
+ void LoadFromDB(QueryResult *achievementResult, QueryResult *criteriaResult);
+ void SaveToDB();
+ void ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0);
+ void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0);
+ void CheckAllAchievementCriteria();
+ void SendAllAchievementData();
+ void SendRespondInspectAchievements(Player* player);
+ Player* GetPlayer() { return m_player;}
+
+ private:
+ enum ProgressType { PROGRESS_SET, PROGRESS_ACCUMULATE, PROGRESS_HIGHEST };
+ void SendAchievementEarned(AchievementEntry const* achievement);
+ void SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress);
+ void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype = PROGRESS_SET);
+ void CompletedCriteriaFor(AchievementEntry const* achievement);
+ void CompletedAchievement(AchievementEntry const* entry);
+ bool IsCompletedCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement);
+ bool IsCompletedAchievement(AchievementEntry const* entry);
+ void CompleteAchievementsWithRefs(AchievementEntry const* entry);
+ void BuildAllDataPacket(WorldPacket *data);
+
+ Player* m_player;
+ CriteriaProgressMap m_criteriaProgress;
+ CompletedAchievementMap m_completedAchievements;
+};
+
+class AchievementGlobalMgr
+{
+ public:
+ AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type);
+ AchievementCriteriaEntryList const* GetAchievementCriteriaByAchievement(uint32 id)
+ {
+ AchievementCriteriaListByAchievement::const_iterator itr = m_AchievementCriteriaListByAchievement.find(id);
+ return itr != m_AchievementCriteriaListByAchievement.end() ? &itr->second : NULL;
+ }
+
+ AchievementEntryList const* GetAchievementByReferencedId(uint32 id) const
+ {
+ AchievementListByReferencedId::const_iterator itr = m_AchievementListByReferencedId.find(id);
+ return itr != m_AchievementListByReferencedId.end() ? &itr->second : NULL;
+ }
+
+ AchievementReward const* GetAchievementReward(AchievementEntry const* achievement) const
+ {
+ AchievementRewards::const_iterator iter = m_achievementRewards.find(achievement->ID);
+ return iter!=m_achievementRewards.end() ? &iter->second : NULL;
+ }
+
+ AchievementRewardLocale const* GetAchievementRewardLocale(AchievementEntry const* achievement) const
+ {
+ AchievementRewardLocales::const_iterator iter = m_achievementRewardLocales.find(achievement->ID);
+ return iter!=m_achievementRewardLocales.end() ? &iter->second : NULL;
+ }
+
+ AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteriaEntry const *achievementCriteria)
+ {
+ AchievementCriteriaDataMap::const_iterator iter = m_criteriaDataMap.find(achievementCriteria->ID);
+ return iter!=m_criteriaDataMap.end() ? &iter->second : NULL;
+ }
+
+ bool IsRealmCompleted(AchievementEntry const* achievement) const
+ {
+ return m_allCompletedAchievements.find(achievement->ID) != m_allCompletedAchievements.end();
+ }
+
+ void SetRealmCompleted(AchievementEntry const* achievement)
+ {
+ m_allCompletedAchievements.insert(achievement->ID);
+ }
+
+ void LoadAchievementCriteriaList();
+ void LoadAchievementCriteriaData();
+ void LoadAchievementReferenceList();
+ void LoadCompletedAchievements();
+ void LoadRewards();
+ void LoadRewardLocales();
+ private:
+ AchievementCriteriaDataMap m_criteriaDataMap;
+
+ // store achievement criterias by type to speed up lookup
+ AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL];
+ // store achievement criterias by achievement to speed up lookup
+ AchievementCriteriaListByAchievement m_AchievementCriteriaListByAchievement;
+ // store achievements by referenced achievement id to speed up lookup
+ AchievementListByReferencedId m_AchievementListByReferencedId;
+
+ typedef std::set<uint32> AllCompletedAchievements;
+ AllCompletedAchievements m_allCompletedAchievements;
+
+ AchievementRewards m_achievementRewards;
+ AchievementRewardLocales m_achievementRewardLocales;
+};
+
+#define achievementmgr Trinity::Singleton<AchievementGlobalMgr>::Instance()
+
+#endif
diff --git a/src/game/AddonHandler.cpp b/src/game/AddonHandler.cpp
index 63582113914..4dd25c56b26 100644
--- a/src/game/AddonHandler.cpp
+++ b/src/game/AddonHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -66,63 +66,84 @@ bool AddonHandler::BuildAddonPacket(WorldPacket *Source, WorldPacket *Target)
if (Source->rpos() + 4 > Source->size())
return false;
- *Source >> TempValue; //get real size of the packed structure
+ *Source >> TempValue; // get real size of the packed structure
// empty addon packet, nothing process, can't be received from real client
if(!TempValue)
return false;
- AddonRealSize = TempValue; //temp value because ZLIB only excepts uLongf
+ AddonRealSize = TempValue; // temp value because ZLIB only excepts uLongf
- CurrentPosition = Source->rpos(); //get the position of the pointer in the structure
+ CurrentPosition = Source->rpos(); // get the position of the pointer in the structure
- AddOnPacked.resize(AddonRealSize); //resize target for zlib action
+ AddOnPacked.resize(AddonRealSize); // resize target for zlib action
if (!uncompress(const_cast<uint8*>(AddOnPacked.contents()), &AddonRealSize, const_cast<uint8*>((*Source).contents() + CurrentPosition), (*Source).size() - CurrentPosition)!= Z_OK)
{
Target->Initialize(SMSG_ADDON_INFO);
- while(AddOnPacked.rpos() < AddOnPacked.size())
+ uint32 addonsCount;
+ AddOnPacked >> addonsCount; // addons count?
+
+ for(uint32 i = 0; i < addonsCount; ++i)
{
- std::string AddonNames;
- uint8 unk6;
- uint32 crc, unk7;
+ std::string addonName;
+ uint8 enabled;
+ uint32 crc, unk2;
// check next addon data format correctness
- if(AddOnPacked.rpos()+1+4+4+1 > AddOnPacked.size())
+ if(AddOnPacked.rpos()+1 > AddOnPacked.size())
return false;
- AddOnPacked >> AddonNames;
+ AddOnPacked >> addonName;
// recheck next addon data format correctness
- if(AddOnPacked.rpos()+4+4+1 > AddOnPacked.size())
+ if(AddOnPacked.rpos()+1+4+4 > AddOnPacked.size())
return false;
- AddOnPacked >> crc >> unk7 >> unk6;
+ AddOnPacked >> enabled >> crc >> unk2;
- //sLog.outDebug("ADDON: Name:%s CRC:%x Unknown1 :%x Unknown2 :%x", AddonNames.c_str(), crc, unk7, unk6);
+ sLog.outDebug("ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk2);
- *Target << (uint8)2;
+ uint8 state = (enabled ? 2 : 1);
+ *Target << uint8(state);
- uint8 unk1 = 1;
- *Target << (uint8)unk1;
+ uint8 unk1 = (enabled ? 1 : 0);
+ *Target << uint8(unk1);
if (unk1)
{
- uint8 unk2 = crc != 0x1c776d01LL; //If addon is Standard addon CRC
- *Target << (uint8)unk2;
+ uint8 unk2 = (crc != 0x4c1c776d); // If addon is Standard addon CRC
+ *Target << uint8(unk2);
if (unk2)
Target->append(tdata, sizeof(tdata));
- *Target << (uint32)0;
+ *Target << uint32(0);
}
- uint8 unk3 = 0;
- *Target << (uint8)unk3;
+ uint8 unk3 = (enabled ? 0 : 1);
+ *Target << uint8(unk3);
if (unk3)
{
- // String, 256
+ // String, 256 (null terminated?)
+ *Target << uint8(0);
}
}
+
+ uint32 unk4;
+ AddOnPacked >> unk4;
+
+ uint32 count = 0;
+ *Target << uint32(count);
+ /*for(uint32 i = 0; i < count; ++i)
+ {
+ uint32
+ string (16 bytes)
+ string (16 bytes)
+ uint32
+ }*/
+
+ if(AddOnPacked.rpos() != AddOnPacked.size())
+ sLog.outDebug("packet under read!");
}
else
{
diff --git a/src/game/AddonHandler.h b/src/game/AddonHandler.h
index 6255bd551e2..fd9ad395924 100644
--- a/src/game/AddonHandler.h
+++ b/src/game/AddonHandler.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp
index d44cab9fd22..d827e3e2672 100644
--- a/src/game/AggressorAI.cpp
+++ b/src/game/AggressorAI.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,17 +19,9 @@
*/
#include "AggressorAI.h"
-#include "Errors.h"
-#include "Creature.h"
-#include "Player.h"
-#include "ObjectAccessor.h"
-#include "VMapFactory.h"
-#include "World.h"
+#include "SpellMgr.h"
-#include <list>
-
-int
-AggressorAI::Permissible(const Creature *creature)
+int AggressorAI::Permissible(const Creature *creature)
{
// have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight
if( !creature->isCivilian() && !creature->IsNeutralToAll() )
@@ -38,80 +30,64 @@ AggressorAI::Permissible(const Creature *creature)
return PERMIT_BASE_NO;
}
-AggressorAI::AggressorAI(Creature *c) : CreatureAI(c), i_creature(*c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
+void AggressorAI::UpdateAI(const uint32 /*diff*/)
{
+ if(!UpdateVictim())
+ return;
+
+ DoMeleeAttackIfReady();
}
-void AggressorAI::EnterEvadeMode()
+int SpellAI::Permissible(const Creature *creature)
{
- if( !i_creature.isAlive() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his dead [guid=%u]", i_creature.GetGUIDLow());
- i_victimGuid = 0;
- i_creature.CombatStop();
- i_creature.DeleteThreatList();
- return;
- }
+ return PERMIT_BASE_NO;
+}
- Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid );
+void SpellAI::InitializeAI()
+{
+ for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
+ if(me->m_spells[i] && GetSpellStore()->LookupEntry(me->m_spells[i]))
+ spells.push_back(me->m_spells[i]);
+}
- if( !victim )
- {
- DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow());
- }
- else if( !victim->isAlive() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his victim is dead [guid=%u]", i_creature.GetGUIDLow());
- }
- else if( victim->HasStealthAura() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", i_creature.GetGUIDLow());
- }
- else if( victim->isInFlight() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", i_creature.GetGUIDLow());
- }
- else
- {
- DEBUG_LOG("Creature stopped attacking due to target out run him [guid=%u]", i_creature.GetGUIDLow());
- //i_state = STATE_LOOK_AT_VICTIM;
- //i_tracker.Reset(TIME_INTERVAL_LOOK);
- }
+void SpellAI::Reset()
+{
+ events.Reset();
+}
- if(!i_creature.GetCharmerOrOwner())
- {
- i_creature.RemoveAllAuras();
+void SpellAI::JustDied(Unit *killer)
+{
+ for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
+ if(AISpellInfo[*i].condition == AICOND_DIE)
+ me->CastSpell(killer, *i, true);
+}
- // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
- if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
- i_creature.GetMotionMaster()->MoveTargetedHome();
+void SpellAI::EnterCombat(Unit *who)
+{
+ for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
+ {
+ if(AISpellInfo[*i].condition == AICOND_AGGRO)
+ me->CastSpell(who, *i, false);
+ else if(AISpellInfo[*i].condition == AICOND_COMBAT)
+ events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand()%AISpellInfo[*i].cooldown);
}
- else if (i_creature.GetOwner() && i_creature.GetOwner()->isAlive())
- i_creature.GetMotionMaster()->MoveFollow(i_creature.GetOwner(),PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
-
- i_creature.DeleteThreatList();
- i_victimGuid = 0;
- i_creature.CombatStop();
- i_creature.SetLootRecipient(NULL);
- i_creature.ResetDamageByPlayers();
}
-void
-AggressorAI::UpdateAI(const uint32 /*diff*/)
+void SpellAI::UpdateAI(const uint32 diff)
{
- // update i_victimGuid if i_creature.getVictim() !=0 and changed
if(!UpdateVictim())
return;
- i_victimGuid = i_creature.getVictim()->GetGUID();
+ events.Update(diff);
- if( i_creature.isAttackReady() )
+ if(me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ if(uint32 spellId = events.ExecuteEvent())
{
- if( i_creature.IsWithinMeleeRange(i_creature.getVictim()))
- {
- i_creature.AttackerStateUpdate(i_creature.getVictim());
- i_creature.resetAttackTimer();
- }
+ DoCast(spellId);
+ events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown);
}
+ else
+ DoMeleeAttackIfReady();
}
-
diff --git a/src/game/AggressorAI.h b/src/game/AggressorAI.h
index 97dccbcd329..2c43ccf82b7 100644
--- a/src/game/AggressorAI.h
+++ b/src/game/AggressorAI.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,32 +22,35 @@
#define TRINITY_AGGRESSORAI_H
#include "CreatureAI.h"
-#include "Timer.h"
+#include "CreatureAIImpl.h"
class Creature;
class TRINITY_DLL_DECL AggressorAI : public CreatureAI
{
- enum AggressorState
- {
- STATE_NORMAL = 1,
- STATE_LOOK_AT_VICTIM = 2
- };
-
public:
-
- AggressorAI(Creature *c);
-
- void EnterEvadeMode();
+ explicit AggressorAI(Creature *c) : CreatureAI(c) {}
void UpdateAI(const uint32);
static int Permissible(const Creature *);
+};
+
+typedef std::vector<uint32> SpellVct;
+class TRINITY_DLL_SPEC SpellAI : public CreatureAI
+{
+ public:
+ explicit SpellAI(Creature *c) : CreatureAI(c) {}
+
+ void InitializeAI();
+ void Reset();
+ void EnterCombat(Unit* who);
+ void JustDied(Unit *killer);
+ void UpdateAI(const uint32 diff);
+ static int Permissible(const Creature *);
private:
- Creature &i_creature;
- uint64 i_victimGuid;
- AggressorState i_state;
- TimeTracker i_tracker;
+ EventMap events;
+ SpellVct spells;
};
-#endif
+#endif
diff --git a/src/game/AnimalRandomMovementGenerator.h b/src/game/AnimalRandomMovementGenerator.h
index c24162d2708..9c64edcaa44 100644
--- a/src/game/AnimalRandomMovementGenerator.h
+++ b/src/game/AnimalRandomMovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/ArenaTeam.cpp b/src/game/ArenaTeam.cpp
index 747ad811b85..c00a103b1ca 100644
--- a/src/game/ArenaTeam.cpp
+++ b/src/game/ArenaTeam.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -304,8 +304,11 @@ void ArenaTeam::Roster(WorldSession *session)
{
Player *pl = NULL;
+ uint8 unk308 = 0;
+
WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100);
data << uint32(GetId()); // arena team id
+ data << uint8(unk308); // 308 unknown value but affect packet structure
data << uint32(GetMembersSize()); // members count
data << uint32(GetType()); // arena team type?
@@ -313,18 +316,24 @@ void ArenaTeam::Roster(WorldSession *session)
{
pl = objmgr.GetPlayer(itr->guid);
- data << uint64(itr->guid); // guid
- data << uint8((pl ? 1 : 0)); // online flag
- data << itr->name; // member name
+ data << uint64(itr->guid); // guid
+ data << uint8((pl ? 1 : 0)); // online flag
+ data << itr->name; // member name
data << uint32((itr->guid == GetCaptain() ? 0 : 1));// captain flag 0 captain 1 member
- data << uint8((pl ? pl->getLevel() : 0)); // unknown, level?
- data << uint8(itr->Class); // class
- data << uint32(itr->games_week); // played this week
- data << uint32(itr->wins_week); // wins this week
- data << uint32(itr->games_season); // played this season
- data << uint32(itr->wins_season); // wins this season
- data << uint32(itr->personal_rating); // personal rating
+ data << uint8((pl ? pl->getLevel() : 0)); // unknown, level?
+ data << uint8(itr->Class); // class
+ data << uint32(itr->games_week); // played this week
+ data << uint32(itr->wins_week); // wins this week
+ data << uint32(itr->games_season); // played this season
+ data << uint32(itr->wins_season); // wins this season
+ data << uint32(itr->personal_rating); // personal rating
+ if(unk308)
+ {
+ data << float(0.0); // 308 unk
+ data << float(0.0); // 308 unk
+ }
}
+
session->SendPacket(&data);
sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_ROSTER");
}
@@ -508,7 +517,7 @@ int32 ArenaTeam::WonAgainst(uint32 againstRating)
stats.wins_season += 1;
//update team's rank
stats.rank = 1;
- ObjectMgr::ArenaTeamMap::iterator i = objmgr.GetArenaTeamMapBegin();
+ ObjectMgr::ArenaTeamMap::const_iterator i = objmgr.GetArenaTeamMapBegin();
for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i)
{
if (i->second->GetType() == this->Type && i->second->GetStats().rating > stats.rating)
@@ -533,7 +542,7 @@ int32 ArenaTeam::LostAgainst(uint32 againstRating)
//update team's rank
stats.rank = 1;
- ObjectMgr::ArenaTeamMap::iterator i = objmgr.GetArenaTeamMapBegin();
+ ObjectMgr::ArenaTeamMap::const_iterator i = objmgr.GetArenaTeamMapBegin();
for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i)
{
if (i->second->GetType() == this->Type && i->second->GetStats().rating > stats.rating)
@@ -566,6 +575,28 @@ void ArenaTeam::MemberLost(Player * plr, uint32 againstRating)
}
}
+void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstRating)
+{
+ // called for offline player after ending rated arena match!
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ if(itr->guid == guid)
+ {
+ // update personal rating
+ float chance = GetChanceAgainst(itr->personal_rating, againstRating);
+ int32 mod = (int32)ceil(32.0f * (0.0f - chance));
+ if (int32(itr->personal_rating) + mod < 0)
+ itr->personal_rating = 0;
+ else
+ itr->personal_rating += mod;
+ // update personal played stats
+ itr->games_week +=1;
+ itr->games_season +=1;
+ return;
+ }
+ }
+}
+
void ArenaTeam::MemberWon(Player * plr, uint32 againstRating)
{
// called for each participant after winning a match
@@ -599,7 +630,7 @@ void ArenaTeam::UpdateArenaPointsHelper(std::map<uint32, uint32>& PlayerPoints)
return;
// to get points, a player has to participate in at least 30% of the matches
uint32 min_plays = (uint32) ceil(stats.games_week * 0.3);
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
// the player participated in enough games, update his points
uint32 points_to_add = 0;
@@ -623,11 +654,13 @@ void ArenaTeam::SaveToDB()
{
// save team and member stats to db
// called after a match has ended, or when calculating arena_points
+ CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games_week, stats.games_season, stats.rank, stats.wins_week, stats.wins_season, GetId());
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
- CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', personal_rating = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->games_week, itr->wins_week, itr->games_season, itr->wins_season, itr->personal_rating, Id, itr->guid);
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', personal_rating = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->games_week, itr->wins_week, itr->games_season, itr->wins_season, itr->personal_rating, Id, GUID_LOPART(itr->guid));
}
+ CharacterDatabase.CommitTransaction();
}
void ArenaTeam::FinishWeek()
@@ -641,6 +674,19 @@ void ArenaTeam::FinishWeek()
}
}
+bool ArenaTeam::IsFighting() const
+{
+ for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ if (Player *p = objmgr.GetPlayer(itr->guid))
+ {
+ if (p->GetMap()->IsBattleArena())
+ return true;
+ }
+ }
+ return false;
+}
+
/*
arenateam fields (id from 2.3.3 client):
1414 - arena team id 2v2
diff --git a/src/game/ArenaTeam.h b/src/game/ArenaTeam.h
index 9641c1e5992..60c80f972d2 100644
--- a/src/game/ArenaTeam.h
+++ b/src/game/ArenaTeam.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -98,7 +98,7 @@ struct ArenaTeamMember
void ModifyPersonalRating(Player* plr, int32 mod, uint32 slot)
{
- if (personal_rating + mod < 0)
+ if (int32(personal_rating) + mod < 0)
personal_rating = 0;
else
personal_rating += mod;
@@ -179,18 +179,7 @@ class ArenaTeam
return NULL;
}
- bool IsFighting() const
- {
- for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
- {
- if (Player *p = objmgr.GetPlayer(itr->guid))
- {
- if (p->GetMap()->IsBattleArena())
- return true;
- }
- }
- return false;
- }
+ bool IsFighting() const;
bool LoadArenaTeamFromDB(uint32 ArenaTeamId);
void LoadMembersFromDB(uint32 ArenaTeamId);
@@ -211,6 +200,7 @@ class ArenaTeam
void MemberWon(Player * plr, uint32 againstRating);
int32 LostAgainst(uint32 againstRating);
void MemberLost(Player * plr, uint32 againstRating);
+ void OfflineMemberLost(uint64 guid, uint32 againstRating);
void UpdateArenaPointsHelper(std::map<uint32, uint32> & PlayerPoints);
diff --git a/src/game/ArenaTeamHandler.cpp b/src/game/ArenaTeamHandler.cpp
index 9ba2e65ec92..f195ccc93c3 100644
--- a/src/game/ArenaTeamHandler.cpp
+++ b/src/game/ArenaTeamHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@
#include "ArenaTeam.h"
#include "World.h"
#include "SocialMgr.h"
-#include "Language.h"
void WorldSession::HandleInspectArenaStatsOpcode(WorldPacket & recv_data)
{
@@ -41,7 +40,7 @@ void WorldSession::HandleInspectArenaStatsOpcode(WorldPacket & recv_data)
if(Player *plr = objmgr.GetPlayer(guid))
{
- for (uint8 i = 0; i < MAX_ARENA_SLOT; i++)
+ for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i)
{
if(uint32 a_id = plr->GetArenaTeamId(i))
{
@@ -173,7 +172,7 @@ void WorldSession::HandleArenaTeamInviteAcceptOpcode(WorldPacket & /*recv_data*/
if(!at)
return;
- if(_player->GetArenaTeamIdFromDB(_player->GetGUIDLow(), at->GetType()))
+ if(_player->GetArenaTeamId(at->GetSlot()))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S,"","",ERR_ALREADY_IN_ARENA_TEAM); // already in arena team that size
return;
diff --git a/src/game/AuctionHouseBot.cpp b/src/game/AuctionHouseBot.cpp
index b139358b74a..27315f8e2e9 100644
--- a/src/game/AuctionHouseBot.cpp
+++ b/src/game/AuctionHouseBot.cpp
@@ -4,8 +4,8 @@
#include "Database/DatabaseEnv.h"
#include "Item.h"
#include "Log.h"
-#include "AuctionHouseMgr.h"
#include "ObjectMgr.h"
+#include "AuctionHouseMgr.h"
#include "Player.h"
#include "World.h"
#include "WorldSession.h"
@@ -15,7 +15,7 @@
using namespace std;
-static bool debug_Out = sConfig.GetIntDefault("AuctionHouseBot.DEBUG", 0);
+static bool debug_Out = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG", false);
static vector<uint32> npcItems;
static vector<uint32> lootItems;
@@ -752,7 +752,7 @@ void AuctionHouseBot()
if ((!AHBSeller) && (!AHBBuyer))
return;
- WorldSession _session(AHBplayerAccount, NULL, 0, true, 0, LOCALE_enUS);
+ WorldSession _session(AHBplayerAccount, NULL, SEC_PLAYER, true, 0, LOCALE_enUS);
Player _AHBplayer(&_session);
_AHBplayer.MinimalLoadFromDB(NULL, AHBplayerGUID);
ObjectAccessor::Instance().AddObject(&_AHBplayer);
@@ -785,13 +785,13 @@ void AuctionHouseBot()
///////////////////////////////////////////////////////////////////////////////
void AuctionHouseBotInit()
{
- AHBSeller = sConfig.GetBoolDefault("AuctionHouseBot.EnableSeller", 0);
- AHBBuyer = sConfig.GetBoolDefault("AuctionHouseBot.EnableBuyer", 0);
- No_Bind = sConfig.GetBoolDefault("AuctionHouseBot.No_Bind", 1);
- Bind_When_Picked_Up = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Picked_Up", 0);
- Bind_When_Equipped = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Equipped", 1);
- Bind_When_Use = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Use", 1);
- Bind_Quest_Item = sConfig.GetBoolDefault("AuctionHouseBot.Bind_Quest_Item", 0);
+ AHBSeller = sConfig.GetBoolDefault("AuctionHouseBot.EnableSeller", false);
+ AHBBuyer = sConfig.GetBoolDefault("AuctionHouseBot.EnableBuyer", false);
+ No_Bind = sConfig.GetBoolDefault("AuctionHouseBot.No_Bind", true);
+ Bind_When_Picked_Up = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Picked_Up", false);
+ Bind_When_Equipped = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Equipped", true);
+ Bind_When_Use = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Use", true);
+ Bind_Quest_Item = sConfig.GetBoolDefault("AuctionHouseBot.Bind_Quest_Item", false);
if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
{
@@ -802,9 +802,9 @@ void AuctionHouseBotInit()
if (AHBSeller)
{
- Vendor_Items = sConfig.GetBoolDefault("AuctionHouseBot.VendorItems", 0);
- Loot_Items = sConfig.GetBoolDefault("AuctionHouseBot.LootItems", 1);
- Other_Items = sConfig.GetBoolDefault("AuctionHouseBot.OtherItems", 0);
+ Vendor_Items = sConfig.GetBoolDefault("AuctionHouseBot.VendorItems", false);
+ Loot_Items = sConfig.GetBoolDefault("AuctionHouseBot.LootItems", true);
+ Other_Items = sConfig.GetBoolDefault("AuctionHouseBot.OtherItems", false);
QueryResult* results = (QueryResult*) NULL;
char npcQuery[] = "SELECT distinct `item` FROM `npc_vendor`";
@@ -1025,20 +1025,20 @@ void AuctionHouseBotInit()
}
sLog.outString("AuctionHouseBot:");
- sLog.outString("loaded %d grey trade goods", greyTradeGoodsBin.size());
- sLog.outString("loaded %d white trade goods", whiteTradeGoodsBin.size());
- sLog.outString("loaded %d green trade goods", greenTradeGoodsBin.size());
- sLog.outString("loaded %d blue trade goods", blueTradeGoodsBin.size());
- sLog.outString("loaded %d purple trade goods", purpleTradeGoodsBin.size());
- sLog.outString("loaded %d orange trade goods", orangeTradeGoodsBin.size());
- sLog.outString("loaded %d yellow trade goods", yellowTradeGoodsBin.size());
- sLog.outString("loaded %d grey items", greyItemsBin.size());
- sLog.outString("loaded %d white items", whiteItemsBin.size());
- sLog.outString("loaded %d green items", greenItemsBin.size());
- sLog.outString("loaded %d blue items", blueItemsBin.size());
- sLog.outString("loaded %d purple items", purpleItemsBin.size());
- sLog.outString("loaded %d orange items", orangeItemsBin.size());
- sLog.outString("loaded %d yellow items", yellowItemsBin.size());
+ sLog.outString("loaded %u grey trade goods", greyTradeGoodsBin.size());
+ sLog.outString("loaded %u white trade goods", whiteTradeGoodsBin.size());
+ sLog.outString("loaded %u green trade goods", greenTradeGoodsBin.size());
+ sLog.outString("loaded %u blue trade goods", blueTradeGoodsBin.size());
+ sLog.outString("loaded %u purple trade goods", purpleTradeGoodsBin.size());
+ sLog.outString("loaded %u orange trade goods", orangeTradeGoodsBin.size());
+ sLog.outString("loaded %u yellow trade goods", yellowTradeGoodsBin.size());
+ sLog.outString("loaded %u grey items", greyItemsBin.size());
+ sLog.outString("loaded %u white items", whiteItemsBin.size());
+ sLog.outString("loaded %u green items", greenItemsBin.size());
+ sLog.outString("loaded %u blue items", blueItemsBin.size());
+ sLog.outString("loaded %u purple items", purpleItemsBin.size());
+ sLog.outString("loaded %u orange items", orangeItemsBin.size());
+ sLog.outString("loaded %u yellow items", yellowItemsBin.size());
}
sLog.outString("AuctionHouseBot by Paradox (original by ChrisK) has been loaded.");
sLog.outString("AuctionHouseBot now includes AHBuyer by Kerbe and Paradox");
diff --git a/src/game/AuctionHouseHandler.cpp b/src/game/AuctionHouseHandler.cpp
index b36d1870b86..921db551508 100644
--- a/src/game/AuctionHouseHandler.cpp
+++ b/src/game/AuctionHouseHandler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
@@ -41,7 +41,7 @@ void WorldSession::HandleAuctionHelloOpcode( WorldPacket & recv_data )
uint64 guid; //NPC guid
recv_data >> guid;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleAuctionHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -50,7 +50,7 @@ void WorldSession::HandleAuctionHelloOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
SendAuctionHello(guid, unit);
}
@@ -168,7 +168,7 @@ void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data )
if (!item || !bid || !etime)
return; //check for cheaters
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
@@ -199,7 +199,7 @@ void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
Item *it = pl->GetItemByGuid( item );
//do not allow to sell already auctioned items
@@ -295,7 +295,7 @@ void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
if (!auctionId || !price)
return; //check for cheaters
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
@@ -304,7 +304,7 @@ void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap( pCreature->getFaction() );
@@ -367,6 +367,7 @@ void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
}
auction->bidder = pl->GetGUIDLow();
auction->bid = price;
+ GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price);
// after this update we should save player's money ...
CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id);
@@ -390,6 +391,7 @@ void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
}
auction->bidder = pl->GetGUIDLow();
auction->bid = auction->buyout;
+ GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout);
auctionmgr.SendAuctionSalePendingMail( auction );
auctionmgr.SendAuctionSuccessfulMail( auction );
@@ -419,7 +421,7 @@ void WorldSession::HandleAuctionRemoveItem( WorldPacket & recv_data )
recv_data >> auctionId;
//sLog.outDebug( "Cancel AUCTION AuctionID: %u", auctionId);
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) );
@@ -428,7 +430,7 @@ void WorldSession::HandleAuctionRemoveItem( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap( pCreature->getFaction() );
@@ -500,11 +502,11 @@ void WorldSession::HandleAuctionListBidderItems( WorldPacket & recv_data )
recv_data >> outbiddedCount;
if (recv_data.size() != (16 + outbiddedCount * 4 ))
{
- sLog.outError("Client sent bad opcode!!! with count: %u and size : %d (mustbe: %d", outbiddedCount, recv_data.size(),(16 + outbiddedCount * 4 ));
+ sLog.outError("Client sent bad opcode!!! with count: %u and size : %lu (must be: %u)", outbiddedCount, (unsigned long)recv_data.size(),(16 + outbiddedCount * 4 ));
outbiddedCount = 0;
}
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -513,7 +515,7 @@ void WorldSession::HandleAuctionListBidderItems( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap( pCreature->getFaction() );
@@ -553,7 +555,7 @@ void WorldSession::HandleAuctionListOwnerItems( WorldPacket & recv_data )
recv_data >> guid;
recv_data >> listfrom; // not used in fact (this list not have page control in client)
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleAuctionListOwnerItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -562,7 +564,7 @@ void WorldSession::HandleAuctionListOwnerItems( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap( pCreature->getFaction() );
@@ -600,7 +602,7 @@ void WorldSession::HandleAuctionListItems( WorldPacket & recv_data )
recv_data >> auctionSlotID >> auctionMainCategory >> auctionSubCategory;
recv_data >> quality >> usable;
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_AUCTIONEER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleAuctionListItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -609,7 +611,7 @@ void WorldSession::HandleAuctionListItems( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap( pCreature->getFaction() );
@@ -638,3 +640,22 @@ void WorldSession::HandleAuctionListItems( WorldPacket & recv_data )
SendPacket(&data);
}
+void WorldSession::HandleAuctionListPendingSales( WorldPacket & recv_data )
+{
+ sLog.outDebug("CMSG_AUCTION_LIST_PENDING_SALES");
+ recv_data.hexlike();
+
+ uint32 count = 0;
+
+ WorldPacket data(SMSG_AUCTION_LIST_PENDING_SALES, 4);
+ data << uint32(count); // count
+ /*for(uint32 i = 0; i < count; ++i)
+ {
+ data << ""; // string
+ data << ""; // string
+ data << uint32(0);
+ data << uint32(0);
+ data << float(0);
+ }*/
+ SendPacket(&data);
+}
diff --git a/src/game/AuctionHouseMgr.cpp b/src/game/AuctionHouseMgr.cpp
index 1554013af99..bfb24b15e7a 100644
--- a/src/game/AuctionHouseMgr.cpp
+++ b/src/game/AuctionHouseMgr.cpp
@@ -1,25 +1,25 @@
/*
-* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
#include "Common.h"
#include "Database/DatabaseEnv.h"
-#include "Database/DBCStores.h"
#include "Database/SQLStorage.h"
+#include "DBCStores.h"
#include "ProgressBar.h"
#include "AccountMgr.h"
@@ -43,7 +43,7 @@ AuctionHouseMgr::AuctionHouseMgr()
AuctionHouseMgr::~AuctionHouseMgr()
{
- for(ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
+ for(ItemMap::const_iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
delete itr->second;
}
@@ -223,6 +223,8 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail( AuctionEntry * auction )
if (owner)
{
+ //FIXME: what do if owner offline
+ owner->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD, auction->bid);
//send auction owner notification, bidder must be current!
owner->GetSession()->SendAuctionOwnerNotification( auction );
}
@@ -257,7 +259,7 @@ void AuctionHouseMgr::SendAuctionExpiredMail( AuctionEntry * auction )
if ( owner )
owner->GetSession()->SendAuctionOwnerNotification( auction );
else
- RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
+ RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
MailItemsInfo mi;
mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
@@ -283,7 +285,7 @@ void AuctionHouseMgr::LoadAuctionItems()
{
barGoLink bar(1);
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 auction items");
return;
}
@@ -298,8 +300,8 @@ void AuctionHouseMgr::LoadAuctionItems()
bar.step();
fields = result->Fetch();
- uint32 item_guid = fields[1].GetUInt32();
- uint32 item_template = fields[2].GetUInt32();
+ uint32 item_guid = fields[1].GetUInt32();
+ uint32 item_template = fields[2].GetUInt32();
ItemPrototype const *proto = objmgr.GetItemPrototype(item_template);
@@ -334,7 +336,7 @@ void AuctionHouseMgr::LoadAuctions()
{
barGoLink bar(1);
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 auctions. DB table `auctionhouse` is empty.");
return;
}
@@ -347,7 +349,7 @@ void AuctionHouseMgr::LoadAuctions()
{
barGoLink bar(1);
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 auctions. DB table `auctionhouse` is empty.");
return;
}
@@ -357,7 +359,7 @@ void AuctionHouseMgr::LoadAuctions()
{
barGoLink bar(1);
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 auctions. DB table `auctionhouse` is empty.");
return;
}
@@ -468,17 +470,17 @@ AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTem
// but no easy way convert creature faction to player race faction for specific city
switch(factionTemplateId)
{
- case 12: houseid = 1; break; // human
- case 29: houseid = 6; break; // orc, and generic for horde
- case 55: houseid = 2; break; // dwarf, and generic for alliance
- case 68: houseid = 4; break; // undead
- case 80: houseid = 3; break; // n-elf
- case 104: houseid = 5; break; // trolls
- case 120: houseid = 7; break; // booty bay, neutral
- case 474: houseid = 7; break; // gadgetzan, neutral
- case 855: houseid = 7; break; // everlook, neutral
+ case 12: houseid = 1; break; // human
+ case 29: houseid = 6; break; // orc, and generic for horde
+ case 55: houseid = 2; break; // dwarf, and generic for alliance
+ case 68: houseid = 4; break; // undead
+ case 80: houseid = 3; break; // n-elf
+ case 104: houseid = 5; break; // trolls
+ case 120: houseid = 7; break; // booty bay, neutral
+ case 474: houseid = 7; break; // gadgetzan, neutral
+ case 855: houseid = 7; break; // everlook, neutral
case 1604: houseid = 6; break; // b-elfs,
- default: // for unknown case
+ default: // for unknown case
{
FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
if(!u_entry)
@@ -576,22 +578,22 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
ItemPrototype const *proto = item->GetProto();
- if (itemClass != (0xffffffff) && proto->Class != itemClass)
+ if (itemClass != 0xffffffff && proto->Class != itemClass)
continue;
- if (itemSubClass != (0xffffffff) && proto->SubClass != itemSubClass)
+ if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass)
continue;
- if (inventoryType != (0xffffffff) && proto->InventoryType != inventoryType)
+ if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType)
continue;
- if (quality != (0xffffffff) && proto->Quality != quality)
+ if (quality != 0xffffffff && proto->Quality != quality)
continue;
- if( levelmin != (0x00) && (proto->RequiredLevel < levelmin || levelmax != (0x00) && proto->RequiredLevel > levelmax ) )
+ if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax)))
continue;
- if( usable != (0x00) && player->CanUseItem( item ) != EQUIP_ERR_OK )
+ if (usable != 0x00 && player->CanUseItem( item ) != EQUIP_ERR_OK)
continue;
std::string name = proto->Name1;
@@ -609,10 +611,10 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
}
}
- if( !wsearchedname.empty() && !Utf8FitTo(name, wsearchedname) )
+ if (!wsearchedname.empty() && !Utf8FitTo(name, wsearchedname) )
continue;
- if ((count < 50) && (totalcount >= listfrom))
+ if (count < 50 && totalcount >= listfrom)
{
++count;
Aentry->BuildAuctionInfo(data);
@@ -630,35 +632,35 @@ bool AuctionEntry::BuildAuctionInfo(WorldPacket & data) const
sLog.outError("auction to item, that doesn't exist !!!!");
return false;
}
- data << (uint32) Id;
- data << (uint32) pItem->GetEntry();
+ data << uint32(Id);
+ data << uint32(pItem->GetEntry());
- for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; i++)
+ for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i)
{
- data << (uint32) pItem->GetEnchantmentId(EnchantmentSlot(i));
- data << (uint32) pItem->GetEnchantmentDuration(EnchantmentSlot(i));
- data << (uint32) pItem->GetEnchantmentCharges(EnchantmentSlot(i));
+ data << uint32(pItem->GetEnchantmentId(EnchantmentSlot(i)));
+ data << uint32(pItem->GetEnchantmentDuration(EnchantmentSlot(i)));
+ data << uint32(pItem->GetEnchantmentCharges(EnchantmentSlot(i)));
}
- data << (uint32) pItem->GetItemRandomPropertyId(); //random item property id
- data << (uint32) pItem->GetItemSuffixFactor(); //SuffixFactor
- data << (uint32) pItem->GetCount(); //item->count
- data << (uint32) pItem->GetSpellCharges(); //item->charge FFFFFFF
- data << (uint32) 0; //Unknown
- data << (uint64) owner; //Auction->owner
- data << (uint32) startbid; //Auction->startbid (not sure if useful)
- data << (uint32) (bid ? GetAuctionOutBid() : 0);
+ data << uint32(pItem->GetItemRandomPropertyId()); //random item property id
+ data << uint32(pItem->GetItemSuffixFactor()); //SuffixFactor
+ data << uint32(pItem->GetCount()); //item->count
+ data << uint32(pItem->GetSpellCharges()); //item->charge FFFFFFF
+ data << uint32(0); //Unknown
+ data << uint64(owner); //Auction->owner
+ data << uint32(startbid); //Auction->startbid (not sure if useful)
+ data << uint32(bid ? GetAuctionOutBid() : 0);
//minimal outbid
- data << (uint32) buyout; //auction->buyout
- data << (uint32) (expire_time - time(NULL))* 1000; //time left
- data << (uint64) bidder; //auction->bidder current
- data << (uint32) bid; //current bid
+ data << uint32(buyout); //auction->buyout
+ data << uint32((expire_time-time(NULL))*IN_MILISECONDS);//time left
+ data << uint64(bidder) ; //auction->bidder current
+ data << uint32(bid); //current bid
return true;
}
uint32 AuctionEntry::GetAuctionCut() const
{
- return uint32(auctionHouseEntry->cutPercent * bid * sWorld.getRate(RATE_AUCTION_CUT) / 100.f);
+ return uint32(auctionHouseEntry->cutPercent * bid * sWorld.getRate(RATE_AUCTION_CUT) / 100.0f);
}
/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
diff --git a/src/game/Bag.cpp b/src/game/Bag.cpp
index 331b12acde5..1edbc06474d 100644
--- a/src/game/Bag.cpp
+++ b/src/game/Bag.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,9 +23,7 @@
#include "ObjectMgr.h"
#include "Database/DatabaseEnv.h"
#include "Log.h"
-#include "WorldPacket.h"
#include "UpdateData.h"
-#include "WorldSession.h"
Bag::Bag( ): Item()
{
@@ -34,7 +32,7 @@ Bag::Bag( ): Item()
m_valuesCount = CONTAINER_END;
- memset(m_bagslot, 0, sizeof(Item *) * MAX_BAG_SIZE); // Maximum 20 Slots
+ memset(m_bagslot, 0, sizeof(Item *) * MAX_BAG_SIZE);
}
Bag::~Bag()
@@ -86,7 +84,7 @@ bool Bag::Create(uint32 guidlow, uint32 itemid, Player const* owner)
SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->ContainerSlots);
// Cleaning 20 slots
- for (uint8 i = 0; i < MAX_BAG_SIZE; i++)
+ for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
{
SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0);
m_bagslot[i] = NULL;
@@ -121,7 +119,7 @@ bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result)
void Bag::DeleteFromDB()
{
- for (int i = 0; i < MAX_BAG_SIZE; i++)
+ for (int i = 0; i < MAX_BAG_SIZE; ++i)
if (m_bagslot[i])
m_bagslot[i]->DeleteFromDB();
@@ -131,7 +129,7 @@ void Bag::DeleteFromDB()
uint32 Bag::GetFreeSlots() const
{
uint32 slots = 0;
- for (uint32 i=0; i < GetBagSize(); i++)
+ for (uint32 i=0; i < GetBagSize(); ++i)
if (!m_bagslot[i])
++slots;
diff --git a/src/game/Bag.h b/src/game/Bag.h
index d930809cf4a..1c341b5611d 100644
--- a/src/game/Bag.h
+++ b/src/game/Bag.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,10 +24,7 @@
// Maximum 36 Slots ( (CONTAINER_END - CONTAINER_FIELD_SLOT_1)/2
#define MAX_BAG_SIZE 36 // 2.0.12
-#include "Object.h"
#include "ItemPrototype.h"
-#include "Unit.h"
-#include "Creature.h"
#include "Item.h"
class Bag : public Item
diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp
index 9be5650a16e..acb3f25ae31 100644
--- a/src/game/BattleGround.cpp
+++ b/src/game/BattleGround.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,23 +21,119 @@
#include "Object.h"
#include "Player.h"
#include "BattleGround.h"
+#include "BattleGroundMgr.h"
#include "Creature.h"
#include "MapManager.h"
#include "Language.h"
-#include "Chat.h"
#include "SpellAuras.h"
#include "ArenaTeam.h"
#include "World.h"
+#include "Group.h"
+#include "ObjectMgr.h"
+#include "WorldPacket.h"
#include "Util.h"
+#include "Formulas.h"
+#include "GridNotifiersImpl.h"
+
+namespace MaNGOS
+{
+ class BattleGroundChatBuilder
+ {
+ public:
+ BattleGroundChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, va_list* args = NULL)
+ : i_msgtype(msgtype), i_textId(textId), i_source(source), i_args(args) {}
+ void operator()(WorldPacket& data, int32 loc_idx)
+ {
+ char const* text = objmgr.GetMangosString(i_textId,loc_idx);
+
+ if (i_args)
+ {
+ // we need copy va_list before use or original va_list will corrupted
+ va_list ap;
+ va_copy(ap,*i_args);
+
+ char str [2048];
+ vsnprintf(str,2048,text, ap );
+ va_end(ap);
+
+ do_helper(data,&str[0]);
+ }
+ else
+ do_helper(data,text);
+ }
+ private:
+ void do_helper(WorldPacket& data, char const* text)
+ {
+ uint64 target_guid = i_source ? i_source ->GetGUID() : 0;
+
+ data << uint8(i_msgtype);
+ data << uint32(LANG_UNIVERSAL);
+ data << uint64(target_guid); // there 0 for BG messages
+ data << uint32(0); // can be chat msg group or something
+ data << uint64(target_guid);
+ data << uint32(strlen(text)+1);
+ data << text;
+ data << uint8(i_source ? i_source->chatTag() : uint8(0));
+ }
+
+ ChatMsg i_msgtype;
+ int32 i_textId;
+ Player const* i_source;
+ va_list* i_args;
+ };
+
+ class BattleGround2ChatBuilder
+ {
+ public:
+ BattleGround2ChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, int32 arg1, int32 arg2)
+ : i_msgtype(msgtype), i_textId(textId), i_source(source), i_arg1(arg1), i_arg2(arg2) {}
+ void operator()(WorldPacket& data, int32 loc_idx)
+ {
+ char const* text = objmgr.GetMangosString(i_textId,loc_idx);
+ char const* arg1str = i_arg1 ? objmgr.GetMangosString(i_arg1,loc_idx) : "";
+ char const* arg2str = i_arg2 ? objmgr.GetMangosString(i_arg2,loc_idx) : "";
+
+ char str [2048];
+ snprintf(str,2048,text, arg1str, arg2str );
+
+ uint64 target_guid = i_source ? i_source ->GetGUID() : 0;
+
+ data << uint8(i_msgtype);
+ data << uint32(LANG_UNIVERSAL);
+ data << uint64(target_guid); // there 0 for BG messages
+ data << uint32(0); // can be chat msg group or something
+ data << uint64(target_guid);
+ data << uint32(strlen(str)+1);
+ data << str;
+ data << uint8(i_source ? i_source->chatTag() : uint8(0));
+ }
+ private:
+
+ ChatMsg i_msgtype;
+ int32 i_textId;
+ Player const* i_source;
+ int32 i_arg1;
+ int32 i_arg2;
+ };
+} // namespace MaNGOS
+
+template<class Do>
+void BattleGround::BroadcastWorker(Do& _do)
+{
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ if (Player *plr = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
+ _do(plr);
+}
BattleGround::BattleGround()
{
- m_TypeID = 0;
+ m_TypeID = BattleGroundTypeId(0);
m_InstanceID = 0;
- m_Status = 0;
+ m_Status = STATUS_NONE;
+ m_ClientInstanceID = 0;
m_EndTime = 0;
m_LastResurrectTime = 0;
- m_Queue_type = MAX_BATTLEGROUND_QUEUES;
+ m_QueueId = QUEUE_ID_MAX_LEVEL_19;
m_InvitedAlliance = 0;
m_InvitedHorde = 0;
m_ArenaType = 0;
@@ -88,6 +184,16 @@ BattleGround::BattleGround()
m_PrematureCountDown = 0;
m_HonorMode = BG_NORMAL;
+
+ m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_2M;
+ m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_1M;
+ m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_30S;
+ m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
+ //we must set to some default existing values
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN;
}
BattleGround::~BattleGround()
@@ -105,99 +211,68 @@ BattleGround::~BattleGround()
DelObject(i);
}
- // delete creature and go respawn times
- WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
- WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
- // delete instance from db
- CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
- // remove from battlegrounds
- sBattleGroundMgr.RemoveBattleGround(GetInstanceID());
+ if(GetInstanceID()) // not spam by useless queries in case BG templates
+ {
+ // delete creature and go respawn times
+ WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
+ WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
+ // delete instance from db
+ CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
+ // remove from battlegrounds
+ }
+
+ sBattleGroundMgr.RemoveBattleGround(GetInstanceID(), GetTypeID());
// unload map
- if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
- if(map->IsBattleGroundOrArena())
+ if (Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
+ if (map->IsBattleGroundOrArena())
((BattleGroundMap*)map)->SetUnload();
// remove from bg free slot queue
this->RemoveFromBGFreeSlotQueue();
}
-void BattleGround::Update(time_t diff)
+void BattleGround::Update(uint32 diff)
{
- if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
+ if (!GetPlayersSize() && !GetReviveQueueSize())
//BG is empty
return;
- m_StartTime += diff;
-
- // WorldPacket data;
-
- if(GetRemovedPlayersSize())
+ // remove offline players from bg after 5 minutes
+ if (!m_OfflineQueue.empty())
{
- for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr)
+ BattleGroundPlayerMap::iterator itr = m_Players.find(*(m_OfflineQueue.begin()));
+ if (itr != m_Players.end())
{
- Player *plr = objmgr.GetPlayer(itr->first);
- switch(itr->second)
+ if (itr->second.OfflineRemoveTime <= sWorld.GetGameTime())
{
- //following code is handled by event:
- /*case 0:
- sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first);
- //RemovePlayerFromQueue(itr->first);
- if(plr)
- {
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
- plr->GetSession()->SendPacket(&data);
- }
- break;*/
- case 1: // currently in bg and was removed from bg
- if(plr)
- RemovePlayerAtLeave(itr->first, true, true);
- else
- RemovePlayerAtLeave(itr->first, false, false);
- break;
- case 2: // revive queue
- RemovePlayerFromResurrectQueue(itr->first);
- break;
- default:
- sLog.outError("BattleGround: Unknown remove player case!");
+ RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
+ m_OfflineQueue.pop_front(); // remove from offline queue
+ //do not use itr for anything, because it is erased in RemovePlayerAtLeave()
}
}
- m_RemovedPlayers.clear();
}
- // this code isn't efficient and its idea isn't implemented yet
- /* offline players are removed from battleground in worldsession::LogoutPlayer()
- // remove offline players from bg after ~5 minutes
- if(GetPlayersSize())
- {
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
- {
- Player *plr = objmgr.GetPlayer(itr->first);
- itr->second.LastOnlineTime += diff;
-
- if(plr)
- itr->second.LastOnlineTime = 0; // update last online time
- else
- if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME) // 5 minutes
- m_RemovedPlayers[itr->first] = 1; // add to remove list (BG)
- }
- }*/
+ /*********************************************************/
+ /*** BATTLEGROUND RESSURECTION SYSTEM ***/
+ /*********************************************************/
+ //this should be handled by spell system
m_LastResurrectTime += diff;
if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
{
- if(GetReviveQueueSize())
+ if (GetReviveQueueSize())
{
for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
{
Creature *sh = NULL;
- for(std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
+ for(std::vector<uint64>::const_iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
{
Player *plr = objmgr.GetPlayer(*itr2);
- if(!plr)
+ if (!plr)
continue;
- if (!sh)
+ if (!sh && plr->IsInWorld())
{
- sh = ObjectAccessor::GetCreature(*plr, itr->first);
+ sh = plr->GetMap()->GetCreature(itr->first);
// only for visual effect
if (sh)
sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true); // Spirit Heal, effect 117
@@ -218,10 +293,10 @@ void BattleGround::Update(time_t diff)
}
else if (m_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
{
- for(std::vector<uint64>::iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
+ for(std::vector<uint64>::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(*itr);
- if(!plr)
+ if (!plr)
continue;
plr->ResurrectPlayer(1.0f);
plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true);
@@ -230,46 +305,168 @@ void BattleGround::Update(time_t diff)
m_ResurrectQueue.clear();
}
+ /*********************************************************/
+ /*** BATTLEGROUND BALLANCE SYSTEM ***/
+ /*********************************************************/
+
// if less then minimum players are in on one side, then start premature finish timer
- if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
+ if (GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
{
- if(!m_PrematureCountDown)
+ if (!m_PrematureCountDown)
{
m_PrematureCountDown = true;
m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
- SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
}
- else if(m_PrematureCountDownTimer < diff)
+ else if (m_PrematureCountDownTimer < diff)
{
// time's up!
- EndBattleGround(0); // noone wins
+ uint32 winner = 0;
+ if (GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam())
+ winner = ALLIANCE;
+ else if (GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam())
+ winner = HORDE;
+
+ EndBattleGround(winner);
m_PrematureCountDown = false;
}
else
{
uint32 newtime = m_PrematureCountDownTimer - diff;
// announce every minute
- if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000)
- SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
+ if (newtime > (MINUTE * IN_MILISECONDS))
+ {
+ if (newtime / (MINUTE * IN_MILISECONDS) != m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS))
+ PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS)));
+ }
+ else
+ {
+ //announce every 15 seconds
+ if (newtime / (15 * IN_MILISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILISECONDS))
+ PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / IN_MILISECONDS));
+ }
m_PrematureCountDownTimer = newtime;
}
}
else if (m_PrematureCountDown)
m_PrematureCountDown = false;
- if(GetStatus() == STATUS_WAIT_LEAVE)
+ /*********************************************************/
+ /*** BATTLEGROUND STARTING SYSTEM ***/
+ /*********************************************************/
+
+ if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
+ {
+ ModifyStartDelayTime(diff);
+
+ if (!(m_Events & BG_STARTING_EVENT_1))
+ {
+ m_Events |= BG_STARTING_EVENT_1;
+
+ // setup here, only when at least one player has ported to the map
+ if (!SetupBattleGround())
+ {
+ EndNow();
+ return;
+ }
+
+ StartingEventCloseDoors();
+ SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FIRST]);
+ //first start warning - 2 or 1 minute
+ SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ }
+ // After 1 minute or 30 seconds, warning is signalled
+ else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2))
+ {
+ m_Events |= BG_STARTING_EVENT_2;
+ SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ }
+ // After 30 or 15 seconds, warning is signalled
+ else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3))
+ {
+ m_Events |= BG_STARTING_EVENT_3;
+ SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ }
+ // delay expired (atfer 2 or 1 minute)
+ else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4))
+ {
+ m_Events |= BG_STARTING_EVENT_4;
+
+ StartingEventOpenDoors();
+
+ SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ SetStatus(STATUS_IN_PROGRESS);
+ SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FOURTH]);
+
+ //remove preparation
+ if (isArena())
+ {
+ //TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START);
+
+ for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
+ if (Player *plr = objmgr.GetPlayer(itr->first))
+ {
+ plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
+ // remove auras with duration lower than 30s
+ Unit::AuraMap & aurMap = plr->GetAuras();
+ for(Unit::AuraMap::iterator iter = aurMap.begin(); iter != aurMap.end();)
+ {
+ if (!iter->second->IsPermanent()
+ && iter->second->GetAuraDuration()<=30*IN_MILISECONDS
+ && iter->second->IsPositive()
+ && (!(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY))
+ && (!iter->second->IsAuraType(SPELL_AURA_MOD_INVISIBILITY)))
+ {
+ plr->RemoveAura(iter);
+ }
+ else
+ ++iter;
+ }
+ }
+
+ CheckArenaWinConditions();
+ }
+ else
+ {
+
+ PlaySoundToAll(SOUND_BG_START);
+
+ for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
+ if (Player* plr = objmgr.GetPlayer(itr->first))
+ plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
+ //Announce BG starting
+ if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
+ {
+ sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel());
+ }
+ }
+ }
+ }
+
+ /*********************************************************/
+ /*** BATTLEGROUND ENDING SYSTEM ***/
+ /*********************************************************/
+
+ if (GetStatus() == STATUS_WAIT_LEAVE)
{
// remove all players from battleground after 2 minutes
- m_EndTime += diff;
- if(m_EndTime >= TIME_TO_AUTOREMOVE) // 2 minutes
+ m_EndTime -= diff;
+ if (m_EndTime <= 0)
{
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ m_EndTime = 0;
+ BattleGroundPlayerMap::iterator itr, next;
+ for(itr = m_Players.begin(); itr != m_Players.end(); itr = next)
{
- m_RemovedPlayers[itr->first] = 1; // add to remove list (BG)
+ next = itr;
+ ++next;
+ //itr is erased here!
+ RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
+ // do not change any battleground's private variables
}
- // do not change any battleground's private variables
}
}
+
+ //update start time
+ m_StartTime += diff;
}
void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
@@ -283,10 +480,10 @@ void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, flo
void BattleGround::SendPacketToAll(WorldPacket *packet)
{
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
- if(plr)
+ if (plr)
plr->GetSession()->SendPacket(packet);
else
sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
@@ -295,23 +492,23 @@ void BattleGround::SendPacketToAll(WorldPacket *packet)
void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self)
{
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
- if(!plr)
+ if (!plr)
{
sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
continue;
}
- if(!self && sender == plr)
+ if (!self && sender == plr)
continue;
- uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ uint32 team = itr->second.Team;
if(!team) team = plr->GetTeam();
- if(team == TeamID)
+ if (team == TeamID)
plr->GetSession()->SendPacket(packet);
}
}
@@ -327,20 +524,20 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
{
WorldPacket data;
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
- if(!plr)
+ if (!plr)
{
sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
continue;
}
- uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ uint32 team = itr->second.Team;
if(!team) team = plr->GetTeam();
- if(team == TeamID)
+ if (team == TeamID)
{
sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
plr->GetSession()->SendPacket(&data);
@@ -350,20 +547,20 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
{
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
- if(!plr)
+ if (!plr)
{
sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
continue;
}
- uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ uint32 team = itr->second.Team;
if(!team) team = plr->GetTeam();
- if(team == TeamID)
+ if (team == TeamID)
plr->CastSpell(plr, SpellID, true);
}
}
@@ -387,20 +584,20 @@ void BattleGround::YellToAll(Creature* creature, const char* text, uint32 langua
void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
{
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
- if(!plr)
+ if (!plr)
{
sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
continue;
}
- uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ uint32 team = itr->second.Team;
if(!team) team = plr->GetTeam();
- if(team == TeamID)
+ if (team == TeamID)
UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
}
}
@@ -409,24 +606,24 @@ void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation,
{
FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
- if(!factionEntry)
+ if (!factionEntry)
return;
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
- if(!plr)
+ if (!plr)
{
sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
continue;
}
- uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
+ uint32 team = itr->second.Team;
if(!team) team = plr->GetTeam();
- if(team == TeamID)
- plr->ModifyFactionReputation(factionEntry, Reputation);
+ if (team == TeamID)
+ plr->GetReputationMgr().ModifyReputation(factionEntry, Reputation);
}
}
@@ -447,32 +644,25 @@ void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player
void BattleGround::EndBattleGround(uint32 winner)
{
this->RemoveFromBGFreeSlotQueue();
- uint32 almost_winning_team = HORDE;
+
ArenaTeam * winner_arena_team = NULL;
ArenaTeam * loser_arena_team = NULL;
uint32 loser_rating = 0;
uint32 winner_rating = 0;
WorldPacket data;
- Player *Source = NULL;
- const char *winmsg = "";
+ int32 winmsg_id = 0;
- if(winner == ALLIANCE)
+ if (winner == ALLIANCE)
{
- if(isBattleGround())
- winmsg = GetTrinityString(LANG_BG_A_WINS);
- else
- winmsg = GetTrinityString(LANG_ARENA_GOLD_WINS);
+ winmsg_id = isBattleGround() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS;
PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
SetWinner(WINNER_ALLIANCE);
}
- else if(winner == HORDE)
+ else if (winner == HORDE)
{
- if(isBattleGround())
- winmsg = GetTrinityString(LANG_BG_H_WINS);
- else
- winmsg = GetTrinityString(LANG_ARENA_GREEN_WINS);
+ winmsg_id = isBattleGround() ? LANG_BG_H_WINS : LANG_ARENA_GREEN_WINS;
PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
@@ -484,38 +674,23 @@ void BattleGround::EndBattleGround(uint32 winner)
}
SetStatus(STATUS_WAIT_LEAVE);
- m_EndTime = 0;
+ //we must set it this way, because end time is sent in packet!
+ m_EndTime = TIME_TO_AUTOREMOVE;
// arena rating calculation
- if(isArena() && isRated())
+ if (isArena() && isRated())
{
- if(winner == ALLIANCE)
- {
- winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
- loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
- }
- else if(winner == HORDE)
- {
- winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
- loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
- }
- if(winner_arena_team && loser_arena_team)
+ winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(winner));
+ loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(winner)));
+ if (winner_arena_team && loser_arena_team)
{
loser_rating = loser_arena_team->GetStats().rating;
winner_rating = winner_arena_team->GetStats().rating;
int32 winner_change = winner_arena_team->WonAgainst(loser_rating);
int32 loser_change = loser_arena_team->LostAgainst(winner_rating);
sLog.outDebug("--- Winner rating: %u, Loser rating: %u, Winner change: %u, Losser change: %u ---", winner_rating, loser_rating, winner_change, loser_change);
- if(winner == ALLIANCE)
- {
- SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
- SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
- }
- else
- {
- SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
- SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
- }
+ SetArenaTeamRatingChangeForTeam(winner, winner_change);
+ SetArenaTeamRatingChangeForTeam(GetOtherTeam(winner), loser_change);
}
else
{
@@ -524,69 +699,54 @@ void BattleGround::EndBattleGround(uint32 winner)
}
}
- if(!isArena()){
-
- if(m_score[GetTeamIndexByTeamId(ALLIANCE)] == m_score[GetTeamIndexByTeamId(HORDE)])
- almost_winning_team = 0; //no real winner
- if(m_score[GetTeamIndexByTeamId(ALLIANCE)] > m_score[GetTeamIndexByTeamId(HORDE)])
- almost_winning_team = ALLIANCE;
-
- }
-
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
- if(!plr)
+ uint32 team = itr->second.Team;
+
+ if (!plr)
{
+ //if rated arena match - make member lost!
+ if (isArena() && isRated() && winner_arena_team && loser_arena_team)
+ {
+ if (team == winner)
+ winner_arena_team->OfflineMemberLost(itr->first, loser_rating);
+ else
+ loser_arena_team->OfflineMemberLost(itr->first, winner_rating);
+ }
sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
continue;
}
// should remove spirit of redemption
if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
- plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
+ plr->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
- if(!plr->isAlive())
+ if (!plr->isAlive())
{
plr->ResurrectPlayer(1.0f);
plr->SpawnCorpseBones();
}
- uint32 team = itr->second.Team;
- if(!team) team = plr->GetTeam();
+ //this line is obsolete - team is set ALWAYS
+ //if(!team) team = plr->GetTeam();
// per player calculation
- if(isArena() && isRated() && winner_arena_team && loser_arena_team)
+ if (isArena() && isRated() && winner_arena_team && loser_arena_team)
{
- if(team == winner)
+ if (team == winner)
winner_arena_team->MemberWon(plr,loser_rating);
else
loser_arena_team->MemberLost(plr,winner_rating);
}
- if(team == winner)
+ if (team == winner)
{
- if(!Source)
- Source = plr;
RewardMark(plr,ITEM_WINNER_COUNT);
- UpdatePlayerScore(plr, SCORE_BONUS_HONOR, 20);
- RewardQuest(plr);
- }
- else if(winner !=0)
- {
- RewardMark(plr,ITEM_LOSER_COUNT);
- }
- else if(winner == 0)
- {
- if(sWorld.getConfig(CONFIG_PREMATURE_BG_REWARD)) // We're feeling generous, giving rewards to people who not earned them ;)
- { //nested ifs for the win! its boring writing that, forgive me my unfunniness
-
- if(almost_winning_team == team) //player's team had more points
- RewardMark(plr,ITEM_WINNER_COUNT);
- else
- RewardMark(plr,ITEM_LOSER_COUNT); // if scores were the same, each team gets 1 mark.
+ RewardQuestComplete(plr);
}
- }
+ else if(winner)
+ RewardMark(plr,ITEM_LOSER_COUNT);
plr->CombatStopWithPets(true);
@@ -595,12 +755,13 @@ void BattleGround::EndBattleGround(uint32 winner)
sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
plr->GetSession()->SendPacket(&data);
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType());
plr->GetSession()->SendPacket(&data);
+ plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
}
- if(isArena() && isRated() && winner_arena_team && loser_arena_team)
+ if (isArena() && isRated() && winner_arena_team && loser_arena_team)
{
// update arena points only after increasing the player's match count!
//obsolete: winner_arena_team->UpdateArenaPointsHelper();
@@ -612,17 +773,16 @@ void BattleGround::EndBattleGround(uint32 winner)
// this way all arena team members will get notified, not only the ones who participated in this match
winner_arena_team->NotifyStatsChanged();
loser_arena_team->NotifyStatsChanged();
- sLog.outDebug("Rated arena match between %s and %s finished, winner: %s", loser_arena_team->GetName().c_str(),winner_arena_team->GetName().c_str(),winner_arena_team->GetName().c_str());
}
- // inform invited players about the removal
- sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
+ if (winmsg_id)
+ SendMessageToAll(winmsg_id, CHAT_MSG_BG_SYSTEM_NEUTRAL);
+}
- if(Source)
- {
- ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg);
- SendPacketToAll(&data);
- }
+uint32 BattleGround::GetBonusHonorFromKill(uint32 kills) const
+{
+ //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
+ return MaNGOS::Honor::hk_honor_at_level(GetMaxLevel(), kills);
}
uint32 BattleGround::GetBattlemasterEntry() const
@@ -640,14 +800,7 @@ uint32 BattleGround::GetBattlemasterEntry() const
void BattleGround::RewardMark(Player *plr,uint32 count)
{
- // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
- if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
- return;
-
- if(!plr || !count)
- return;
-
- BattleGroundMarks mark;
+ BattleGroundMarks mark;
switch(GetTypeID())
{
case BATTLEGROUND_AV:
@@ -659,41 +812,73 @@ void BattleGround::RewardMark(Player *plr,uint32 count)
case BATTLEGROUND_AB:
mark = ITEM_AB_MARK_OF_HONOR;
break;
- case BATTLEGROUND_EY:
+ case BATTLEGROUND_EY:
mark = ITEM_EY_MARK_OF_HONOR;
break;
default:
return;
}
- if ( objmgr.GetItemPrototype( mark ) )
+ //if (IsSpell)
+ // RewardSpellCast(plr,mark);
+ //else
+ RewardItem(plr,mark,count);
+}
+
+void BattleGround::RewardSpellCast(Player *plr, uint32 spell_id)
+{
+ // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
+ if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
+ return;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
+ if(!spellInfo)
{
- ItemPosCountVec dest;
- uint32 no_space_count = 0;
- uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
- if( msg != EQUIP_ERR_OK ) // convert to possible store amount
- count -= no_space_count;
+ sLog.outError("Battleground reward casting spell %u not exist.",spell_id);
+ return;
+ }
- if(!dest.empty()) // can add some
- if(Item* item = plr->StoreNewItem( dest, mark, true, 0))
- plr->SendNewItem(item,count,false,true);
+ plr->CastSpell(plr, spellInfo, true);
+}
+
+void BattleGround::RewardItem(Player *plr, uint32 item_id, uint32 count)
+{
+ // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
+ if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
+ return;
+
+ ItemPosCountVec dest;
+ uint32 no_space_count = 0;
+ uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item_id, count, &no_space_count );
- if(no_space_count > 0)
- SendRewardMarkByMail(plr,mark,no_space_count);
+ if( msg == EQUIP_ERR_ITEM_NOT_FOUND)
+ {
+ sLog.outErrorDb("Battleground reward item (Entry %u) not exist in `item_template`.",item_id);
+ return;
}
+
+ if( msg != EQUIP_ERR_OK ) // convert to possible store amount
+ count -= no_space_count;
+
+ if( count != 0 && !dest.empty()) // can add some
+ if (Item* item = plr->StoreNewItem( dest, item_id, true, 0))
+ plr->SendNewItem(item,count,false,true);
+
+ if (no_space_count > 0)
+ SendRewardMarkByMail(plr,item_id,no_space_count);
}
void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
{
uint32 bmEntry = GetBattlemasterEntry();
- if(!bmEntry)
+ if (!bmEntry)
return;
ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
- if(!markProto)
+ if (!markProto)
return;
- if(Item* markItem = Item::CreateItem(mark,count,plr))
+ if (Item* markItem = Item::CreateItem(mark,count,plr))
{
// save new item before send
markItem->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
@@ -705,8 +890,8 @@ void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
// subject: item name
std::string subject = markProto->Name1;
int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
- if ( loc_idx >= 0 )
- if(ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
+ if (loc_idx >= 0 )
+ if (ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty())
subject = il->Name[loc_idx];
@@ -720,12 +905,8 @@ void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
}
}
-void BattleGround::RewardQuest(Player *plr)
+void BattleGround::RewardQuestComplete(Player *plr)
{
- // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
- if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
- return;
-
uint32 quest;
switch(GetTypeID())
{
@@ -745,7 +926,7 @@ void BattleGround::RewardQuest(Player *plr)
return;
}
- plr->CastSpell(plr, quest, true);
+ RewardSpellCast(plr, quest);
}
void BattleGround::BlockMovement(Player *plr)
@@ -758,17 +939,17 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
uint32 team = GetPlayerTeam(guid);
bool participant = false;
// Remove from lists/maps
- std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
- if(itr != m_Players.end())
+ BattleGroundPlayerMap::iterator itr = m_Players.find(guid);
+ if (itr != m_Players.end())
{
- UpdatePlayersCountByTeam(team, true); // -1 player
+ UpdatePlayersCountByTeam(team, true); // -1 player
m_Players.erase(itr);
// check if the player was a participant of the match, or only entered through gm command (goname)
participant = true;
}
std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
- if(itr2 != m_PlayerScores.end())
+ if (itr2 != m_PlayerScores.end())
{
delete itr2->second; // delete player's score
m_PlayerScores.erase(itr2);
@@ -780,7 +961,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
// should remove spirit of redemption
if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
- plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
+ plr->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
if(plr && !plr->isAlive()) // resurrect on exit
{
@@ -790,100 +971,91 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
RemovePlayer(plr, guid); // BG subclass specific code
- if(plr)
+ if(participant) // if the player was a match participant, remove auras, calc rating, update queue
{
- plr->ClearAfkReports();
-
- if(participant) // if the player was a match participant, remove auras, calc rating, update queue
+ BattleGroundTypeId bgTypeId = GetTypeID();
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
+ if (plr)
{
+ plr->ClearAfkReports();
+
if(!team) team = plr->GetTeam();
- uint32 bgTypeId = GetTypeID();
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
// if arena, remove the specific arena auras
- if(isArena())
+ if (isArena())
{
- plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
- bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
+ plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out
+ bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
- // summon old pet if there was one and there isn't a current pet
- if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber())
- {
- Pet* NewPet = new Pet;
- if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true))
- delete NewPet;
+ // unsummon current and summon old pet if there was one and there isn't a current pet
+ plr->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT);
+ plr->ResummonPetTemporaryUnSummonedIfAny();
- (plr)->SetTemporaryUnsummonedPetNumber(0);
- }
-
- if(isRated() && GetStatus() == STATUS_IN_PROGRESS)
+ if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
{
//left a rated match while the encounter was in progress, consider as loser
- ArenaTeam * winner_arena_team = 0;
- ArenaTeam * loser_arena_team = 0;
- if(team == HORDE)
- {
- winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
- loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
- }
- else
- {
- winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
- loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
- }
- if(winner_arena_team && loser_arena_team)
- {
+ ArenaTeam * winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
+ ArenaTeam * loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team));
+ if (winner_arena_team && loser_arena_team)
loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());
- }
}
}
-
- WorldPacket data;
- if(SendPacket)
+ if (SendPacket)
{
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
+ WorldPacket data;
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0);
plr->GetSession()->SendPacket(&data);
}
// this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
plr->RemoveBattleGroundQueueId(bgQueueTypeId);
-
- DecreaseInvitedCount(team);
- //we should update battleground queue, but only if bg isn't ending
- if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType());
-
- Group * group = plr->GetGroup();
- // remove from raid group if exist
- if(group && group == GetBgRaid(team))
+ }
+ else
+ // removing offline participant
+ {
+ if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
{
- if(!group->RemoveMember(guid, 0)) // group was disbanded
- {
- SetBgRaid(team, NULL);
- delete group;
- }
+ //left a rated match while the encounter was in progress, consider as loser
+ ArenaTeam * others_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
+ ArenaTeam * players_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team));
+ if (others_arena_team && players_arena_team)
+ players_arena_team->OfflineMemberLost(guid, others_arena_team->GetRating());
}
+ }
- // Let others know
- sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
- SendPacketToTeam(team, &data, plr, false);
+ // remove from raid group if player is member
+ if (Group *group = GetBgRaid(team))
+ {
+ if( !group->RemoveMember(guid, 0) ) // group was disbanded
+ {
+ SetBgRaid(team, NULL);
+ delete group;
+ }
}
+ DecreaseInvitedCount(team);
+ //we should update battleground queue, but only if bg isn't ending
+ if (isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE)
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId());
+ // Let others know
+ WorldPacket data;
+ sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, guid);
+ SendPacketToTeam(team, &data, plr, false);
+ }
+ if (plr)
+ {
// Do next only if found in battleground
- plr->SetBattleGroundId(0); // We're not in BG.
+ plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
// reset destination bg team
plr->SetBGTeam(0);
- if(Transport)
- {
- plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO());
- }
+ if (Transport)
+ plr->TeleportTo(plr->GetBattleGroundEntryPoint());
- // Log
sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
}
- if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
+ if (!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
{
// if no players left AND no invitees left, set this bg to delete in next update
// direct deletion could cause crashes
@@ -899,7 +1071,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
// this method is called when no players remains in battleground
void BattleGround::Reset()
{
- SetQueueType(MAX_BATTLEGROUND_QUEUES);
+ SetQueueId(QUEUE_ID_MAX_LEVEL_19);
SetWinner(WINNER_NONE);
SetStatus(STATUS_WAIT_QUEUE);
SetStartTime(0);
@@ -911,7 +1083,7 @@ void BattleGround::Reset()
m_Events = 0;
if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
- sLog.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
+ sLog.outError("BattleGround system: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
m_InvitedAlliance = 0;
m_InvitedHorde = 0;
@@ -919,9 +1091,6 @@ void BattleGround::Reset()
m_Players.clear();
m_PlayerScores.clear();
-
- // reset BGSubclass
- ResetBGSubclass();
}
void BattleGround::StartBattleGround()
@@ -940,7 +1109,7 @@ void BattleGround::AddPlayer(Player *plr)
uint32 team = plr->GetBGTeam();
BattleGroundPlayer bp;
- bp.LastOnlineTime = 0;
+ bp.OfflineRemoveTime = 0;
bp.Team = team;
// Add to list/maps
@@ -953,40 +1122,28 @@ void BattleGround::AddPlayer(Player *plr)
SendPacketToTeam(team, &data, plr, false);
// add arena specific auras
- if(isArena())
+ if (isArena())
{
plr->RemoveArenaSpellCooldowns();
plr->RemoveArenaAuras();
- plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
+ plr->RemoveArenaEnchantments(TEMP_ENCHANTMENT_SLOT);
if(team == ALLIANCE) // gold
{
- if(plr->GetTeam() == HORDE)
+ if (plr->GetTeam() == HORDE)
plr->CastSpell(plr, SPELL_HORDE_GOLD_FLAG,true);
else
plr->CastSpell(plr, SPELL_ALLIANCE_GOLD_FLAG,true);
}
else // green
{
- if(plr->GetTeam() == HORDE)
+ if (plr->GetTeam() == HORDE)
plr->CastSpell(plr, SPELL_HORDE_GREEN_FLAG,true);
else
plr->CastSpell(plr, SPELL_ALLIANCE_GREEN_FLAG,true);
}
plr->DestroyConjuredItems(true);
-
- Pet* pet = plr->GetPet();
- if(pet)
- {
- if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
- {
- (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
- (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
- }
- (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
- }
- else
- (plr)->SetTemporaryUnsummonedPetNumber(0);
+ plr->UnsummonPetTemporaryIfAny();
if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
{
@@ -1002,15 +1159,86 @@ void BattleGround::AddPlayer(Player *plr)
plr->CastSpell(plr, SPELL_PREPARATION, true); // reduces all mana cost of spells.
}
+ plr->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, ACHIEVEMENT_CRITERIA_CONDITION_MAP, GetMapId());
+ plr->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, ACHIEVEMENT_CRITERIA_CONDITION_MAP, GetMapId());
+
+ // setup BG group membership
+ PlayerAddedToBGCheckIfBGIsRunning(plr);
+ AddOrSetPlayerToCorrectBgGroup(plr, guid, team);
+
// Log
sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
}
+/* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
+void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, uint32 team)
+{
+ Group* group = GetBgRaid(team);
+ if(!group) // first player joined
+ {
+ group = new Group;
+ SetBgRaid(team, group);
+ group->Create(plr_guid, plr->GetName());
+ }
+ else // raid already exist
+ {
+ if (group->IsMember(plr_guid))
+ {
+ uint8 subgroup = group->GetMemberGroup(plr_guid);
+ plr->SetBattleGroundRaid(group, subgroup);
+ }
+ else
+ {
+ group->AddMember(plr_guid, plr->GetName());
+ if (Group* originalGroup = plr->GetOriginalGroup())
+ if (originalGroup->IsLeader(plr_guid))
+ group->ChangeLeader(plr_guid);
+ }
+ }
+}
+
+// This method should be called when player logs into running battleground
+void BattleGround::EventPlayerLoggedIn(Player* player, uint64 plr_guid)
+{
+ // player is correct pointer
+ for(std::deque<uint64>::iterator itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr)
+ {
+ if (*itr == plr_guid)
+ {
+ m_OfflineQueue.erase(itr);
+ break;
+ }
+ }
+ m_Players[plr_guid].OfflineRemoveTime = 0;
+ PlayerAddedToBGCheckIfBGIsRunning(player);
+ // if battleground is starting, then add preparation aura
+ // we don't have to do that, because preparation aura isn't removed when player logs out
+}
+
+// This method should be called when player logs out from running battleground
+void BattleGround::EventPlayerLoggedOut(Player* player)
+{
+ // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
+ m_OfflineQueue.push_back(player->GetGUID());
+ m_Players[player->GetGUID()].OfflineRemoveTime = sWorld.GetGameTime() + MAX_OFFLINE_TIME;
+ if (GetStatus() == STATUS_IN_PROGRESS)
+ {
+ if (isBattleGround())
+ EventPlayerDroppedFlag(player);
+ else
+ {
+ //1 player is logging out, if it is the last, then end arena!
+ if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())))
+ EndBattleGround(GetOtherTeam(player->GetTeam()));
+ }
+ }
+}
+
/* This method should be called only once ... it adds pointer to queue */
void BattleGround::AddToBGFreeSlotQueue()
{
// make sure to add only once
- if(!m_InBGFreeSlotQueue)
+ if (!m_InBGFreeSlotQueue && isBattleGround())
{
sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
m_InBGFreeSlotQueue = true;
@@ -1023,7 +1251,7 @@ void BattleGround::RemoveFromBGFreeSlotQueue()
// set to be able to re-add if needed
m_InBGFreeSlotQueue = false;
// uncomment this code when battlegrounds will work like instances
- for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
+ for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
{
if ((*itr)->GetInstanceID() == m_InstanceID)
{
@@ -1034,61 +1262,12 @@ void BattleGround::RemoveFromBGFreeSlotQueue()
}
// get the number of free slots for team
-// works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group
+// returns the number how many players can join battleground to MaxPlayersPerTeam
uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
{
- //if BG is starting ... invite anyone
- if (GetStatus() == STATUS_WAIT_JOIN)
+ //return free slot count to MaxPlayerPerTeam
+ if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS)
return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
- //if BG is already started .. do not allow to join too much players of one faction
- uint32 otherTeam;
- uint32 otherIn;
- if (Team == ALLIANCE)
- {
- otherTeam = GetInvitedCount(HORDE);
- otherIn = GetPlayersCountByTeam(HORDE);
- }
- else
- {
- otherTeam = GetInvitedCount(ALLIANCE);
- otherIn = GetPlayersCountByTeam(ALLIANCE);
- }
- if (GetStatus() == STATUS_IN_PROGRESS)
- {
- // difference based on ppl invited (not necessarily entered battle)
- // default: allow 0
- uint32 diff = 0;
- // allow join one person if the sides are equal (to fill up bg to minplayersperteam)
- if (otherTeam == GetInvitedCount(Team))
- diff = 1;
- // allow join more ppl if the other side has more players
- else if(otherTeam > GetInvitedCount(Team))
- diff = otherTeam - GetInvitedCount(Team);
-
- // difference based on max players per team (don't allow inviting more)
- uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
-
- // difference based on players who already entered
- // default: allow 0
- uint32 diff3 = 0;
- // allow join one person if the sides are equal (to fill up bg minplayersperteam)
- if (otherIn == GetPlayersCountByTeam(Team))
- diff3 = 1;
- // allow join more ppl if the other side has more players
- else if (otherIn > GetPlayersCountByTeam(Team))
- diff3 = otherIn - GetPlayersCountByTeam(Team);
- // or other side has less than minPlayersPerTeam
- else if (GetInvitedCount(Team) <= GetMinPlayersPerTeam())
- diff3 = GetMinPlayersPerTeam() - GetInvitedCount(Team) + 1;
-
- // return the minimum of the 3 differences
-
- // min of diff and diff 2
- diff = diff < diff2 ? diff : diff2;
-
- // min of diff, diff2 and diff3
- return diff < diff3 ? diff : diff3 ;
- }
return 0;
}
@@ -1101,7 +1280,7 @@ bool BattleGround::HasFreeSlots() const
void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
{
//this procedure is called from virtual function implemented in bg subclass
- std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
+ std::map<uint64, BattleGroundScore*>::const_iterator itr = m_PlayerScores.find(Source->GetGUID());
if(itr == m_PlayerScores.end()) // player not found...
return;
@@ -1119,10 +1298,10 @@ void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
break;
case SCORE_BONUS_HONOR: // Honor bonus
// do not add honor in arenas
- if(isBattleGround())
+ if (isBattleGround())
{
// reward honor instantly
- if(Source->RewardHonor(NULL, 1, value))
+ if (Source->RewardHonor(NULL, 1, value))
itr->second->BonusHonor += value;
}
break;
@@ -1144,14 +1323,13 @@ void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid
m_ReviveQueue[npc_guid].push_back(player_guid);
Player *plr = objmgr.GetPlayer(player_guid);
- if(!plr)
+ if (!plr)
return;
- plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
- if(spellInfo)
+ if (spellInfo)
{
- Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
+ Aura *Aur = new Aura(spellInfo, 1, NULL, plr);
plr->AddAura(Aur);
}
}
@@ -1162,12 +1340,12 @@ void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
{
for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
{
- if(*itr2 == player_guid)
+ if (*itr2 == player_guid)
{
(itr->second).erase(itr2);
Player *plr = objmgr.GetPlayer(player_guid);
- if(!plr)
+ if (!plr)
return;
plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
@@ -1181,14 +1359,15 @@ void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
{
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
- if(!map)
+ if (!map)
return false;
// must be created this way, adding to godatamap would add it to the base map of the instance
// and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
// so we must create it specific for this instance
GameObject * go = new GameObject;
- if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
+ if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,
+ PHASEMASK_NORMAL, x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,GO_STATE_READY))
{
sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
@@ -1228,10 +1407,10 @@ bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float
void BattleGround::DoorClose(uint32 type)
{
GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
- if(obj)
+ if (obj)
{
//if doors are open, close it
- if( obj->getLootState() == GO_ACTIVATED && !obj->GetGoState() )
+ if (obj->getLootState() == GO_ACTIVATED && obj->GetGoState() != GO_STATE_READY)
{
//change state to allow door to be closed
obj->SetLootState(GO_READY);
@@ -1247,7 +1426,7 @@ void BattleGround::DoorClose(uint32 type)
void BattleGround::DoorOpen(uint32 type)
{
GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
- if(obj)
+ if (obj)
{
//change state to be sure they will be opened
obj->SetLootState(GO_READY);
@@ -1278,15 +1457,15 @@ Creature* BattleGround::GetBGCreature(uint32 type)
void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
{
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
- if(!map)
+ if (!map)
return;
- if( respawntime == 0 )
+ if (respawntime == 0)
{
GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
- if(obj)
+ if (obj)
{
//we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
- if( obj->getLootState() == GO_JUST_DEACTIVATED )
+ if (obj->getLootState() == GO_JUST_DEACTIVATED)
obj->SetLootState(GO_READY);
obj->SetRespawnTime(0);
map->Add(obj);
@@ -1295,7 +1474,7 @@ void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
else
{
GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
- if(obj)
+ if (obj)
{
map->Add(obj);
obj->SetRespawnTime(respawntime);
@@ -1307,11 +1486,11 @@ void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
{
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
- if(!map)
+ if (!map)
return NULL;
Creature* pCreature = new Creature;
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, entry, teamval))
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, PHASEMASK_NORMAL, entry, teamval))
{
sLog.outError("Can't create creature entry: %u",entry);
delete pCreature;
@@ -1320,15 +1499,14 @@ Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, f
pCreature->Relocate(x, y, z, o);
- if(!pCreature->IsPositionValid())
+ if (!pCreature->IsPositionValid())
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not added to battleground. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ sLog.outError("Creature (guidlow %d, entry %d) not added to battleground. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
delete pCreature;
return NULL;
}
pCreature->SetHomePosition(x, y, z, o);
- pCreature->AIM_Initialize();
//pCreature->SetDungeonDifficulty(0);
@@ -1341,13 +1519,13 @@ Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, f
void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
{
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
- if(!map)
+ if (!map)
return false;
- if(respawntime == 0)
+ if (respawntime == 0)
{
Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
- if(obj)
+ if (obj)
{
//obj->Respawn(); // bugged
obj->SetRespawnTime(0);
@@ -1358,7 +1536,7 @@ void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
else
{
Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
- if(obj)
+ if (obj)
{
obj->setDeathState(DEAD);
obj->SetRespawnTime(respawntime);
@@ -1369,8 +1547,11 @@ void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
*/
bool BattleGround::DelCreature(uint32 type)
{
+ if (!m_BgCreatures[type])
+ return true;
+
Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
- if(!cr)
+ if (!cr)
{
sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
return false;
@@ -1384,8 +1565,11 @@ bool BattleGround::DelCreature(uint32 type)
bool BattleGround::DelObject(uint32 type)
{
+ if (!m_BgObjects[type])
+ return true;
+
GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
- if(!obj)
+ if (!obj)
{
sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type]));
return false;
@@ -1400,13 +1584,13 @@ bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float
{
uint32 entry = 0;
- if(team == ALLIANCE)
+ if (team == ALLIANCE)
entry = 13116;
else
entry = 13117;
Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
- if(!pCreature)
+ if (!pCreature)
{
sLog.outError("Can't create Spirit guide. BattleGround not created!");
EndNow();
@@ -1417,10 +1601,12 @@ bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float
pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
// aura
- pCreature->SetUInt32Value(UNIT_FIELD_AURA, SPELL_SPIRIT_HEAL_CHANNEL);
- pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
- pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
- pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
+ //TODO: Fix display here
+ //pCreature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
+
+ //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
+ //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
+ //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
// casting visual effect
pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
// correct cast speed
@@ -1431,31 +1617,40 @@ bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float
return true;
}
-void BattleGround::SendMessageToAll(char const* text)
+void BattleGround::SendMessageToAll(int32 entry, ChatMsg type, Player const* source)
{
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
- SendPacketToAll(&data);
+ MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source);
+ MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundChatBuilder> bg_do(bg_builder);
+ BroadcastWorker(bg_do);
}
-void BattleGround::SendMessageToAll(int32 entry)
+void BattleGround::PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ...)
{
- char const* text = GetTrinityString(entry);
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
- SendPacketToAll(&data);
+ va_list ap;
+ va_start(ap, source);
+
+ MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source, &ap);
+ MaNGOS::LocalizedPacketDo<MaNGOS::BattleGroundChatBuilder> bg_do(bg_builder);
+ BroadcastWorker(bg_do);
+
+ va_end(ap);
+}
+
+void BattleGround::SendMessage2ToAll(int32 entry, ChatMsg type, Player const* source, int32 arg1, int32 arg2)
+{
+ MaNGOS::BattleGround2ChatBuilder bg_builder(type, entry, source, arg1, arg2);
+ MaNGOS::LocalizedPacketDo<MaNGOS::BattleGround2ChatBuilder> bg_do(bg_builder);
+ BroadcastWorker(bg_do);
}
void BattleGround::EndNow()
{
RemoveFromBGFreeSlotQueue();
SetStatus(STATUS_WAIT_LEAVE);
- SetEndTime(TIME_TO_AUTOREMOVE);
- // inform invited players about the removal
- sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
+ SetEndTime(0);
}
-// Battleground messages are localized using the dbc lang, they are not client language dependent
+//to be removed
const char *BattleGround::GetTrinityString(int32 entry)
{
// FIXME: now we have different DBC locales and need localized message for each target client
@@ -1470,7 +1665,7 @@ buffs are in their positions when battleground starts
void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
{
GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
- if(!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
+ if (!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
return;
//change buff type, when buff is used:
@@ -1486,13 +1681,13 @@ void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
//randomly select new buff
uint8 buff = urand(0, 2);
uint32 entry = obj->GetEntry();
- if( m_BuffChange && entry != Buff_Entries[buff] )
+ if (m_BuffChange && entry != Buff_Entries[buff])
{
//despawn current buff
SpawnBGObject(index, RESPAWN_ONE_DAY);
//set index for new one
for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
- if( entry == Buff_Entries[currBuffTypeIndex] )
+ if (entry == Buff_Entries[currBuffTypeIndex])
{
index -= currBuffTypeIndex;
index += buff;
@@ -1510,46 +1705,77 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer )
UpdatePlayerScore(player, SCORE_DEATHS, 1);
// add +1 kills to group and +1 killing_blows to killer
- if( killer )
+ if (killer)
{
UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
- for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = objmgr.GetPlayer(itr->first);
- if(!plr || plr == killer)
+ if (!plr || plr == killer)
continue;
- if( plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player) )
+ if (plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player))
UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
}
}
- // to be able to remove insignia
- player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
+ // to be able to remove insignia -- ONLY IN BattleGrounds
+ if (!isArena())
+ player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
}
// return the player's team based on battlegroundplayer info
// used in same faction arena matches mainly
uint32 BattleGround::GetPlayerTeam(uint64 guid)
{
- std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
- if(itr!=m_Players.end())
+ BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid);
+ if (itr!=m_Players.end())
return itr->second.Team;
return 0;
}
+uint32 BattleGround::GetOtherTeam(uint32 teamId)
+{
+ return (teamId) ? ((teamId == ALLIANCE) ? HORDE : ALLIANCE) : 0;
+}
+
+bool BattleGround::IsPlayerInBattleGround(uint64 guid)
+{
+ BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid);
+ if (itr != m_Players.end())
+ return true;
+ return false;
+}
+
+void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player* plr)
+{
+ if (GetStatus() != STATUS_WAIT_LEAVE)
+ return;
+
+ WorldPacket data;
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
+
+ BlockMovement(plr);
+
+ sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
+ plr->GetSession()->SendPacket(&data);
+
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType());
+ plr->GetSession()->SendPacket(&data);
+}
+
uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
{
int count = 0;
- for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
- if(itr->second.Team == Team)
+ if (itr->second.Team == Team)
{
Player * pl = objmgr.GetPlayer(itr->first);
- if(pl && pl->isAlive())
+ if (pl && pl->isAlive() && !pl->HasByteFlag(UNIT_FIELD_BYTES_2, 3, FORM_SPIRITOFREDEMPTION))
++count;
}
}
@@ -1577,3 +1803,23 @@ void BattleGround::HandleKillUnit(Creature *creature, Player *killer)
{
}
+void BattleGround::CheckArenaWinConditions()
+{
+ if (!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
+ EndBattleGround(HORDE);
+ else if (GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
+ EndBattleGround(ALLIANCE);
+}
+
+void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid )
+{
+ Group* &old_raid = TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE];
+ if(old_raid) old_raid->SetBattlegroundGroup(NULL);
+ if(bg_raid) bg_raid->SetBattlegroundGroup(this);
+ old_raid = bg_raid;
+}
+
+WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard( Player* player )
+{
+ return objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam() );
+}
diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h
index e03e36cbd1e..509ba6eb972 100644
--- a/src/game/BattleGround.h
+++ b/src/game/BattleGround.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,13 +22,16 @@
#define __BATTLEGROUND_H
#include "Common.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
-#include "Opcodes.h"
-#include "ObjectMgr.h"
-#include "BattleGroundMgr.h"
#include "SharedDefines.h"
+class Creature;
+class GameObject;
+class Group;
+class Player;
+class WorldPacket;
+
+struct WorldSafeLocsEntry;
+
enum BattleGroundSounds
{
SOUND_HORDE_WINS = 8454,
@@ -83,17 +86,22 @@ enum BattleGroundTimeIntervals
{
RESURRECTION_INTERVAL = 30000, // ms
REMIND_INTERVAL = 30000, // ms
+ INVITATION_REMIND_TIME = 60000, // ms
INVITE_ACCEPT_WAIT_TIME = 80000, // ms
TIME_TO_AUTOREMOVE = 120000, // ms
- MAX_OFFLINE_TIME = 300000, // ms
- START_DELAY0 = 120000, // ms
- START_DELAY1 = 60000, // ms
- START_DELAY2 = 30000, // ms
- START_DELAY3 = 15000, // ms used only in arena
+ MAX_OFFLINE_TIME = 300, // secs
RESPAWN_ONE_DAY = 86400, // secs
RESPAWN_IMMEDIATELY = 0, // secs
BUFF_RESPAWN_TIME = 180, // secs
- BG_HONOR_SCORE_TICKS = 330 // points
+};
+
+enum BattleGroundStartTimeIntervals
+{
+ BG_START_DELAY_2M = 120000, // ms (2 minutes)
+ BG_START_DELAY_1M = 60000, // ms (1 minute)
+ BG_START_DELAY_30S = 30000, // ms (30 seconds)
+ BG_START_DELAY_15S = 15000, // ms (15 seconds) Used only in arena
+ BG_START_DELAY_NONE = 0, // ms
};
enum BattleGroundBuffObjects
@@ -107,16 +115,16 @@ const uint32 Buff_Entries[3] = { BG_OBJECTID_SPEEDBUFF_ENTRY, BG_OBJECTID_REGENB
enum BattleGroundStatus
{
- STATUS_NONE = 0,
- STATUS_WAIT_QUEUE = 1,
- STATUS_WAIT_JOIN = 2,
- STATUS_IN_PROGRESS = 3,
- STATUS_WAIT_LEAVE = 4 // custom
+ STATUS_NONE = 0, // first status, should mean bg is not instance
+ STATUS_WAIT_QUEUE = 1, // means bg is empty and waiting for queue
+ STATUS_WAIT_JOIN = 2, // this means, that BG has already started and it is waiting for more players
+ STATUS_IN_PROGRESS = 3, // means bg is running
+ STATUS_WAIT_LEAVE = 4 // means some faction has won BG and it is ending
};
struct BattleGroundPlayer
{
- uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes
+ time_t OfflineRemoveTime; // for tracking and removing offline players from queue after 5 minutes
uint32 Team; // Player's team
};
@@ -129,31 +137,33 @@ struct BattleGroundObjectInfo
uint32 spellid;
};
-#define MAX_QUEUED_PLAYERS_MAP 7
-
-enum BattleGroundTypeId
+// handle the queue types and bg types separately to enable joining queue for different sized arenas at the same time
+enum BattleGroundQueueTypeId
{
- BATTLEGROUND_AV = 1,
- BATTLEGROUND_WS = 2,
- BATTLEGROUND_AB = 3,
- BATTLEGROUND_NA = 4,
- BATTLEGROUND_BE = 5,
- BATTLEGROUND_AA = 6,
- BATTLEGROUND_EY = 7,
- BATTLEGROUND_RL = 8
+ BATTLEGROUND_QUEUE_NONE = 0,
+ BATTLEGROUND_QUEUE_AV = 1,
+ BATTLEGROUND_QUEUE_WS = 2,
+ BATTLEGROUND_QUEUE_AB = 3,
+ BATTLEGROUND_QUEUE_EY = 4,
+ BATTLEGROUND_QUEUE_SA = 5,
+ BATTLEGROUND_QUEUE_2v2 = 6,
+ BATTLEGROUND_QUEUE_3v3 = 7,
+ BATTLEGROUND_QUEUE_5v5 = 8
};
+#define MAX_BATTLEGROUND_QUEUE_TYPES 9
-// handle the queue types and bg types separately to enable joining queue for different sized arenas at the same time
-enum BattleGroundQueueTypeId
+enum BGQueueIdBasedOnLevel // queue_id for level ranges
{
- BATTLEGROUND_QUEUE_AV = 1,
- BATTLEGROUND_QUEUE_WS = 2,
- BATTLEGROUND_QUEUE_AB = 3,
- BATTLEGROUND_QUEUE_EY = 4,
- BATTLEGROUND_QUEUE_2v2 = 5,
- BATTLEGROUND_QUEUE_3v3 = 6,
- BATTLEGROUND_QUEUE_5v5 = 7,
+ QUEUE_ID_MAX_LEVEL_19 = 0,
+ QUEUE_ID_MAX_LEVEL_29 = 1,
+ QUEUE_ID_MAX_LEVEL_39 = 2,
+ QUEUE_ID_MAX_LEVEL_49 = 3,
+ QUEUE_ID_MAX_LEVEL_59 = 4,
+ QUEUE_ID_MAX_LEVEL_69 = 5,
+ QUEUE_ID_MAX_LEVEL_79 = 6,
+ QUEUE_ID_MAX_LEVEL_80 = 7
};
+#define MAX_BATTLEGROUND_QUEUES 8
enum ScoreType
{
@@ -206,6 +216,25 @@ enum BattleGroundTeamId
BG_TEAM_ALLIANCE = 0,
BG_TEAM_HORDE = 1
};
+#define BG_TEAMS_COUNT 2
+
+enum BattleGroundStartingEvents
+{
+ BG_STARTING_EVENT_NONE = 0x00,
+ BG_STARTING_EVENT_1 = 0x01,
+ BG_STARTING_EVENT_2 = 0x02,
+ BG_STARTING_EVENT_3 = 0x04,
+ BG_STARTING_EVENT_4 = 0x08
+};
+
+enum BattleGroundStartingEventsIds
+{
+ BG_STARTING_EVENT_FIRST = 0,
+ BG_STARTING_EVENT_SECOND = 1,
+ BG_STARTING_EVENT_THIRD = 2,
+ BG_STARTING_EVENT_FOURTH = 3
+};
+#define BG_STARTING_EVENT_COUNT 4
enum BattleGroundJoinError
{
@@ -224,10 +253,11 @@ enum BattleGroundJoinError
class BattleGroundScore
{
public:
- BattleGroundScore() : KillingBlows(0), HonorableKills(0), Deaths(0), DamageDone(0), HealingDone(0), BonusHonor(0) {};
- virtual ~BattleGroundScore() //virtual destructor is used when deleting score from scores map
- {
- };
+ BattleGroundScore() : KillingBlows(0), Deaths(0), HonorableKills(0),
+ BonusHonor(0), DamageDone(0), HealingDone(0)
+ {}
+ virtual ~BattleGroundScore() {} //virtual destructor is used when deleting score from scores map
+
uint32 KillingBlows;
uint32 Deaths;
uint32 HonorableKills;
@@ -259,23 +289,23 @@ class BattleGround
BattleGround();
/*BattleGround(const BattleGround& bg);*/
virtual ~BattleGround();
- virtual void Update(time_t diff); // must be implemented in BG subclass of BG specific update code, but must in begginning call parent version
+ virtual void Update(uint32 diff); // must be implemented in BG subclass of BG specific update code, but must in begginning call parent version
virtual bool SetupBattleGround() // must be implemented in BG subclass
{
return true;
}
- void Reset(); // resets all common properties for battlegrounds
- virtual void ResetBGSubclass() // must be implemented in BG subclass
- {
- }
+ virtual void Reset(); // resets all common properties for battlegrounds, must be implemented and called in BG subclass
+ virtual void StartingEventCloseDoors() {}
+ virtual void StartingEventOpenDoors() {}
/* Battleground */
// Get methods:
char const* GetName() const { return m_Name; }
- uint32 GetTypeID() const { return m_TypeID; }
- uint32 GetQueueType() const { return m_Queue_type; }
+ BattleGroundTypeId GetTypeID() const { return m_TypeID; }
+ BGQueueIdBasedOnLevel GetQueueId() const { return m_QueueId; }
uint32 GetInstanceID() const { return m_InstanceID; }
- uint32 GetStatus() const { return m_Status; }
+ BattleGroundStatus GetStatus() const { return m_Status; }
+ uint32 GetClientInstanceID() const { return m_ClientInstanceID; }
uint32 GetStartTime() const { return m_StartTime; }
uint32 GetEndTime() const { return m_EndTime; }
uint32 GetLastResurrectTime() const { return m_LastResurrectTime; }
@@ -288,17 +318,25 @@ class BattleGround
uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayersPerTeam; }
uint32 GetMinPlayersPerTeam() const { return m_MinPlayersPerTeam; }
- int GetStartDelayTime() const { return m_StartDelayTime; }
+ int32 GetStartDelayTime() const { return m_StartDelayTime; }
uint8 GetArenaType() const { return m_ArenaType; }
uint8 GetWinner() const { return m_Winner; }
uint32 GetBattlemasterEntry() const;
+ uint32 GetBonusHonorFromKill(uint32 kills) const;
// Set methods:
void SetName(char const* Name) { m_Name = Name; }
- void SetTypeID(uint32 TypeID) { m_TypeID = TypeID; }
- void SetQueueType(uint32 ID) { m_Queue_type = ID; }
+ void SetTypeID(BattleGroundTypeId TypeID) { m_TypeID = TypeID; }
+ //here we can count minlevel and maxlevel for players
+ void SetQueueId(BGQueueIdBasedOnLevel ID)
+ {
+ m_QueueId = ID;
+ uint8 diff = (m_TypeID == BATTLEGROUND_AV) ? 1 : 0;
+ this->SetLevelRange((ID + 1) * 10 + diff, (ID + 2) * 10 - ((diff + 1) % 2));
+ }
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
- void SetStatus(uint32 Status) { m_Status = Status; }
+ void SetStatus(BattleGroundStatus Status) { m_Status = Status; }
+ void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; }
void SetStartTime(uint32 Time) { m_StartTime = Time; }
void SetEndTime(uint32 Time) { m_EndTime = Time; }
void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; }
@@ -323,12 +361,11 @@ class BattleGround
void IncreaseInvitedCount(uint32 team) { (team == ALLIANCE) ? ++m_InvitedAlliance : ++m_InvitedHorde; }
uint32 GetInvitedCount(uint32 team) const
{
- if( team == ALLIANCE )
+ if (team == ALLIANCE)
return m_InvitedAlliance;
else
return m_InvitedHorde;
}
- bool HasFreeSlotsForTeam(uint32 Team) const;
bool HasFreeSlots() const;
uint32 GetFreeSlotsForTeam(uint32 Team) const;
@@ -339,7 +376,6 @@ class BattleGround
typedef std::map<uint64, BattleGroundPlayer> BattleGroundPlayerMap;
BattleGroundPlayerMap const& GetPlayers() const { return m_Players; }
uint32 GetPlayersSize() const { return m_Players.size(); }
- uint32 GetRemovedPlayersSize() const { return m_RemovedPlayers.size(); }
std::map<uint64, BattleGroundScore*>::const_iterator GetPlayerScoresBegin() const { return m_PlayerScores.begin(); }
std::map<uint64, BattleGroundScore*>::const_iterator GetPlayerScoresEnd() const { return m_PlayerScores.end(); }
@@ -374,6 +410,10 @@ class BattleGround
void SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender = NULL, bool self = true);
void SendPacketToAll(WorldPacket *packet);
void YellToAll(Creature* creature, const char* text, uint32 language);
+
+ template<class Do>
+ void BroadcastWorker(Do& _do);
+
void PlaySoundToTeam(uint32 SoundID, uint32 TeamID);
void PlaySoundToAll(uint32 SoundID);
void CastSpellOnTeam(uint32 SpellID, uint32 TeamID);
@@ -381,24 +421,23 @@ class BattleGround
void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID);
void RewardMark(Player *plr,uint32 count);
void SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count);
- void RewardQuest(Player *plr);
+ void RewardItem(Player *plr, uint32 item_id, uint32 count);
+ void RewardQuestComplete(Player *plr);
+ void RewardSpellCast(Player *plr, uint32 spell_id);
void UpdateWorldState(uint32 Field, uint32 Value);
void UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source);
void EndBattleGround(uint32 winner);
void BlockMovement(Player *plr);
- void SendMessageToAll(char const* text);
- void SendMessageToAll(int32 entry);
+ void SendMessageToAll(int32 entry, ChatMsg type, Player const* source = NULL);
+ void PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ... );
+
+ // specialized version with 2 string id args
+ void SendMessage2ToAll(int32 entry, ChatMsg type, Player const* source, int32 strId1 = 0, int32 strId2 = 0);
/* Raid Group */
Group *GetBgRaid(uint32 TeamID) const { return TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE]; }
- void SetBgRaid(uint32 TeamID, Group *bg_raid)
- {
- Group* &old_raid = TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE];
- if(old_raid) old_raid->SetBattlegroundGroup(NULL);
- if(bg_raid) bg_raid->SetBattlegroundGroup(this);
- old_raid = bg_raid;
- }
+ void SetBgRaid(uint32 TeamID, Group *bg_raid);
virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
@@ -407,7 +446,7 @@ class BattleGround
uint32 GetAlivePlayersCountByTeam(uint32 Team) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases
void UpdatePlayersCountByTeam(uint32 Team, bool remove)
{
- if(remove)
+ if (remove)
--m_PlayersCount[GetTeamIndexByTeamId(Team)];
else
++m_PlayersCount[GetTeamIndexByTeamId(Team)];
@@ -415,9 +454,10 @@ class BattleGround
// used for rated arena battles
void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId) { m_ArenaTeamIds[GetTeamIndexByTeamId(Team)] = ArenaTeamId; }
- uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[GetTeamIndexByTeamId(Team)]; }
+ uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[GetTeamIndexByTeamId(Team)]; }
void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 RatingChange) { m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)] = RatingChange; }
- int32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)]; }
+ int32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)]; }
+ void CheckArenaWinConditions();
/* Triggers handle */
// must be implemented in BG subclass
@@ -427,16 +467,19 @@ class BattleGround
virtual void HandleKillUnit(Creature* /*unit*/, Player* /*killer*/);
/* Battleground events */
- /* these functions will return true event is possible, but false if player is bugger */
virtual void EventPlayerDroppedFlag(Player* /*player*/) {}
virtual void EventPlayerClickedOnFlag(Player* /*player*/, GameObject* /*target_obj*/) {}
virtual void EventPlayerCapturedFlag(Player* /*player*/) {}
+ void EventPlayerLoggedIn(Player* player, uint64 plr_guid);
+ void EventPlayerLoggedOut(Player* player);
/* Death related */
- virtual WorldSafeLocsEntry const* GetClosestGraveYard(float /*x*/, float /*y*/, float /*z*/, uint32 /*team*/) { return NULL; }
+ virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
virtual void AddPlayer(Player *plr); // must be implemented in BG subclass
+ void AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, uint32 team);
+
virtual void RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket);
// can be extended in in BG subclass
@@ -459,18 +502,22 @@ class BattleGround
void DoorOpen(uint32 type);
void DoorClose(uint32 type);
+ //to be removed
const char *GetTrinityString(int32 entry);
- virtual bool HandlePlayerUnderMap(Player * plr) {return false;}
+ virtual bool HandlePlayerUnderMap(Player * /*plr*/) { return false; }
// since arenas can be AvA or Hvh, we have to get the "temporary" team of a player
uint32 GetPlayerTeam(uint64 guid);
+ uint32 GetOtherTeam(uint32 teamId);
+ bool IsPlayerInBattleGround(uint64 guid);
void SetDeleteThis() {m_SetDeleteThis = true;}
protected:
//this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround
void EndNow();
+ void PlayerAddedToBGCheckIfBGIsRunning(Player* plr);
/* Scorekeeping */
// Player scores
@@ -484,29 +531,29 @@ class BattleGround
std::map<uint64, std::vector<uint64> > m_ReviveQueue;
/*
- this is important variable used for invitation messages
+ these are important variables used for starting messages
*/
uint8 m_Events;
+ BattleGroundStartTimeIntervals m_StartDelayTimes[BG_STARTING_EVENT_COUNT];
+ //this must be filled in constructors!
+ uint32 m_StartMessageIds[BG_STARTING_EVENT_COUNT];
bool m_BuffChange;
- uint32 m_score[2]; //array that keeps general team scores, used to determine who gets most marks when bg ends prematurely
BGHonorMode m_HonorMode;
private:
/* Battleground */
- uint32 m_TypeID; //Battleground type, defined in enum BattleGroundTypeId
+ BattleGroundTypeId m_TypeID;
uint32 m_InstanceID; //BattleGround Instance's GUID!
- uint32 m_Status;
+ BattleGroundStatus m_Status;
+ uint32 m_ClientInstanceID; //the instance-id which is sent to the client and without any other internal use
uint32 m_StartTime;
- uint32 m_EndTime;
+ int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself
uint32 m_LastResurrectTime;
- uint32 m_Queue_type;
+ BGQueueIdBasedOnLevel m_QueueId;
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
bool m_InBGFreeSlotQueue; // used to make sure that BG is only once inserted into the BattleGroundMgr.BGFreeSlotQueue[bgTypeId] deque
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
- // this variable is not used .... it can be found in many other ways... but to store it in BG object instance is useless
- //uint8 m_BattleGroundType; // 3=BG, 4=arena
- //instead of uint8 (in previous line) is bool used
bool m_IsArena;
uint8 m_Winner; // 0=alliance, 1=horde, 2=none
int32 m_StartDelayTime;
@@ -514,11 +561,10 @@ class BattleGround
bool m_PrematureCountDown;
uint32 m_PrematureCountDownTimer;
char const *m_Name;
-
/* Player lists */
std::vector<uint64> m_ResurrectQueue; // Player GUID
- std::map<uint64, uint8> m_RemovedPlayers; // uint8 is remove type (0 - bgqueue, 1 - bg, 2 - resurrect queue)
+ std::deque<uint64> m_OfflineQueue; // Player GUID
/* Invited counters are useful for player invitation to BG - do not allow, if BG is started to one faction to have 2 more players than another faction */
/* Invited counters will be changed only when removing already invited player from queue, removing player from battleground and inviting player to BG */
@@ -527,15 +573,15 @@ class BattleGround
uint32 m_InvitedHorde;
/* Raid Group */
- Group *m_BgRaids[2]; // 0 - alliance, 1 - horde
+ Group *m_BgRaids[BG_TEAMS_COUNT]; // 0 - alliance, 1 - horde
/* Players count by team */
- uint32 m_PlayersCount[2];
+ uint32 m_PlayersCount[BG_TEAMS_COUNT];
/* Arena team ids by team */
- uint32 m_ArenaTeamIds[2];
+ uint32 m_ArenaTeamIds[BG_TEAMS_COUNT];
- int32 m_ArenaTeamRatingChanges[2];
+ int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT];
/* Limits */
uint32 m_LevelMin;
@@ -545,12 +591,12 @@ class BattleGround
uint32 m_MinPlayersPerTeam;
uint32 m_MinPlayers;
- /* Location */
+ /* Start location */
uint32 m_MapId;
- float m_TeamStartLocX[2];
- float m_TeamStartLocY[2];
- float m_TeamStartLocZ[2];
- float m_TeamStartLocO[2];
+ float m_TeamStartLocX[BG_TEAMS_COUNT];
+ float m_TeamStartLocY[BG_TEAMS_COUNT];
+ float m_TeamStartLocZ[BG_TEAMS_COUNT];
+ float m_TeamStartLocO[BG_TEAMS_COUNT];
};
#endif
diff --git a/src/game/BattleGroundAA.cpp b/src/game/BattleGroundAA.cpp
index ad9720ad5fe..2aac2dde3eb 100644
--- a/src/game/BattleGroundAA.cpp
+++ b/src/game/BattleGroundAA.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,10 +21,20 @@
#include "Player.h"
#include "BattleGround.h"
#include "BattleGroundAA.h"
+#include "Language.h"
BattleGroundAA::BattleGroundAA()
{
+ m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
+ m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
+ m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
+ m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
+ //we must set messageIds
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
}
BattleGroundAA::~BattleGroundAA()
@@ -32,11 +42,19 @@ BattleGroundAA::~BattleGroundAA()
}
-void BattleGroundAA::Update(time_t diff)
+void BattleGroundAA::Update(uint32 diff)
{
BattleGround::Update(diff);
}
+void BattleGroundAA::StartingEventCloseDoors()
+{
+}
+
+void BattleGroundAA::StartingEventOpenDoors()
+{
+}
+
void BattleGroundAA::AddPlayer(Player *plr)
{
BattleGround::AddPlayer(plr);
diff --git a/src/game/BattleGroundAA.h b/src/game/BattleGroundAA.h
index 8a07831eb38..06793ea38e0 100644
--- a/src/game/BattleGroundAA.h
+++ b/src/game/BattleGroundAA.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,10 +37,13 @@ class BattleGroundAA : public BattleGround
public:
BattleGroundAA();
~BattleGroundAA();
- void Update(time_t diff);
+ void Update(uint32 diff);
/* inherited from BattlegroundClass */
virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
+
void RemovePlayer(Player *plr, uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
diff --git a/src/game/BattleGroundAB.cpp b/src/game/BattleGroundAB.cpp
index bbaef37152f..40f60960377 100644
--- a/src/game/BattleGroundAB.cpp
+++ b/src/game/BattleGroundAB.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,12 +23,11 @@
#include "BattleGround.h"
#include "BattleGroundAB.h"
#include "Creature.h"
-#include "Chat.h"
#include "ObjectMgr.h"
-#include "MapManager.h"
#include "Language.h"
#include "World.h"
#include "Util.h"
+#include "WorldPacket.h"
// these variables aren't used outside of this file, so declare them only here
uint32 BG_AB_HonorScoreTicks[BG_HONOR_MODE_NUM] = {
@@ -46,102 +45,31 @@ BattleGroundAB::BattleGroundAB()
m_BuffChange = true;
m_BgObjects.resize(BG_AB_OBJECT_MAX);
m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT);
+
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN;
}
BattleGroundAB::~BattleGroundAB()
{
}
-void BattleGroundAB::Update(time_t diff)
+void BattleGroundAB::Update(uint32 diff)
{
BattleGround::Update(diff);
- if( GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize() )
+ if (GetStatus() == STATUS_IN_PROGRESS)
{
- ModifyStartDelayTime(diff);
-
- if( !(m_Events & 0x01) )
- {
- m_Events |= 0x01;
-
- // setup here, only when at least one player has ported to the map
- if(!SetupBattleGround())
- {
- EndNow();
- return;
- }
-
- sLog.outDebug("Arathi Basin: entering state STATUS_WAIT_JOIN ...");
-
- // despawn banners, auras and buffs
- for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
- SpawnBGObject(obj, RESPAWN_ONE_DAY);
- for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
- SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
-
- // Starting doors
- SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
- SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
- DoorClose(BG_AB_OBJECT_GATE_A);
- DoorClose(BG_AB_OBJECT_GATE_H);
-
- // Starting base spirit guides
- _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
- _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
-
- SetStartDelayTime(START_DELAY0);
- }
- // After 1 minute, warning is signalled
- else if( GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04) )
- {
- m_Events |= 0x04;
- SendMessageToAll(GetTrinityString(LANG_BG_AB_ONEMINTOSTART));
- }
- // After 1,5 minute, warning is signalled
- else if( GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08) )
- {
- m_Events |= 0x08;
- SendMessageToAll(GetTrinityString(LANG_BG_AB_HALFMINTOSTART));
- }
- // After 2 minutes, gates OPEN ! x)
- else if( GetStartDelayTime() < 0 && !(m_Events & 0x10) )
- {
- m_Events |= 0x10;
- SendMessageToAll(GetTrinityString(LANG_BG_AB_STARTED));
-
- // spawn neutral banners
- for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
- SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
- for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
- {
- //randomly select buff to spawn
- uint8 buff = urand(0, 2);
- SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
- }
- DoorOpen(BG_AB_OBJECT_GATE_A);
- DoorOpen(BG_AB_OBJECT_GATE_H);
-
- PlaySoundToAll(SOUND_BG_START);
- if(sWorld.getConfig(CONFIG_BG_START_MUSIC))
- PlaySoundToAll(SOUND_BG_START_L70ETC); //MUSIC
- SetStatus(STATUS_IN_PROGRESS);
-
- for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if(Player* plr = objmgr.GetPlayer(itr->first))
- plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
- }
-
- }
- else if( GetStatus() == STATUS_IN_PROGRESS )
- {
- int team_points[2] = { 0, 0 };
+ int team_points[BG_TEAMS_COUNT] = { 0, 0 };
for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
{
// 3 sec delay to spawn new banner instead previous despawned one
- if( m_BannerTimers[node].timer )
+ if (m_BannerTimers[node].timer)
{
- if( m_BannerTimers[node].timer > diff )
+ if (m_BannerTimers[node].timer > diff)
m_BannerTimers[node].timer -= diff;
else
{
@@ -151,9 +79,9 @@ void BattleGroundAB::Update(time_t diff)
}
// 1-minute to occupy a node from contested state
- if( m_NodeTimers[node] )
+ if (m_NodeTimers[node])
{
- if( m_NodeTimers[node] > diff )
+ if (m_NodeTimers[node] > diff)
m_NodeTimers[node] -= diff;
else
{
@@ -169,72 +97,111 @@ void BattleGroundAB::Update(time_t diff)
_SendNodeUpdate(node);
_NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
// Message to chatlog
- char buf[256];
- uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
- sprintf(buf, GetTrinityString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetTrinityString(LANG_BG_AB_ALLY) : GetTrinityString(LANG_BG_AB_HORDE), _GetNodeName(node));
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL);
- SendPacketToAll(&data);
- PlaySoundToAll((teamIndex == 0) ? SOUND_NODE_CAPTURED_ALLIANCE : SOUND_NODE_CAPTURED_HORDE);
+
+ if (teamIndex == 0)
+ {
+ // FIXME: team and node names not localized
+ SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node));
+ PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
+ }
+ else
+ {
+ // FIXME: team and node names not localized
+ SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node));
+ PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
+ }
}
}
- for (int team = 0; team < 2; ++team)
- if( m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED )
+ for (int team = 0; team < BG_TEAMS_COUNT; ++team)
+ if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED)
++team_points[team];
}
// Accumulate points
- for (int team = 0; team < 2; ++team)
+ for (int team = 0; team < BG_TEAMS_COUNT; ++team)
{
int points = team_points[team];
- if( !points )
+ if (!points)
continue;
m_lastTick[team] += diff;
- if( m_lastTick[team] > BG_AB_TickIntervals[points] )
+ if (m_lastTick[team] > BG_AB_TickIntervals[points])
{
m_lastTick[team] -= BG_AB_TickIntervals[points];
m_TeamScores[team] += BG_AB_TickPoints[points];
- m_score[team] = m_TeamScores[team];
m_HonorScoreTics[team] += BG_AB_TickPoints[points];
m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
- if( m_ReputationScoreTics[team] >= BG_AB_ReputationScoreTicks[m_HonorMode] )
+ if (m_ReputationScoreTics[team] >= m_ReputationTics)
{
(team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE);
- m_ReputationScoreTics[team] -= BG_AB_ReputationScoreTicks[m_HonorMode];
+ m_ReputationScoreTics[team] -= m_ReputationTics;
}
- if( m_HonorScoreTics[team] >= BG_AB_HonorScoreTicks[m_HonorMode] )
+ if (m_HonorScoreTics[team] >= m_HonorTics)
{
- (team == BG_TEAM_ALLIANCE) ? RewardHonorToTeam(20, ALLIANCE) : RewardHonorToTeam(20, HORDE);
- m_HonorScoreTics[team] -= BG_AB_HonorScoreTicks[m_HonorMode];
+ RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE);
+ m_HonorScoreTics[team] -= m_HonorTics;
}
- if( !m_IsInformedNearVictory && m_TeamScores[team] > 1800 )
+ if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE)
{
- if( team == BG_TEAM_ALLIANCE )
- SendMessageToAll(GetTrinityString(LANG_BG_AB_A_NEAR_VICTORY));
+ if (team == BG_TEAM_ALLIANCE)
+ SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
else
- SendMessageToAll(GetTrinityString(LANG_BG_AB_H_NEAR_VICTORY));
- PlaySoundToAll(SOUND_NEAR_VICTORY);
+ SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY);
m_IsInformedNearVictory = true;
}
- if( m_TeamScores[team] > 2000 )
- m_TeamScores[team] = 2000;
- if( team == BG_TEAM_ALLIANCE )
+ if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE)
+ m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE;
+ if (team == BG_TEAM_ALLIANCE)
UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
- if( team == BG_TEAM_HORDE )
+ if (team == BG_TEAM_HORDE)
UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]);
}
}
// Test win condition
- if( m_TeamScores[BG_TEAM_ALLIANCE] >= 2000 )
+ if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE)
EndBattleGround(ALLIANCE);
- if( m_TeamScores[BG_TEAM_HORDE] >= 2000 )
+ if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE)
EndBattleGround(HORDE);
}
}
+void BattleGroundAB::StartingEventCloseDoors()
+{
+ // despawn banners, auras and buffs
+ for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
+ SpawnBGObject(obj, RESPAWN_ONE_DAY);
+ for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
+ SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
+
+ // Starting doors
+ DoorClose(BG_AB_OBJECT_GATE_A);
+ DoorClose(BG_AB_OBJECT_GATE_H);
+ SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
+ SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
+
+ // Starting base spirit guides
+ _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
+ _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
+}
+
+void BattleGroundAB::StartingEventOpenDoors()
+{
+ // spawn neutral banners
+ for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
+ SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
+ for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ {
+ //randomly select buff to spawn
+ uint8 buff = urand(0, 2);
+ SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
+ }
+ DoorOpen(BG_AB_OBJECT_GATE_A);
+ DoorOpen(BG_AB_OBJECT_GATE_H);
+}
+
void BattleGroundAB::AddPlayer(Player *plr)
{
BattleGround::AddPlayer(plr);
@@ -251,19 +218,19 @@ void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
{
- if( GetStatus() != STATUS_IN_PROGRESS )
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
switch(Trigger)
{
case 3948: // Arathi Basin Alliance Exit.
- if( Source->GetTeam() != ALLIANCE )
+ if (Source->GetTeam() != ALLIANCE)
Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
else
Source->LeaveBattleground();
break;
case 3949: // Arathi Basin Horde Exit.
- if( Source->GetTeam() != HORDE )
+ if (Source->GetTeam() != HORDE)
Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
else
Source->LeaveBattleground();
@@ -288,7 +255,7 @@ void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
{
// Just put it into the queue
- if( delay )
+ if (delay)
{
m_BannerTimers[node].timer = 2000;
m_BannerTimers[node].type = type;
@@ -301,7 +268,7 @@ void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool
SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
// handle aura with banner
- if( !type )
+ if (!type)
return;
obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
@@ -313,30 +280,25 @@ void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
SpawnBGObject(obj, RESPAWN_ONE_DAY);
// handle aura with banner
- if( !type )
+ if (!type)
return;
obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
SpawnBGObject(obj, RESPAWN_ONE_DAY);
}
-const char* BattleGroundAB::_GetNodeName(uint8 node)
+int32 BattleGroundAB::_GetNodeNameId(uint8 node)
{
switch (node)
{
- case BG_AB_NODE_STABLES:
- return GetTrinityString(LANG_BG_AB_NODE_STABLES);
- case BG_AB_NODE_BLACKSMITH:
- return GetTrinityString(LANG_BG_AB_NODE_BLACKSMITH);
- case BG_AB_NODE_FARM:
- return GetTrinityString(LANG_BG_AB_NODE_FARM);
- case BG_AB_NODE_LUMBER_MILL:
- return GetTrinityString(LANG_BG_AB_NODE_LUMBER_MILL);
- case BG_AB_NODE_GOLD_MINE:
- return GetTrinityString(LANG_BG_AB_NODE_GOLD_MINE);
+ case BG_AB_NODE_STABLES: return LANG_BG_AB_NODE_STABLES;
+ case BG_AB_NODE_BLACKSMITH: return LANG_BG_AB_NODE_BLACKSMITH;
+ case BG_AB_NODE_FARM: return LANG_BG_AB_NODE_FARM;
+ case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL;
+ case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE;
default:
ASSERT(0);
}
- return "";
+ return 0;
}
void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
@@ -355,9 +317,9 @@ void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
// How many bases each team owns
uint8 ally = 0, horde = 0;
for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
- if( m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED )
+ if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
++ally;
- else if( m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED )
+ else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
++horde;
data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally);
@@ -365,7 +327,7 @@ void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
// Team scores
data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
- data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_SCORE);
+ data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE);
data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]);
@@ -378,7 +340,7 @@ void BattleGroundAB::_SendNodeUpdate(uint8 node)
// Send node owner state update to refresh map icons on client
const uint8 plusArray[] = {0, 2, 3, 0, 1};
- if( m_prevNodes[node] )
+ if (m_prevNodes[node])
UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
else
UpdateWorldState(BG_AB_OP_NODEICONS[node], 0);
@@ -388,9 +350,9 @@ void BattleGroundAB::_SendNodeUpdate(uint8 node)
// How many bases each team owns
uint8 ally = 0, horde = 0;
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
- if( m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED )
+ if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
++ally;
- else if( m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED )
+ else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
++horde;
UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally);
@@ -399,46 +361,47 @@ void BattleGroundAB::_SendNodeUpdate(uint8 node)
void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
{
- if( !AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team) )
+ if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team))
sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
// SpawnBGCreature(node,RESPAWN_IMMEDIATELY);
uint8 capturedNodes = 0;
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
{
- if( m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
+ if (m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
++capturedNodes;
}
- if(capturedNodes >= 5)
+ if (capturedNodes >= 5)
CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team);
- if(capturedNodes >= 4)
+ if (capturedNodes >= 4)
CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team);
}
void BattleGroundAB::_NodeDeOccupied(uint8 node)
{
- if( node >= BG_AB_DYNAMIC_NODES_COUNT)
+ if (node >= BG_AB_DYNAMIC_NODES_COUNT)
return;
// Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
- if( !ghost_list.empty() )
+ if (!ghost_list.empty())
{
WorldSafeLocsEntry const *ClosestGrave = NULL;
- Player *plr;
- for (std::vector<uint64>::iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
+ for (std::vector<uint64>::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
{
- plr = objmgr.GetPlayer(*ghost_list.begin());
- if( !plr )
+ Player* plr = objmgr.GetPlayer(*itr);
+ if (!plr)
continue;
- if( !ClosestGrave )
- ClosestGrave = GetClosestGraveYard(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetTeam());
- plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
+ if (!ClosestGrave) // cache
+ ClosestGrave = GetClosestGraveYard(plr);
+
+ if (ClosestGrave)
+ plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
}
}
- if( m_BgCreatures[node] )
+ if (m_BgCreatures[node])
DelCreature(node);
// buff object isn't despawned
@@ -447,7 +410,7 @@ void BattleGroundAB::_NodeDeOccupied(uint8 node)
/* Invoked if a player used a banner as a gameobject */
void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/)
{
- if( GetStatus() != STATUS_IN_PROGRESS )
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
uint8 node = BG_AB_NODE_STABLES;
@@ -458,7 +421,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]);
}
- if( node == BG_AB_DYNAMIC_NODES_COUNT)
+ if (node == BG_AB_DYNAMIC_NODES_COUNT)
{
// this means our player isn't close to any of banners - maybe cheater ??
return;
@@ -466,18 +429,14 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam());
- // Message to chatlog
- char buf[256];
- uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
-
// Check if player really could use this banner, not cheated
- if( !(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2) )
+ if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2))
return;
source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
uint32 sound = 0;
// If node is neutral, change to contested
- if( m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL )
+ if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL)
{
UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
m_prevNodes[node] = m_Nodes[node];
@@ -488,14 +447,20 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
_CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
_SendNodeUpdate(node);
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
- sprintf(buf, GetTrinityString(LANG_BG_AB_NODE_CLAIMED), _GetNodeName(node), (teamIndex == 0) ? GetTrinityString(LANG_BG_AB_ALLY) : GetTrinityString(LANG_BG_AB_HORDE));
- sound = SOUND_NODE_CLAIMED;
+
+ // FIXME: team and node names not localized
+ if (teamIndex == 0)
+ SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY);
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE);
+
+ sound = BG_AB_SOUND_NODE_CLAIMED;
}
// If node is contested
- else if( (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED) )
+ else if ((m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED))
{
// If last state is NOT occupied, change node to enemy-contested
- if( m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED )
+ if (m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED)
{
UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
m_prevNodes[node] = m_Nodes[node];
@@ -506,7 +471,12 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
_CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
_SendNodeUpdate(node);
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
- sprintf(buf, GetTrinityString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node));
+
+ // FIXME: node names not localized
+ if (teamIndex == 0)
+ SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
}
// If contested, change back to occupied
else
@@ -521,9 +491,14 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
_SendNodeUpdate(node);
m_NodeTimers[node] = 0;
_NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
- sprintf(buf, GetTrinityString(LANG_BG_AB_NODE_DEFENDED), _GetNodeName(node));
+
+ // FIXME: node names not localized
+ if (teamIndex == 0)
+ SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
}
- sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
+ sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
}
// If node is occupied, change to enemy-contested
else
@@ -538,18 +513,24 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
_SendNodeUpdate(node);
_NodeDeOccupied(node);
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
- sprintf(buf, GetTrinityString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node));
- sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
+
+ // FIXME: node names not localized
+ if (teamIndex == 0)
+ SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
+
+ sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
}
- WorldPacket data;
- ChatHandler::FillMessageData(&data, source->GetSession(), type, LANG_UNIVERSAL, NULL, source->GetGUID(), buf, NULL);
- SendPacketToAll(&data);
+
// If node is occupied again, send "X has taken the Y" msg.
- if( m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED )
+ if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED)
{
- sprintf(buf, GetTrinityString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetTrinityString(LANG_BG_AB_ALLY) : GetTrinityString(LANG_BG_AB_HORDE), _GetNodeName(node));
- ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL);
- SendPacketToAll(&data);
+ // FIXME: team and node names not localized
+ if (teamIndex == 0)
+ SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node));
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node));
}
PlaySoundToAll(sound);
}
@@ -558,7 +539,7 @@ bool BattleGroundAB::SetupBattleGround()
{
for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
{
- if( !AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+ if (!AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|| !AddObject(BG_AB_OBJECT_BANNER_CONT_A + 8*i,BG_AB_OBJECTID_BANNER_CONT_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|| !AddObject(BG_AB_OBJECT_BANNER_CONT_H + 8*i,BG_AB_OBJECTID_BANNER_CONT_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
|| !AddObject(BG_AB_OBJECT_BANNER_ALLY + 8*i,BG_AB_OBJECTID_BANNER_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
@@ -572,7 +553,7 @@ bool BattleGroundAB::SetupBattleGround()
return false;
}
}
- if( !AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY)
+ if (!AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY)
|| !AddObject(BG_AB_OBJECT_GATE_H,BG_AB_OBJECTID_GATE_H,BG_AB_DoorPositions[1][0],BG_AB_DoorPositions[1][1],BG_AB_DoorPositions[1][2],BG_AB_DoorPositions[1][3],BG_AB_DoorPositions[1][4],BG_AB_DoorPositions[1][5],BG_AB_DoorPositions[1][6],BG_AB_DoorPositions[1][7],RESPAWN_IMMEDIATELY)
)
{
@@ -582,7 +563,7 @@ bool BattleGroundAB::SetupBattleGround()
//buffs
for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
{
- if( !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
+ if (!AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
|| !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
)
@@ -592,8 +573,11 @@ bool BattleGroundAB::SetupBattleGround()
return true;
}
-void BattleGroundAB::ResetBGSubclass()
+void BattleGroundAB::Reset()
{
+ //call parent's class reset
+ BattleGround::Reset();
+
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
m_TeamScores[BG_TEAM_HORDE] = 0;
m_lastTick[BG_TEAM_ALLIANCE] = 0;
@@ -603,6 +587,10 @@ void BattleGroundAB::ResetBGSubclass()
m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0;
m_ReputationScoreTics[BG_TEAM_HORDE] = 0;
m_IsInformedNearVictory = false;
+ bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call!
+ m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks;
+ m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks;
+
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
{
m_Nodes[i] = 0;
@@ -612,32 +600,49 @@ void BattleGroundAB::ResetBGSubclass()
}
for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i)
- if(m_BgCreatures[i])
+ if (m_BgCreatures[i])
DelCreature(i);
}
-WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(float x, float y, float /*z*/, uint32 team)
+void BattleGroundAB::EndBattleGround(uint32 winner)
{
- uint8 teamIndex = GetTeamIndexByTeamId(team);
+ //win reward
+ if (winner == ALLIANCE)
+ RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
+ if (winner == HORDE)
+ RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
+ //complete map_end rewards (even if no team wins)
+ RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
+ RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
+
+ BattleGround::EndBattleGround(winner);
+}
+
+WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
+{
+ uint8 teamIndex = GetTeamIndexByTeamId(player->GetTeam());
// Is there any occupied node for this team?
std::vector<uint8> nodes;
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
- if( m_Nodes[i] == teamIndex + 3 )
+ if (m_Nodes[i] == teamIndex + 3)
nodes.push_back(i);
WorldSafeLocsEntry const* good_entry = NULL;
// If so, select the closest node to place ghost on
- if( !nodes.empty() )
+ if (!nodes.empty())
{
+ float plr_x = player->GetPositionX();
+ float plr_y = player->GetPositionY();
+
float mindist = 999999.0f;
for (uint8 i = 0; i < nodes.size(); ++i)
{
WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] );
- if( !entry )
+ if (!entry)
continue;
- float dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y);
- if( mindist > dist )
+ float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y);
+ if (mindist > dist)
{
mindist = dist;
good_entry = entry;
@@ -646,7 +651,7 @@ WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(float x, float y,
nodes.clear();
}
// If not, place ghost on starting location
- if( !good_entry )
+ if (!good_entry)
good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] );
return good_entry;
diff --git a/src/game/BattleGroundAB.h b/src/game/BattleGroundAB.h
index 3fcea59c8e8..1c4a6d3b738 100644
--- a/src/game/BattleGroundAB.h
+++ b/src/game/BattleGroundAB.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -77,17 +77,17 @@ enum BG_AB_NodeObjectId
enum BG_AB_ObjectType
{
// for all 5 node points 8*5=40 objects
- BG_AB_OBJECT_BANNER_NEUTRAL = 0,
- BG_AB_OBJECT_BANNER_CONT_A = 1,
- BG_AB_OBJECT_BANNER_CONT_H = 2,
- BG_AB_OBJECT_BANNER_ALLY = 3,
- BG_AB_OBJECT_BANNER_HORDE = 4,
- BG_AB_OBJECT_AURA_ALLY = 5,
- BG_AB_OBJECT_AURA_HORDE = 6,
- BG_AB_OBJECT_AURA_CONTESTED = 7,
+ BG_AB_OBJECT_BANNER_NEUTRAL = 0,
+ BG_AB_OBJECT_BANNER_CONT_A = 1,
+ BG_AB_OBJECT_BANNER_CONT_H = 2,
+ BG_AB_OBJECT_BANNER_ALLY = 3,
+ BG_AB_OBJECT_BANNER_HORDE = 4,
+ BG_AB_OBJECT_AURA_ALLY = 5,
+ BG_AB_OBJECT_AURA_HORDE = 6,
+ BG_AB_OBJECT_AURA_CONTESTED = 7,
//gates
- BG_AB_OBJECT_GATE_A = 40,
- BG_AB_OBJECT_GATE_H = 41,
+ BG_AB_OBJECT_GATE_A = 40,
+ BG_AB_OBJECT_GATE_H = 41,
//buffs
BG_AB_OBJECT_SPEEDBUFF_STABLES = 42,
BG_AB_OBJECT_REGENBUFF_STABLES = 43,
@@ -130,8 +130,8 @@ enum BG_AB_Timers
enum BG_AB_Score
{
- BG_AB_MAX_TEAM_SCORE = 2000,
- BG_AB_WARNING_SCORE = 1800
+ BG_AB_WARNING_NEAR_VICTORY_SCORE = 1800,
+ BG_AB_MAX_TEAM_SCORE = 2000
};
/* do NOT change the order, else wrong behaviour */
@@ -164,14 +164,19 @@ enum BG_AB_NodeStatus
enum BG_AB_Sounds
{
- SOUND_NODE_CLAIMED = 8192,
- SOUND_NODE_CAPTURED_ALLIANCE = 8173,
- SOUND_NODE_CAPTURED_HORDE = 8213,
- SOUND_NODE_ASSAULTED_ALLIANCE = 8174,
- SOUND_NODE_ASSAULTED_HORDE = 8212,
- SOUND_NEAR_VICTORY = 8456
+ BG_AB_SOUND_NODE_CLAIMED = 8192,
+ BG_AB_SOUND_NODE_CAPTURED_ALLIANCE = 8173,
+ BG_AB_SOUND_NODE_CAPTURED_HORDE = 8213,
+ BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE = 8212,
+ BG_AB_SOUND_NODE_ASSAULTED_HORDE = 8174,
+ BG_AB_SOUND_NEAR_VICTORY = 8456
};
+#define BG_AB_NotABBGWeekendHonorTicks 330
+#define BG_AB_ABBGWeekendHonorTicks 200
+#define BG_AB_NotABBGWeekendReputationTicks 200
+#define BG_AB_ABBGWeekendReputationTicks 150
+
// x, y, z, o
const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] = {
{1166.785f, 1200.132f, -56.70859f, 0.9075713f}, // stables
@@ -238,13 +243,16 @@ class BattleGroundAB : public BattleGround
BattleGroundAB();
~BattleGroundAB();
- void Update(time_t diff);
+ void Update(uint32 diff);
void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
void RemovePlayer(Player *plr,uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
virtual bool SetupBattleGround();
- virtual void ResetBGSubclass();
- virtual WorldSafeLocsEntry const* GetClosestGraveYard(float x, float y, float z, uint32 team);
+ virtual void Reset();
+ void EndBattleGround(uint32 winner);
+ virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
/* Scorekeeping */
virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
@@ -265,7 +273,7 @@ class BattleGroundAB : public BattleGround
void _NodeOccupied(uint8 node,Team team);
void _NodeDeOccupied(uint8 node);
- const char* _GetNodeName(uint8 node);
+ int32 _GetNodeNameId(uint8 node);
/* Nodes info:
0: neutral
@@ -273,15 +281,19 @@ class BattleGroundAB : public BattleGround
2: horde contested
3: ally occupied
4: horde occupied */
- uint8 m_Nodes[BG_AB_DYNAMIC_NODES_COUNT];
- uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT];
- BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT];
- int32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT];
- uint32 m_TeamScores[2];
- uint32 m_lastTick[2];
- uint32 m_HonorScoreTics[2];
- uint32 m_ReputationScoreTics[2];
- bool m_IsInformedNearVictory;
+ uint8 m_Nodes[BG_AB_DYNAMIC_NODES_COUNT];
+ uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT];
+ BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT];
+ uint32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT];
+ uint32 m_TeamScores[BG_TEAMS_COUNT];
+ uint32 m_lastTick[BG_TEAMS_COUNT];
+ uint32 m_HonorScoreTics[BG_TEAMS_COUNT];
+ uint32 m_ReputationScoreTics[BG_TEAMS_COUNT];
+ bool m_IsInformedNearVictory;
+ uint32 m_HonorTics;
+ uint32 m_ReputationTics;
+
+
};
#endif
diff --git a/src/game/BattleGroundAV.cpp b/src/game/BattleGroundAV.cpp
index 6086d0be441..bc0b50d21f0 100644
--- a/src/game/BattleGroundAV.cpp
+++ b/src/game/BattleGroundAV.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,21 +21,23 @@
#include "Player.h"
#include "BattleGround.h"
#include "BattleGroundAV.h"
-#include "Creature.h"
-#include "Chat.h"
-#include "Object.h"
-#include "ObjectMgr.h"
-#include "ObjectAccessor.h"
-#include "MapManager.h"
#include "Language.h"
#include "SpellAuras.h"
#include "Formulas.h"
+#include "WorldPacket.h"
+#include "ObjectMgr.h"
+#include "GameObject.h"
BattleGroundAV::BattleGroundAV()
{
-
m_BgObjects.resize(BG_AV_OBJECT_MAX);
m_BgCreatures.resize(AV_CPLACE_MAX+AV_STATICCPLACE_MAX);
+
+ //TODO FIX ME!
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN;
}
BattleGroundAV::~BattleGroundAV()
@@ -229,8 +231,6 @@ void BattleGroundAV::UpdateScore(uint16 team, int16 points )
uint8 teamindex = GetTeamIndexByTeamId(team); //0=ally 1=horde
m_Team_Scores[teamindex] += points;
- m_score[teamindex] = m_Team_Scores[teamindex];
-
UpdateWorldState(((teamindex==BG_TEAM_HORDE)?AV_Horde_Score:AV_Alliance_Score), m_Team_Scores[teamindex]);
if( points < 0)
{
@@ -241,7 +241,7 @@ void BattleGroundAV::UpdateScore(uint16 team, int16 points )
}
else if(!m_IsInformedNearVictory[teamindex] && m_Team_Scores[teamindex] < SEND_MSG_NEAR_LOSE)
{
- SendMessageToAll(GetTrinityString((teamindex==BG_TEAM_HORDE)?LANG_BG_AV_H_NEAR_LOSE:LANG_BG_AV_A_NEAR_LOSE));
+ SendMessageToAll(teamindex==BG_TEAM_HORDE?LANG_BG_AV_H_NEAR_LOSE:LANG_BG_AV_A_NEAR_LOSE, teamindex==BG_TEAM_HORDE ? CHAT_MSG_BG_SYSTEM_HORDE : CHAT_MSG_BG_SYSTEM_ALLIANCE);
PlaySoundToAll(AV_SOUND_NEAR_VICTORY);
m_IsInformedNearVictory[teamindex] = true;
}
@@ -296,7 +296,7 @@ Creature* BattleGroundAV::AddAVCreature(uint16 cinfoid, uint16 type )
return creature;
}
-void BattleGroundAV::Update(time_t diff)
+void BattleGroundAV::Update(uint32 diff)
{
BattleGround::Update(diff);
if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
@@ -368,19 +368,19 @@ void BattleGroundAV::Update(time_t diff)
DoorClose(BG_AV_OBJECT_DOOR_A);
DoorClose(BG_AV_OBJECT_DOOR_H);
- SetStartDelayTime(START_DELAY0);
+ SetStartDelayTime(BG_START_DELAY_2M);
}
// After 1 minute, warning is signalled
- else if (GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04))
+ else if (GetStartDelayTime() <= BG_START_DELAY_1M && !(m_Events & 0x04))
{
m_Events |= 0x04;
- SendMessageToAll(GetTrinityString(LANG_BG_AV_ONEMINTOSTART));
+ SendMessageToAll(LANG_BG_AV_ONEMINTOSTART, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
// After 1,5 minute, warning is signalled
- else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08))
+ else if (GetStartDelayTime() <= BG_START_DELAY_1M + BG_START_DELAY_30S && !(m_Events & 0x08))
{
m_Events |= 0x08;
- SendMessageToAll(GetTrinityString(LANG_BG_AV_HALFMINTOSTART));
+ SendMessageToAll(LANG_BG_AV_HALFMINTOSTART, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
// After 2 minutes, gates OPEN ! x)
else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
@@ -389,7 +389,7 @@ void BattleGroundAV::Update(time_t diff)
UpdateWorldState(AV_SHOW_A_SCORE, 1);
m_Events |= 0x10;
- SendMessageToAll(GetTrinityString(LANG_BG_AV_STARTED));
+ SendMessageToAll(LANG_BG_AV_STARTED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(SOUND_BG_START);
SetStatus(STATUS_IN_PROGRESS);
@@ -467,6 +467,14 @@ void BattleGroundAV::Update(time_t diff)
}
}
+void BattleGroundAV::StartingEventCloseDoors()
+{
+}
+
+void BattleGroundAV::StartingEventOpenDoors()
+{
+}
+
void BattleGroundAV::AddPlayer(Player *plr)
{
BattleGround::AddPlayer(plr);
@@ -535,7 +543,7 @@ void BattleGroundAV::RemovePlayer(Player* plr,uint64 /*guid*/)
void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger)
{
// this is wrong way to implement these things. On official it done by gameobject spell cast.
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
uint32 SpellId = 0;
@@ -568,7 +576,7 @@ void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger)
break;
}
- if(SpellId)
+ if (SpellId)
Source->CastSpell(Source, SpellId, true);
}
diff --git a/src/game/BattleGroundAV.h b/src/game/BattleGroundAV.h
index 310635b995f..f9f4f46b0ae 100644
--- a/src/game/BattleGroundAV.h
+++ b/src/game/BattleGroundAV.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -1500,10 +1500,12 @@ class BattleGroundAV : public BattleGround
public:
BattleGroundAV();
~BattleGroundAV();
- void Update(time_t diff);
+ void Update(uint32 diff);
/* inherited from BattlegroundClass */
virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
void RemovePlayer(Player *plr,uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
diff --git a/src/game/BattleGroundBE.cpp b/src/game/BattleGroundBE.cpp
index a010bb166ac..f61ff697faa 100644
--- a/src/game/BattleGroundBE.cpp
+++ b/src/game/BattleGroundBE.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,14 +22,23 @@
#include "Player.h"
#include "BattleGround.h"
#include "BattleGroundBE.h"
-#include "Creature.h"
#include "ObjectMgr.h"
-#include "MapManager.h"
+#include "WorldPacket.h"
#include "Language.h"
BattleGroundBE::BattleGroundBE()
{
m_BgObjects.resize(BG_BE_OBJECT_MAX);
+
+ m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
+ m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
+ m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
+ m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
+ //we must set messageIds
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
}
BattleGroundBE::~BattleGroundBE()
@@ -37,77 +46,34 @@ BattleGroundBE::~BattleGroundBE()
}
-void BattleGroundBE::Update(time_t diff)
+void BattleGroundBE::Update(uint32 diff)
{
BattleGround::Update(diff);
- // after bg start we get there
- if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
- {
- ModifyStartDelayTime(diff);
-
- if (!(m_Events & 0x01))
- {
- m_Events |= 0x01;
- // setup here, only when at least one player has ported to the map
- if(!SetupBattleGround())
- {
- EndNow();
- return;
- }
- for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; i++)
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
-
- for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; i++)
- SpawnBGObject(i, RESPAWN_ONE_DAY);
-
- SetStartDelayTime(START_DELAY1);
- SendMessageToAll(LANG_ARENA_ONE_MINUTE);
- }
- // After 30 seconds, warning is signalled
- else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04))
- {
- m_Events |= 0x04;
- SendMessageToAll(LANG_ARENA_THIRTY_SECONDS);
- }
- // After 15 seconds, warning is signalled
- else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08))
- {
- m_Events |= 0x08;
- SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS);
- }
- // delay expired (1 minute)
- else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
- {
- m_Events |= 0x10;
-
- for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; i++)
- DoorOpen(i);
-
- for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; i++)
- SpawnBGObject(i, 60);
-
- SendMessageToAll(LANG_ARENA_BEGUN);
- SetStatus(STATUS_IN_PROGRESS);
- SetStartDelayTime(0);
-
- for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if(Player *plr = objmgr.GetPlayer(itr->first))
- plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
-
- if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
- EndBattleGround(HORDE);
- else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
- EndBattleGround(ALLIANCE);
- }
- }
-
- /*if(GetStatus() == STATUS_IN_PROGRESS)
+ /*if (GetStatus() == STATUS_IN_PROGRESS)
{
// update something
}*/
}
+void BattleGroundBE::StartingEventCloseDoors()
+{
+ for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; ++i)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+
+ for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i)
+ SpawnBGObject(i, RESPAWN_ONE_DAY);
+}
+
+void BattleGroundBE::StartingEventOpenDoors()
+{
+ for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; ++i)
+ DoorOpen(i);
+
+ for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i)
+ SpawnBGObject(i, 60);
+}
+
void BattleGroundBE::AddPlayer(Player *plr)
{
BattleGround::AddPlayer(plr);
@@ -122,24 +88,21 @@ void BattleGroundBE::AddPlayer(Player *plr)
void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/)
{
- if(GetStatus() == STATUS_WAIT_LEAVE)
+ if (GetStatus() == STATUS_WAIT_LEAVE)
return;
UpdateWorldState(0x9f1, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0x9f0, GetAlivePlayersCountByTeam(HORDE));
- if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
- EndBattleGround(HORDE);
- else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
- EndBattleGround(ALLIANCE);
+ CheckArenaWinConditions();
}
void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
- if(!killer)
+ if (!killer)
{
sLog.outError("Killer player not found");
return;
@@ -150,16 +113,7 @@ void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)
UpdateWorldState(0x9f1, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0x9f0, GetAlivePlayersCountByTeam(HORDE));
- if(!GetAlivePlayersCountByTeam(ALLIANCE))
- {
- // all opponents killed
- EndBattleGround(HORDE);
- }
- else if(!GetAlivePlayersCountByTeam(HORDE))
- {
- // all opponents killed
- EndBattleGround(ALLIANCE);
- }
+ CheckArenaWinConditions();
}
bool BattleGroundBE::HandlePlayerUnderMap(Player *player)
@@ -171,7 +125,7 @@ bool BattleGroundBE::HandlePlayerUnderMap(Player *player)
void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger)
{
// this is wrong way to implement these things. On official it done by gameobject spell cast.
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
//uint32 SpellId = 0;
@@ -190,7 +144,7 @@ void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger)
break;
}
- //if(buff_guid)
+ //if (buff_guid)
// HandleTriggerBuff(buff_guid,Source);
}
@@ -201,15 +155,16 @@ void BattleGroundBE::FillInitialWorldStates(WorldPacket &data)
data << uint32(0x9f3) << uint32(1); // 9
}
-void BattleGroundBE::ResetBGSubclass()
+void BattleGroundBE::Reset()
{
-
+ //call parent's class reset
+ BattleGround::Reset();
}
bool BattleGroundBE::SetupBattleGround()
{
// gates
- if( !AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
+ if (!AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_BE_OBJECT_DOOR_2, BG_BE_OBJECT_TYPE_DOOR_2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_BE_OBJECT_DOOR_3, BG_BE_OBJECT_TYPE_DOOR_3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_BE_OBJECT_DOOR_4, BG_BE_OBJECT_TYPE_DOOR_4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
diff --git a/src/game/BattleGroundBE.h b/src/game/BattleGroundBE.h
index 00f826f8207..e75e332f44f 100644
--- a/src/game/BattleGroundBE.h
+++ b/src/game/BattleGroundBE.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,15 +57,17 @@ class BattleGroundBE : public BattleGround
public:
BattleGroundBE();
~BattleGroundBE();
- void Update(time_t diff);
+ void Update(uint32 diff);
/* inherited from BattlegroundClass */
virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
void RemovePlayer(Player *plr, uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
- void ResetBGSubclass();
+ virtual void Reset();
virtual void FillInitialWorldStates(WorldPacket &d);
void HandleKillPlayer(Player* player, Player *killer);
bool HandlePlayerUnderMap(Player * plr);
diff --git a/src/game/BattleGroundDS.cpp b/src/game/BattleGroundDS.cpp
new file mode 100644
index 00000000000..78360b9b194
--- /dev/null
+++ b/src/game/BattleGroundDS.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Player.h"
+#include "BattleGround.h"
+#include "BattleGroundDS.h"
+#include "Language.h"
+
+BattleGroundDS::BattleGroundDS()
+{
+
+ m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
+ m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
+ m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
+ m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
+ //we must set messageIds
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
+}
+
+BattleGroundDS::~BattleGroundDS()
+{
+
+}
+
+void BattleGroundDS::Update(uint32 diff)
+{
+ BattleGround::Update(diff);
+}
+
+void BattleGroundDS::StartingEventCloseDoors()
+{
+}
+
+void BattleGroundDS::StartingEventOpenDoors()
+{
+}
+
+void BattleGroundDS::AddPlayer(Player *plr)
+{
+ BattleGround::AddPlayer(plr);
+ //create score and add it to map, default values are set in constructor
+ BattleGroundDSScore* sc = new BattleGroundDSScore;
+
+ m_PlayerScores[plr->GetGUID()] = sc;
+}
+
+void BattleGroundDS::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
+{
+}
+
+void BattleGroundDS::HandleKillPlayer(Player* player, Player* killer)
+{
+ BattleGround::HandleKillPlayer(player, killer);
+}
+
+void BattleGroundDS::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/)
+{
+}
+
+bool BattleGroundDS::SetupBattleGround()
+{
+ return true;
+}
diff --git a/src/game/BattleGroundDS.h b/src/game/BattleGroundDS.h
new file mode 100644
index 00000000000..44a6cfbd33a
--- /dev/null
+++ b/src/game/BattleGroundDS.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __BATTLEGROUNDDS_H
+#define __BATTLEGROUNDDS_H
+
+class BattleGround;
+
+class BattleGroundDSScore : public BattleGroundScore
+{
+ public:
+ BattleGroundDSScore() {};
+ virtual ~BattleGroundDSScore() {};
+ //TODO fix me
+};
+
+class BattleGroundDS : public BattleGround
+{
+ friend class BattleGroundMgr;
+
+ public:
+ BattleGroundDS();
+ ~BattleGroundDS();
+ void Update(uint32 diff);
+
+ /* inherited from BattlegroundClass */
+ virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
+
+ void RemovePlayer(Player *plr, uint64 guid);
+ void HandleAreaTrigger(Player *Source, uint32 Trigger);
+ bool SetupBattleGround();
+ void HandleKillPlayer(Player* player, Player *killer);
+};
+#endif
diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp
index ecf454d1cfe..7e6063a09d2 100644
--- a/src/game/BattleGroundEY.cpp
+++ b/src/game/BattleGroundEY.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,11 +23,10 @@
#include "BattleGround.h"
#include "BattleGroundEY.h"
#include "Creature.h"
-#include "Chat.h"
#include "ObjectMgr.h"
-#include "MapManager.h"
#include "Language.h"
-#include "World.h"
+#include "World.h" //music
+#include "WorldPacket.h"
#include "Util.h"
// these variables aren't used outside of this file, so declare them only here
@@ -45,85 +44,25 @@ BattleGroundEY::BattleGroundEY()
m_Points_Trigger[BLOOD_ELF] = TR_BLOOD_ELF_BUFF;
m_Points_Trigger[DRAENEI_RUINS] = TR_DRAENEI_RUINS_BUFF;
m_Points_Trigger[MAGE_TOWER] = TR_MAGE_TOWER_BUFF;
+
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN;
}
BattleGroundEY::~BattleGroundEY()
{
}
-void BattleGroundEY::Update(time_t diff)
+void BattleGroundEY::Update(uint32 diff)
{
BattleGround::Update(diff);
- // after bg start we get there (once)
- if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
- {
- ModifyStartDelayTime(diff);
-
- if(!(m_Events & 0x01))
- {
- m_Events |= 0x01;
-
- // setup here, only when at least one player has ported to the map
- if(!SetupBattleGround())
- {
- EndNow();
- return;
- }
-
- SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY);
- SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY);
-
-// SpawnBGCreature(EY_SPIRIT_MAIN_ALLIANCE, RESPAWN_IMMEDIATELY);
-// SpawnBGCreature(EY_SPIRIT_MAIN_HORDE, RESPAWN_IMMEDIATELY);
- for(uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER; i < BG_EY_OBJECT_MAX; ++i)
- SpawnBGObject(i, RESPAWN_ONE_DAY);
-
- SetStartDelayTime(START_DELAY0);
- }
- // After 1 minute, warning is signalled
- else if(GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04))
- {
- m_Events |= 0x04;
- SendMessageToAll(GetTrinityString(LANG_BG_EY_ONE_MINUTE));
- }
- // After 1,5 minute, warning is signalled
- else if(GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08))
- {
- m_Events |= 0x08;
- SendMessageToAll(GetTrinityString(LANG_BG_EY_HALF_MINUTE));
- }
- // After 2 minutes, gates OPEN ! x)
- else if(GetStartDelayTime() < 0 && !(m_Events & 0x10))
- {
- m_Events |= 0x10;
- SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_ONE_DAY);
- SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_ONE_DAY);
-
- for(uint32 i = BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER; i <= BG_EY_OBJECT_FLAG_NETHERSTORM; ++i)
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
- for(uint32 i = 0; i < EY_POINTS_MAX; ++i)
- {
- //randomly spawn buff
- uint8 buff = urand(0, 2);
- SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + buff + i * 3, RESPAWN_IMMEDIATELY);
- }
-
- SendMessageToAll(GetTrinityString(LANG_BG_EY_BEGIN));
-
- PlaySoundToAll(SOUND_BG_START);
- if(sWorld.getConfig(CONFIG_BG_START_MUSIC))
- PlaySoundToAll(SOUND_BG_START_L70ETC); //MUSIC
- SetStatus(STATUS_IN_PROGRESS);
- for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if(Player *plr = objmgr.GetPlayer(itr->first))
- plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
- }
- }
- else if(GetStatus() == STATUS_IN_PROGRESS)
+ if (GetStatus() == STATUS_IN_PROGRESS)
{
m_PointAddingTimer -= diff;
- if(m_PointAddingTimer <= 0)
+ if (m_PointAddingTimer <= 0)
{
m_PointAddingTimer = BG_EY_FPOINTS_TICK_TIME;
if (m_TeamPointsCount[BG_TEAM_ALLIANCE] > 0)
@@ -132,11 +71,11 @@ void BattleGroundEY::Update(time_t diff)
AddPoints(HORDE, BG_EY_TickPoints[m_TeamPointsCount[BG_TEAM_HORDE] - 1]);
}
- if(m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN || m_FlagState == BG_EY_FLAG_STATE_ON_GROUND)
+ if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN || m_FlagState == BG_EY_FLAG_STATE_ON_GROUND)
{
m_FlagsTimer -= diff;
- if(m_FlagsTimer < 0)
+ if (m_FlagsTimer < 0)
{
m_FlagsTimer = 0;
if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN)
@@ -147,7 +86,7 @@ void BattleGroundEY::Update(time_t diff)
}
m_TowerCapCheckTimer -= diff;
- if(m_TowerCapCheckTimer <= 0)
+ if (m_TowerCapCheckTimer <= 0)
{
//check if player joined point
/*I used this order of calls, because although we will check if one player is in gameobject's distance 2 times
@@ -162,16 +101,39 @@ void BattleGroundEY::Update(time_t diff)
}
}
+void BattleGroundEY::StartingEventCloseDoors()
+{
+ SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY);
+ SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY);
+
+ for(uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER; i < BG_EY_OBJECT_MAX; ++i)
+ SpawnBGObject(i, RESPAWN_ONE_DAY);
+}
+
+void BattleGroundEY::StartingEventOpenDoors()
+{
+ SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_ONE_DAY);
+
+ for(uint32 i = BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER; i <= BG_EY_OBJECT_FLAG_NETHERSTORM; ++i)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ for(uint32 i = 0; i < EY_POINTS_MAX; ++i)
+ {
+ //randomly spawn buff
+ uint8 buff = urand(0, 2);
+ SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + buff + i * 3, RESPAWN_IMMEDIATELY);
+ }
+}
+
void BattleGroundEY::AddPoints(uint32 Team, uint32 Points)
{
uint8 team_index = GetTeamIndexByTeamId(Team);
m_TeamScores[team_index] += Points;
- m_score[team_index] = m_TeamScores[team_index];
m_HonorScoreTics[team_index] += Points;
- if (m_HonorScoreTics[team_index] >= BG_EY_HonorScoreTicks[m_HonorMode])
+ if (m_HonorScoreTics[team_index] >= m_HonorTics )
{
- RewardHonorToTeam(20, Team);
- m_HonorScoreTics[team_index] -= BG_EY_HonorScoreTicks[m_HonorMode];
+ RewardHonorToTeam(GetBonusHonorFromKill(1), Team);
+ m_HonorScoreTics[team_index] -= m_HonorTics;
}
UpdateTeamScore(Team);
}
@@ -188,13 +150,13 @@ void BattleGroundEY::CheckSomeoneJoinedPoint()
while (j < m_PlayersNearPoint[EY_POINTS_MAX].size())
{
Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[EY_POINTS_MAX][j]);
- if(!plr)
+ if (!plr)
{
sLog.outError("BattleGroundEY: Player " I64FMTD " not found!", m_PlayersNearPoint[EY_POINTS_MAX][j]);
++j;
continue;
}
- if (plr->isAllowUseBattleGroundObject() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
+ if (plr->CanCaptureTowerPoint() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
{
//player joined point!
//show progress bar
@@ -222,7 +184,7 @@ void BattleGroundEY::CheckSomeoneLeftPoint()
for(uint8 i = 0; i < EY_POINTS_MAX; ++i)
{
obj = HashMapHolder<GameObject>::Find(m_BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REALVER + i]);
- if(obj)
+ if (obj)
{
uint8 j = 0;
while (j < m_PlayersNearPoint[i].size())
@@ -237,7 +199,7 @@ void BattleGroundEY::CheckSomeoneLeftPoint()
++j;
continue;
}
- if (!plr->isAllowUseBattleGroundObject() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
+ if (!plr->CanCaptureTowerPoint() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
//move player out of point (add him to players that are out of points
{
m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]);
@@ -305,21 +267,46 @@ void BattleGroundEY::UpdatePointStatuses()
void BattleGroundEY::UpdateTeamScore(uint32 Team)
{
uint32 score = GetTeamScore(Team);
- if(score >= EY_MAX_TEAM_SCORE)
+ //TODO there should be some sound played when one team is near victory!! - and define variables
+ /*if (!m_IsInformedNearVictory && score >= BG_EY_WARNING_NEAR_VICTORY_SCORE)
+ {
+ if (Team == ALLIANCE)
+ SendMessageToAll(LANG_BG_EY_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ else
+ SendMessageToAll(LANG_BG_EY_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ PlaySoundToAll(BG_EY_SOUND_NEAR_VICTORY);
+ m_IsInformedNearVictory = true;
+ }*/
+
+ if (score >= BG_EY_MAX_TEAM_SCORE)
{
- score = EY_MAX_TEAM_SCORE;
+ score = BG_EY_MAX_TEAM_SCORE;
EndBattleGround(Team);
}
- if(Team == ALLIANCE)
+ if (Team == ALLIANCE)
UpdateWorldState(EY_ALLIANCE_RESOURCES, score);
else
UpdateWorldState(EY_HORDE_RESOURCES, score);
}
+void BattleGroundEY::EndBattleGround(uint32 winner)
+{
+ //win reward
+ if (winner == ALLIANCE)
+ RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
+ if (winner == HORDE)
+ RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
+ //complete map reward
+ RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
+ RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
+
+ BattleGround::EndBattleGround(winner);
+}
+
void BattleGroundEY::UpdatePointsCount(uint32 Team)
{
- if(Team == ALLIANCE)
+ if (Team == ALLIANCE)
UpdateWorldState(EY_ALLIANCE_BASE, m_TeamPointsCount[BG_TEAM_ALLIANCE]);
else
UpdateWorldState(EY_HORDE_BASE, m_TeamPointsCount[BG_TEAM_HORDE]);
@@ -331,14 +318,14 @@ void BattleGroundEY::UpdatePointsIcons(uint32 Team, uint32 Point)
if (m_PointState[Point] == EY_POINT_UNDER_CONTROL)
{
UpdateWorldState(m_PointsIconStruct[Point].WorldStateControlIndex, 0);
- if(Team == ALLIANCE)
+ if (Team == ALLIANCE)
UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 1);
else
UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 1);
}
else
{
- if(Team == ALLIANCE)
+ if (Team == ALLIANCE)
UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 0);
else
UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 0);
@@ -362,16 +349,16 @@ void BattleGroundEY::RemovePlayer(Player *plr, uint64 guid)
// sometimes flag aura not removed :(
for (int j = EY_POINTS_MAX; j >= 0; --j)
{
- for(int i = 0; i < m_PlayersNearPoint[j].size(); ++i)
- if(m_PlayersNearPoint[j][i] == guid)
+ for(size_t i = 0; i < m_PlayersNearPoint[j].size(); ++i)
+ if (m_PlayersNearPoint[j][i] == guid)
m_PlayersNearPoint[j].erase(m_PlayersNearPoint[j].begin() + i);
}
- if(IsFlagPickedup())
+ if (IsFlagPickedup())
{
- if(m_FlagKeeper == guid)
+ if (m_FlagKeeper == guid)
{
- if(plr)
- this->EventPlayerDroppedFlag(plr);
+ if (plr)
+ EventPlayerDroppedFlag(plr);
else
{
SetFlagPicker(0);
@@ -383,7 +370,7 @@ void BattleGroundEY::RemovePlayer(Player *plr, uint64 guid)
void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
if(!Source->isAlive()) //hack code, must be removed later
@@ -392,23 +379,23 @@ void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger)
switch(Trigger)
{
case TR_BLOOD_ELF_POINT:
- if(m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[BLOOD_ELF] == Source->GetTeam())
- if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
+ if (m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[BLOOD_ELF] == Source->GetTeam())
+ if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_BLOOD_ELF);
break;
case TR_FEL_REALVER_POINT:
- if(m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[FEL_REALVER] == Source->GetTeam())
- if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
+ if (m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[FEL_REALVER] == Source->GetTeam())
+ if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_FEL_REALVER);
break;
case TR_MAGE_TOWER_POINT:
- if(m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[MAGE_TOWER] == Source->GetTeam())
- if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
+ if (m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[MAGE_TOWER] == Source->GetTeam())
+ if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_MAGE_TOWER);
break;
case TR_DRAENEI_RUINS_POINT:
- if(m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[DRAENEI_RUINS] == Source->GetTeam())
- if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
+ if (m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[DRAENEI_RUINS] == Source->GetTeam())
+ if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID())
EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_DRAENEI_RUINS);
break;
case 4512:
@@ -432,7 +419,7 @@ void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger)
bool BattleGroundEY::SetupBattleGround()
{
// doors
- if( !AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY)
+ if (!AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_EY_OBJECT_DOOR_H, BG_OBJECT_H_DOOR_EY_ENTRY, 1803.21f, 1539.49f, 1261.09f, 3.14159f, 0.173648f, 0, 0.984808f, 0, RESPAWN_IMMEDIATELY)
// banners (alliance)
|| !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY)
@@ -494,12 +481,12 @@ bool BattleGroundEY::SetupBattleGround()
for (int i = 0; i < EY_POINTS_MAX; ++i)
{
AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(m_Points_Trigger[i]);
- if( !at )
+ if (!at)
{
sLog.outError("BattleGroundEY: Unknown trigger: %u", m_Points_Trigger[i]);
continue;
}
- if ( !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3, Buff_Entries[0], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY)
+ if (!AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3, Buff_Entries[0], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY)
|| !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 1, Buff_Entries[1], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY)
|| !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 2, Buff_Entries[2], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY)
)
@@ -508,14 +495,14 @@ bool BattleGroundEY::SetupBattleGround()
WorldSafeLocsEntry const *sg = NULL;
sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_ALLIANCE);
- if( !sg || !AddSpiritGuide(EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE) )
+ if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE))
{
sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!");
return false;
}
sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_HORDE);
- if( !sg || !AddSpiritGuide(EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE) )
+ if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE))
{
sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!");
return false;
@@ -524,8 +511,11 @@ bool BattleGroundEY::SetupBattleGround()
return true;
}
-void BattleGroundEY::ResetBGSubclass()
+void BattleGroundEY::Reset()
{
+ //call parent's class reset
+ BattleGround::Reset();
+
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
m_TeamScores[BG_TEAM_HORDE] = 0;
m_TeamPointsCount[BG_TEAM_ALLIANCE] = 0;
@@ -538,6 +528,8 @@ void BattleGroundEY::ResetBGSubclass()
m_DroppedFlagGUID = 0;
m_PointAddingTimer = 0;
m_TowerCapCheckTimer = 0;
+ bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call!
+ m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks;
for(uint8 i = 0; i < EY_POINTS_MAX; ++i)
{
@@ -560,9 +552,9 @@ void BattleGroundEY::RespawnFlag(bool send_message)
m_FlagState = BG_EY_FLAG_STATE_ON_BASE;
SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_IMMEDIATELY);
- if(send_message)
+ if (send_message)
{
- SendMessageToAll(GetTrinityString(LANG_BG_EY_RESETED_FLAG));
+ SendMessageToAll(LANG_BG_EY_RESETED_FLAG, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_EY_SOUND_FLAG_RESET); // flags respawned sound...
}
@@ -574,7 +566,7 @@ void BattleGroundEY::RespawnFlagAfterDrop()
RespawnFlag(true);
GameObject *obj = HashMapHolder<GameObject>::Find(GetDroppedFlagGUID());
- if(obj)
+ if (obj)
obj->Delete();
else
sLog.outError("BattleGroundEY: Unknown dropped flag guid: %u",GUID_LOPART(GetDroppedFlagGUID()));
@@ -584,7 +576,7 @@ void BattleGroundEY::RespawnFlagAfterDrop()
void BattleGroundEY::HandleKillPlayer(Player *player, Player *killer)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
BattleGround::HandleKillPlayer(player, killer);
@@ -593,11 +585,11 @@ void BattleGroundEY::HandleKillPlayer(Player *player, Player *killer)
void BattleGroundEY::EventPlayerDroppedFlag(Player *Source)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
{
// if not running, do not cast things at the dropper player, neither send unnecessary messages
// just take off the aura
- if(IsFlagPickedup() && GetFlagPickerGUID() == Source->GetGUID())
+ if (IsFlagPickedup() && GetFlagPickerGUID() == Source->GetGUID())
{
SetFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
@@ -605,59 +597,41 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player *Source)
return;
}
- if(!IsFlagPickedup())
+ if (!IsFlagPickedup())
return;
- if(GetFlagPickerGUID() != Source->GetGUID())
+ if (GetFlagPickerGUID() != Source->GetGUID())
return;
- const char *message = "";
- uint8 type = 0;
-
SetFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
m_FlagState = BG_EY_FLAG_STATE_ON_GROUND;
m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME;
Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true);
Source->CastSpell(Source, BG_EY_PLAYER_DROPPED_FLAG_SPELL, true);
- if(Source->GetTeam() == ALLIANCE)
- {
- message = GetTrinityString(LANG_BG_EY_DROPPED_FLAG);
- type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
- }
- else
- {
- message = GetTrinityString(LANG_BG_EY_DROPPED_FLAG);
- type = CHAT_MSG_BG_SYSTEM_HORDE;
- }
//this does not work correctly :( (it should remove flag carrier name)
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
- WorldPacket data;
- ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
- SendPacketToAll(&data);
+ if (Source->GetTeam() == ALLIANCE)
+ SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL);
+ else
+ SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL);
}
void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj)
{
- if(GetStatus() != STATUS_IN_PROGRESS || this->IsFlagPickedup() || !Source->IsWithinDistInMap(target_obj, 10))
+ if (GetStatus() != STATUS_IN_PROGRESS || IsFlagPickedup() || !Source->IsWithinDistInMap(target_obj, 10))
return;
- const char *message;
- uint8 type = 0;
- message = GetTrinityString(LANG_BG_EY_HAS_TAKEN_FLAG);
-
- if(Source->GetTeam() == ALLIANCE)
+ if (Source->GetTeam() == ALLIANCE)
{
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_PLAYER);
- type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE);
}
else
{
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_PLAYER);
- type = CHAT_MSG_BG_SYSTEM_HORDE;
PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_HORDE);
}
@@ -671,29 +645,26 @@ void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target
Source->CastSpell(Source, BG_EY_NETHERSTORM_FLAG_SPELL, true);
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
- WorldPacket data;
- ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
- SendPacketToAll(&data);
+ if (Source->GetTeam() == ALLIANCE)
+ PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, Source->GetName());
+ else
+ PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL, Source->GetName());
}
void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
//Natural point
- uint8 message_type = 0;
- const char *message = "";
uint32 Team = m_PointOwnedByTeam[Point];
- if(!Team)
+ if (!Team)
return;
if (Team == ALLIANCE)
{
m_TeamPointsCount[BG_TEAM_ALLIANCE]--;
- message_type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
- message = GetTrinityString(m_LoosingPointTypes[Point].MessageIdAlliance);
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY);
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY);
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY);
@@ -701,8 +672,6 @@ void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point)
else
{
m_TeamPointsCount[BG_TEAM_HORDE]--;
- message_type = CHAT_MSG_BG_SYSTEM_HORDE;
- message = GetTrinityString(m_LoosingPointTypes[Point].MessageIdHorde);
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY);
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY);
SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY);
@@ -717,9 +686,10 @@ void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point)
m_PointOwnedByTeam[Point] = EY_POINT_NO_OWNER;
m_PointState[Point] = EY_POINT_NO_OWNER;
- WorldPacket data;
- ChatHandler::FillMessageData(&data, Source->GetSession(), message_type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
- SendPacketToAll(&data);
+ if (Team == ALLIANCE)
+ SendMessageToAll(m_LoosingPointTypes[Point].MessageIdAlliance,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source);
+ else
+ SendMessageToAll(m_LoosingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source);
UpdatePointsIcons(Team, Point);
UpdatePointsCount(Team);
@@ -727,11 +697,9 @@ void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point)
void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
- uint8 type = 0;
- const char *message = "";
uint32 Team = Source->GetTeam();
SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType, RESPAWN_ONE_DAY);
@@ -741,8 +709,6 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point)
if (Team == ALLIANCE)
{
m_TeamPointsCount[BG_TEAM_ALLIANCE]++;
- type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
- message = GetTrinityString(m_CapturingPointTypes[Point].MessageIdAlliance);
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY);
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY);
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY);
@@ -750,8 +716,6 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point)
else
{
m_TeamPointsCount[BG_TEAM_HORDE]++;
- type = CHAT_MSG_BG_SYSTEM_HORDE;
- message = GetTrinityString(m_CapturingPointTypes[Point].MessageIdHorde);
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY);
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY);
SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY);
@@ -762,16 +726,17 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point)
m_PointOwnedByTeam[Point] = Team;
m_PointState[Point] = EY_POINT_UNDER_CONTROL;
- WorldPacket data;
- ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
- SendPacketToAll(&data);
+ if (Team == ALLIANCE)
+ SendMessageToAll(m_CapturingPointTypes[Point].MessageIdAlliance,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source);
+ else
+ SendMessageToAll(m_CapturingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source);
- if(m_BgCreatures[Point])
+ if (m_BgCreatures[Point])
DelCreature(Point);
WorldSafeLocsEntry const *sg = NULL;
sg = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[Point].GraveYardId);
- if(!sg || !AddSpiritGuide(Point, sg->x, sg->y, sg->z, 3.124139f, Team))
+ if (!sg || !AddSpiritGuide(Point, sg->x, sg->y, sg->z, 3.124139f, Team))
sLog.outError("BatteGroundEY: Failed to spawn spirit guide! point: %u, team: %u, graveyard_id: %u",
Point, Team, m_CapturingPointTypes[Point].GraveYardId);
@@ -783,43 +748,38 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point)
void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType)
{
- if(GetStatus() != STATUS_IN_PROGRESS || this->GetFlagPickerGUID() != Source->GetGUID())
+ if (GetStatus() != STATUS_IN_PROGRESS || GetFlagPickerGUID() != Source->GetGUID())
return;
- uint8 type = 0;
- uint8 team_id = 0;
- const char *message = "";
-
SetFlagPicker(0);
m_FlagState = BG_EY_FLAG_STATE_WAIT_RESPAWN;
Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
- if(Source->GetTeam() == ALLIANCE)
- {
+
+ if (Source->GetTeam() == ALLIANCE)
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE);
- team_id = BG_TEAM_ALLIANCE;
- message = GetTrinityString(LANG_BG_EY_CAPTURED_FLAG_A);
- type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
- }
else
- {
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE);
- team_id = BG_TEAM_HORDE;
- message = GetTrinityString(LANG_BG_EY_CAPTURED_FLAG_H);
- type = CHAT_MSG_BG_SYSTEM_HORDE;
- }
SpawnBGObject(BgObjectType, RESPAWN_IMMEDIATELY);
m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME;
m_FlagCapturedBgObjectType = BgObjectType;
- WorldPacket data;
- ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
- SendPacketToAll(&data);
+ uint8 team_id = 0;
+ if (Source->GetTeam() == ALLIANCE)
+ {
+ team_id = BG_TEAM_ALLIANCE;
+ SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_A, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source);
+ }
+ else
+ {
+ team_id = BG_TEAM_HORDE;
+ SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_H, CHAT_MSG_BG_SYSTEM_HORDE, Source);
+ }
- if(m_TeamPointsCount[team_id] > 0)
+ if (m_TeamPointsCount[team_id] > 0)
AddPoints(Source->GetTeam(), BG_EY_FlagPoints[m_TeamPointsCount[team_id] - 1]);
UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1);
@@ -893,16 +853,16 @@ void BattleGroundEY::FillInitialWorldStates(WorldPacket& data)
data << uint32(0xc0d) << uint32(0x17b);
}
-WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(float x, float y, float z, uint32 team)
+WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(Player* player)
{
uint32 g_id = 0;
- if(team == ALLIANCE)
- g_id = EY_GRAVEYARD_MAIN_ALLIANCE;
- else if(team == HORDE)
- g_id = EY_GRAVEYARD_MAIN_HORDE;
- else
- return NULL;
+ switch(player->GetTeam())
+ {
+ case ALLIANCE: g_id = EY_GRAVEYARD_MAIN_ALLIANCE; break;
+ case HORDE: g_id = EY_GRAVEYARD_MAIN_HORDE; break;
+ default: return NULL;
+ }
float distance, nearestDistance;
@@ -911,26 +871,31 @@ WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(float x, float y,
entry = sWorldSafeLocsStore.LookupEntry(g_id);
nearestEntry = entry;
- if(!entry)
+ if (!entry)
{
sLog.outError("BattleGroundEY: Not found the main team graveyard. Graveyard system isn't working!");
return NULL;
}
- distance = (entry->x - x)*(entry->x - x) + (entry->y - y)*(entry->y - y) + (entry->z - z)*(entry->z - z);
+ float plr_x = player->GetPositionX();
+ float plr_y = player->GetPositionY();
+ float plr_z = player->GetPositionZ();
+
+
+ distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z);
nearestDistance = distance;
for(uint8 i = 0; i < EY_POINTS_MAX; ++i)
{
- if(m_PointOwnedByTeam[i]==team && m_PointState[i]==EY_POINT_UNDER_CONTROL)
+ if (m_PointOwnedByTeam[i]==player->GetTeam() && m_PointState[i]==EY_POINT_UNDER_CONTROL)
{
entry = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[i].GraveYardId);
- if(!entry)
+ if (!entry)
sLog.outError("BattleGroundEY: Not found graveyard: %u",m_CapturingPointTypes[i].GraveYardId);
else
{
- distance = (entry->x - x)*(entry->x - x) + (entry->y - y)*(entry->y - y) + (entry->z - z)*(entry->z - z);
- if(distance < nearestDistance)
+ distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z);
+ if (distance < nearestDistance)
{
nearestDistance = distance;
nearestEntry = entry;
diff --git a/src/game/BattleGroundEY.h b/src/game/BattleGroundEY.h
index 30ff2b3e584..a22d6ecc6db 100644
--- a/src/game/BattleGroundEY.h
+++ b/src/game/BattleGroundEY.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,9 +25,8 @@
class BattleGround;
-#define EY_MAX_TEAM_SCORE 2000
-#define BG_EY_FLAG_RESPAWN_TIME 10000 //10 seconds
-#define BG_EY_FPOINTS_TICK_TIME 2000 //2 seconds
+#define BG_EY_FLAG_RESPAWN_TIME (10*IN_MILISECONDS) //10 seconds
+#define BG_EY_FPOINTS_TICK_TIME (2*IN_MILISECONDS) //2 seconds
enum BG_EY_WorldStates
{
@@ -73,11 +72,11 @@ enum BG_EY_ProgressBarConsts
enum BG_EY_Sounds
{
//strange ids, but sure about them
- BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212,
- BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213,
- BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174,
- BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
- BG_EY_SOUND_FLAG_RESET = 8192
+ BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212,
+ BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213,
+ BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174,
+ BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
+ BG_EY_SOUND_FLAG_RESET = 8192
};
enum BG_EY_Spells
@@ -88,18 +87,18 @@ enum BG_EY_Spells
enum EYBattleGroundObjectEntry
{
- BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door
- BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door
- BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic)
- BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand)
- BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop)
- BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance)
- BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde)
- BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral)
- BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt
- BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt
- BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt
- BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt
+ BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door
+ BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door
+ BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic)
+ BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand)
+ BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop)
+ BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance)
+ BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde)
+ BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral)
+ BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt
+ BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt
+ BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt
+ BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt
};
enum EYBattleGroundPointsTrigger
@@ -131,7 +130,7 @@ enum EYBattleGroundPoints
DRAENEI_RUINS = 2,
MAGE_TOWER = 3,
- EY_PLAYERS_OUT_OF_POINTS = 4,
+ EY_PLAYERS_OUT_OF_POINTS = 4,
EY_POINTS_MAX = 4
};
@@ -212,6 +211,15 @@ enum EYBattleGroundObjectTypes
BG_EY_OBJECT_MAX = 59
};
+#define BG_EY_NotEYWeekendHonorTicks 330
+#define BG_EY_EYWeekendHonorTicks 200
+
+enum BG_EY_Score
+{
+ BG_EY_WARNING_NEAR_VICTORY_SCORE = 1800,
+ BG_EY_MAX_TEAM_SCORE = 2000
+};
+
enum BG_EY_FlagState
{
BG_EY_FLAG_STATE_ON_BASE = 0,
@@ -239,23 +247,32 @@ struct BattleGroundEYPointIconsStruct
struct BattleGroundEYLoosingPointStruct
{
BattleGroundEYLoosingPointStruct(uint32 _SpawnNeutralObjectType, uint32 _DespawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _DespawnObjectTypeHorde, uint32 _MessageIdHorde)
- : SpawnNeutralObjectType(_SpawnNeutralObjectType), DespawnObjectTypeAlliance(_DespawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance), DespawnObjectTypeHorde(_DespawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde) {}
+ : SpawnNeutralObjectType(_SpawnNeutralObjectType),
+ DespawnObjectTypeAlliance(_DespawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance),
+ DespawnObjectTypeHorde(_DespawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde)
+ {}
+
uint32 SpawnNeutralObjectType;
uint32 DespawnObjectTypeAlliance;
+ uint32 MessageIdAlliance;
uint32 DespawnObjectTypeHorde;
uint32 MessageIdHorde;
- uint32 MessageIdAlliance;
};
struct BattleGroundEYCapturingPointStruct
{
BattleGroundEYCapturingPointStruct(uint32 _DespawnNeutralObjectType, uint32 _SpawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _SpawnObjectTypeHorde, uint32 _MessageIdHorde, uint32 _GraveYardId)
- : DespawnNeutralObjectType(_DespawnNeutralObjectType), SpawnObjectTypeAlliance(_SpawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance), SpawnObjectTypeHorde(_SpawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde), GraveYardId(_GraveYardId) {}
+ : DespawnNeutralObjectType(_DespawnNeutralObjectType),
+ SpawnObjectTypeAlliance(_SpawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance),
+ SpawnObjectTypeHorde(_SpawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde),
+ GraveYardId(_GraveYardId)
+ {}
+
uint32 DespawnNeutralObjectType;
uint32 SpawnObjectTypeAlliance;
+ uint32 MessageIdAlliance;
uint32 SpawnObjectTypeHorde;
uint32 MessageIdHorde;
- uint32 MessageIdAlliance;
uint32 GraveYardId;
};
@@ -300,10 +317,12 @@ class BattleGroundEY : public BattleGround
public:
BattleGroundEY();
~BattleGroundEY();
- void Update(time_t diff);
+ void Update(uint32 diff);
/* inherited from BattlegroundClass */
virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
/* BG Flags */
uint64 GetFlagPickerGUID() const { return m_FlagKeeper; }
@@ -317,10 +336,11 @@ class BattleGroundEY : public BattleGround
void HandleBuffUse(uint64 const& buff_guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
void HandleKillPlayer(Player *player, Player *killer);
- virtual WorldSafeLocsEntry const* GetClosestGraveYard(float x, float y, float z, uint32 team);
+ virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
virtual bool SetupBattleGround();
- virtual void ResetBGSubclass();
+ virtual void Reset();
void UpdateTeamScore(uint32 Team);
+ void EndBattleGround(uint32 winner);
void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
virtual void FillInitialWorldStates(WorldPacket& data);
void SetDroppedFlagGUID(uint64 guid) { m_DroppedFlagGUID = guid;}
@@ -370,6 +390,7 @@ class BattleGroundEY : public BattleGround
uint8 m_CurrentPointPlayersCount[2*EY_POINTS_MAX];
int32 m_PointAddingTimer;
+ uint32 m_HonorTics;
};
#endif
diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp
index b1522c939f7..8464dc2e7e4 100644
--- a/src/game/BattleGroundHandler.cpp
+++ b/src/game/BattleGroundHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,7 +25,6 @@
#include "Player.h"
#include "ObjectMgr.h"
#include "WorldSession.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Object.h"
#include "Chat.h"
@@ -43,8 +42,8 @@ void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
recv_data >> guid;
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from: " I64FMT, guid);
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
+ Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
+ if (!unit)
return;
if(!unit->isBattleMaster()) // it's not battlemaster
@@ -53,9 +52,9 @@ void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
// Stop the npc if moving
unit->StopMoving();
- uint32 bgTypeId = objmgr.GetBattleMasterBG(unit->GetEntry());
+ BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(unit->GetEntry());
- if(!_player->GetBGAccessByLevel(bgTypeId))
+ if (!_player->GetBGAccessByLevel(bgTypeId))
{
// temp, must be gossip message...
SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR);
@@ -65,7 +64,7 @@ void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
SendBattlegGroundList(guid, bgTypeId);
}
-void WorldSession::SendBattlegGroundList( uint64 guid, uint32 bgTypeId )
+void WorldSession::SendBattlegGroundList( uint64 guid, BattleGroundTypeId bgTypeId )
{
WorldPacket data;
sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId);
@@ -77,57 +76,60 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
CHECK_PACKET_SIZE(recv_data, 8+4+4+1);
uint64 guid;
- uint32 bgTypeId;
+ uint32 bgTypeId_;
uint32 instanceId;
uint8 joinAsGroup;
+ bool isPremade = false;
Group * grp;
recv_data >> guid; // battlemaster guid
- recv_data >> bgTypeId; // battleground type id (DBC id)
+ recv_data >> bgTypeId_; // battleground type id (DBC id)
recv_data >> instanceId; // instance id, 0 if First Available selected
recv_data >> joinAsGroup; // join as group
- if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
{
- sLog.outError("Battleground: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());
+ sLog.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_,_player->GetGUIDLow());
return;
}
+ BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
+
sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT, guid);
// can do this, since it's battleground, not arena
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, 0);
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, 0);
// ignore if player is already in BG
- if(_player->InBattleGround())
+ if (_player->InBattleGround())
return;
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
+ Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
+ if (!unit)
return;
if(!unit->isBattleMaster()) // it's not battlemaster
return;
// get bg instance or bg template if instance not found
- BattleGround * bg = 0;
- if(instanceId)
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
+ BattleGround *bg = NULL;
+ if (instanceId)
+ bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId);
- if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
+ if (!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
{
sLog.outError("Battleground: no available bg / template found");
return;
}
// check queueing conditions
- if(!joinAsGroup)
+ if (!joinAsGroup)
{
// check Deserter debuff
- if( !_player->CanJoinToBattleground() )
+ if (!_player->CanJoinToBattleground())
{
WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
- data << (uint32) 0xFFFFFFFE;
+ data << uint32(0xFFFFFFFE);
_player->GetSession()->SendPacket(&data);
return;
}
@@ -136,16 +138,17 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
//player is already in this queue
return;
// check if has free queue slots
- if(!_player->HasFreeBattleGroundQueueId())
+ if (!_player->HasFreeBattleGroundQueueId())
return;
}
else
{
grp = _player->GetGroup();
// no group found, error
- if(!grp)
+ if (!grp)
return;
uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
+ isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam());
if (err != BG_JOIN_ERR_OK)
{
SendBattleGroundOrArenaJoinError(err);
@@ -155,10 +158,11 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
// if we're here, then the conditions to join a bg are met. We can proceed in joining.
// _player->GetGroup() was already checked, grp is already initialized
- if(joinAsGroup /* && _player->GetGroup()*/)
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0);
+ uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
+ if (joinAsGroup /* && _player->GetGroup()*/)
{
sLog.outDebug("Battleground: the following players are joining as group:");
- GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
@@ -171,7 +175,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
WorldPacket data;
// send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
member->GetSession()->SendPacket(&data);
sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
member->GetSession()->SendPacket(&data);
@@ -179,7 +183,6 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
}
sLog.outDebug("Battleground: group end");
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
}
else
{
@@ -190,14 +193,15 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
WorldPacket data;
// send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType);
SendPacket(&data);
- GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
}
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
+ if (!ginfo->IsInvitedToBGInstanceGUID)
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
}
void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
@@ -209,40 +213,62 @@ void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv
if(!bg) // can't be received if player not in battleground
return;
- if(bg->GetTypeID() == BATTLEGROUND_WS)
+ switch( bg->GetTypeID() )
{
- uint32 count1 = 0;
- uint32 count2 = 0;
+ case BATTLEGROUND_WS:
+ {
+ uint32 count1 = 0; //always constant zero?
+ uint32 count2 = 0; //count of next fields
- Player *ap = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
- if(ap) ++count2;
+ Player *ali_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
+ if (ali_plr)
+ ++count2;
- Player *hp = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
- if(hp) ++count2;
+ Player *horde_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
+ if (horde_plr)
+ ++count2;
- WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
- data << count1; // alliance flag holders count
- /*for(uint8 i = 0; i < count1; i++)
- {
- data << uint64(0); // guid
- data << (float)0; // x
- data << (float)0; // y
- }*/
- data << count2; // horde flag holders count
- if(ap)
- {
- data << (uint64)ap->GetGUID();
- data << (float)ap->GetPositionX();
- data << (float)ap->GetPositionY();
- }
- if(hp)
- {
- data << (uint64)hp->GetGUID();
- data << (float)hp->GetPositionX();
- data << (float)hp->GetPositionY();
- }
+ WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
+ data << count1; // alliance flag holders count - obsolete, now always 0
+ /*for(uint8 i = 0; i < count1; ++i)
+ {
+ data << uint64(0); // guid
+ data << (float)0; // x
+ data << (float)0; // y
+ }*/
+ data << count2; // horde flag holders count - obsolete, now count of next fields
+ if (ali_plr)
+ {
+ data << (uint64)ali_plr->GetGUID();
+ data << (float)ali_plr->GetPositionX();
+ data << (float)ali_plr->GetPositionY();
+ }
+ if (horde_plr)
+ {
+ data << (uint64)horde_plr->GetGUID();
+ data << (float)horde_plr->GetPositionX();
+ data << (float)horde_plr->GetPositionY();
+ }
- SendPacket(&data);
+ SendPacket(&data);
+ }
+ break;
+ case BATTLEGROUND_EY:
+ //TODO : fix me!
+ break;
+ case BATTLEGROUND_AB:
+ case BATTLEGROUND_AV:
+ {
+ //for other BG types - send default
+ WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4));
+ data << uint32(0);
+ data << uint32(0);
+ SendPacket(&data);
+ }
+ break;
+ default:
+ //maybe it is sent also in arena - do nothing
+ break;
}
}
@@ -251,7 +277,7 @@ void WorldSession::HandleBattleGroundPVPlogdataOpcode( WorldPacket & /*recv_data
sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
BattleGround *bg = _player->GetBattleGround();
- if(!bg)
+ if (!bg)
return;
WorldPacket data;
@@ -270,19 +296,15 @@ void WorldSession::HandleBattleGroundListOpcode( WorldPacket &recv_data )
uint32 bgTypeId;
recv_data >> bgTypeId; // id from DBC
- if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
+ if (!bl)
{
sLog.outError("Battleground: invalid bgtype received.");
return;
}
- BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
-
- if(!bl)
- return;
-
WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundListPacket(&data, _player->GetGUID(), _player, bgTypeId);
+ sBattleGroundMgr.BuildBattleGroundListPacket(&data, _player->GetGUID(), _player, BattleGroundTypeId(bgTypeId));
SendPacket( &data );
}
@@ -295,45 +317,39 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
uint8 type; // arenatype if arena
uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
uint32 instanceId;
- uint32 bgTypeId; // type id from dbc
+ uint32 bgTypeId_; // type id from dbc
uint16 unk; // 0x1F90 constant?
uint8 action; // enter battle 0x1, leave queue 0x0
- recv_data >> type >> unk2 >> bgTypeId >> unk >> action;
+ recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action;
- if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ if (!sBattlemasterListStore.LookupEntry(bgTypeId_))
{
- sLog.outError("Battleground: invalid bgtype received.");
+ sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_);
// update battleground slots for the player to fix his UI and sent data.
// this is a HACK, I don't know why the client starts sending invalid packets in the first place.
// it usually happens with extremely high latency (if debugging / stepping in the code for example)
- if(_player->InBattleGroundQueue())
+ if (_player->InBattleGroundQueue())
{
// update all queues, send invitation info if player is invited, queue info if queued
- for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
- uint32 queue_id = _player->GetBattleGroundQueueId(i);
- if(!queue_id)
- continue;
- BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
- // if the player is not in queue, contine
- if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
+ if (!bgQueueTypeId)
continue;
-
- // no group information, this should never happen
- if(!itrPlayerStatus->second.GroupInfo)
+ BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
+ BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
+ // if the player is not in queue, continue or no group information - this should never happen
+ if (itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo)
continue;
BattleGround * bg = NULL;
-
// get possibly needed data from groupinfo
- bgTypeId = itrPlayerStatus->second.GroupInfo->BgTypeId;
uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
- uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated;
uint8 status = 0;
-
- if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
+ if (!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
{
// not invited to bg, get template
bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
@@ -342,130 +358,124 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
else
{
// get the bg we're invited to
- BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID);
+ bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
status = STATUS_WAIT_JOIN;
}
- // if bg not found, then continue
- if(!bg)
- continue;
-
- // don't invite if already in the instance
- if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())
+ // if bg not found, then continue, don't invite if already in the instance
+ if (!bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()))
continue;
// re - invite player with proper data
WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team?itrPlayerStatus->second.GroupInfo->Team:_player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype);
SendPacket(&data);
}
}
return;
}
- uint32 bgQueueTypeId = 0;
- // get the bg what we were invited to
- BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus;
- bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId,type);
- itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
-
- if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ //get GroupQueueInfo from BattleGroundQueue
+ BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_);
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
+ BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
+ if (itrPlayerStatus == qpMap.end())
{
sLog.outError("Battleground: itrplayerstatus not found.");
return;
}
- instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
- // if action == 1, then instanceId is _required_
- if(!instanceId && action == 1)
+ instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
+ // if action == 1, then instanceId is required
+ if (!instanceId && action == 1)
{
sLog.outError("Battleground: instance not found.");
return;
}
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
+ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId);
// bg template might and must be used in case of leaving queue, when instance is not created yet
- if(!bg && action == 0)
+ if (!bg && action == 0)
bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
-
- if(!bg)
+ if (!bg)
{
- sLog.outError("Battleground: bg not found.");
+ sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId);
return;
}
- bgTypeId = bg->GetTypeID();
-
- if(_player->InBattleGroundQueue())
+ if (_player->InBattleGroundQueue())
{
- uint32 queueSlot = 0;
- uint32 team = 0;
- uint32 arenatype = 0;
- uint32 israted = 0;
- uint32 rating = 0;
- uint32 opponentsRating = 0;
- // get the team info from the queue
- BattleGroundQueue::QueuedPlayersMap::iterator pitr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
- if(pitr !=sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end()
- && pitr->second.GroupInfo )
- {
- team = pitr->second.GroupInfo->Team;
- arenatype = pitr->second.GroupInfo->ArenaType;
- israted = pitr->second.GroupInfo->IsRated;
- rating = pitr->second.GroupInfo->ArenaTeamRating;
- opponentsRating = pitr->second.GroupInfo->OpponentsTeamRating;
- }
- else
+ //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function!
+ uint32 team = itrPlayerStatus->second.GroupInfo->Team;
+ uint32 arenaType = itrPlayerStatus->second.GroupInfo->ArenaType;
+ uint32 isRated = itrPlayerStatus->second.GroupInfo->IsRated;
+ uint32 rating = itrPlayerStatus->second.GroupInfo->ArenaTeamRating;
+ uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating;
+
+ //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
+ if (action == 1 && arenaType == 0)
{
- sLog.outError("Battleground: Invalid player queue info!");
- return;
+ //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
+ if (!_player->CanJoinToBattleground())
+ {
+ //send bg command result to show nice message
+ WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
+ data2 << uint32(0xFFFFFFFE);
+ _player->GetSession()->SendPacket(&data2);
+ action = 0;
+ sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
+ }
+ //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue
+ if (_player->getLevel() > bg->GetMaxLevel())
+ {
+ sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
+ action = 0;
+ }
}
+ uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
WorldPacket data;
- switch(action)
+ switch( action )
{
- case 1: // port to battleground
- if(!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
- return; // cheating?
+ case 1: // port to battleground
+ if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
+ return; // cheating?
// resurrect the player
- if(!_player->isAlive())
+ if (!_player->isAlive())
{
_player->ResurrectPlayer(1.0f);
_player->SpawnCorpseBones();
}
// stop taxi flight at port
- if(_player->isInFlight())
+ if (_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
_player->m_taxi.ClearTaxiDestinations();
}
- _player->RemoveFromGroup();
- queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
+
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
_player->GetSession()->SendPacket(&data);
// remove battleground queue status from BGmgr
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
- // also this required to prevent stuck at old battleground after SetBattleGroundId set to new
- if( BattleGround *currentBg = _player->GetBattleGround() )
+ // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new
+ if (BattleGround *currentBg = _player->GetBattleGround())
currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
// set the destination instance id
- _player->SetBattleGroundId(bg->GetInstanceID());
+ _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId);
// set the destination team
_player->SetBGTeam(team);
// bg->HandleBeforeTeleportToBattleGround(_player);
- sBattleGroundMgr.SendToBattleGround(_player, instanceId);
+ sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId);
// add only in HandleMoveWorldPortAck()
// bg->AddPlayer(_player,team);
- sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId);
+ sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId);
break;
- case 0: // leave queue
- queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
- /*
- if player leaves rated arena match before match start, it is counted as he played but he lost
- */
- if (israted)
+ case 0: // leave queue
+ // if player leaves rated arena match before match start, it is counted as he played but he lost
+ if (isRated)
{
ArenaTeam * at = objmgr.GetArenaTeamById(team);
if (at)
@@ -475,13 +485,14 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
at->SaveToDB();
}
}
- _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
+ _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
- // player left queue, we should update it, maybe now his group fits in
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(),arenatype,israted,rating);
+ // player left queue, we should update it - do not update Arena Queue
+ if (!arenaType)
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenaType, isRated, rating);
SendPacket(&data);
- sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetTypeID(),bgQueueTypeId);
+ sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId);
break;
default:
sLog.outError("Battleground port: unknown action %u", action);
@@ -506,9 +517,9 @@ void WorldSession::HandleBattleGroundLeaveOpcode( WorldPacket & /*recv_data*/ )
// return;
// not allow leave battleground in combat
- if(_player->isInCombat())
- if(BattleGround* bg = _player->GetBattleGround())
- if(bg->GetStatus() != STATUS_WAIT_LEAVE)
+ if (_player->isInCombat())
+ if (BattleGround* bg = _player->GetBattleGround())
+ if (bg->GetStatus() != STATUS_WAIT_LEAVE)
return;
_player->LeaveBattleground();
@@ -520,81 +531,56 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
sLog.outDebug( "WORLD: Battleground status" );
WorldPacket data;
-
- // TODO: we must put player back to battleground in case disconnect (< 5 minutes offline time) or teleport player on login(!) from battleground map to entry point
- if(_player->InBattleGround())
+ // we must update all queues here
+ BattleGround *bg = NULL;
+ for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
- BattleGround *bg = _player->GetBattleGround();
- if(bg)
+ BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i);
+ if (!bgQueueTypeId)
+ continue;
+ BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId);
+ uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId);
+ if (bgTypeId == _player->GetBattleGroundTypeId())
{
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
- uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
- if((bg->GetStatus() <= STATUS_IN_PROGRESS))
+ bg = _player->GetBattleGround();
+ //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
+ //so i must use bg pointer to get that information
+ if (bg && bg->GetArenaType() == arenaType)
{
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
+ // this line is checked, i only don't know if GetStartTime is changing itself after bg end!
+ // send status in BattleGround
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType);
SendPacket(&data);
- }
- for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- {
- uint32 queue_id = _player->GetBattleGroundQueueId(i); // battlegroundqueueid stores the type id, not the instance id, so this is definitely wrong
- uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);
- uint8 isRated = 0;
- if (i == queueSlot || !queue_id) // we need to get the instance ids
- continue;
- BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
- if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
- continue;
- if(itrPlayerStatus->second.GroupInfo)
- {
- arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
- isRated = itrPlayerStatus->second.GroupInfo->IsRated;
- }
- BattleGround *bg2 = sBattleGroundMgr.GetBattleGroundTemplate(sBattleGroundMgr.BGTemplateId(queue_id)); // try this
- if(bg2)
- {
- //in this call is small bug, this call should be filled by player's waiting time in queue
- //this call nulls all timers for client :
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0,arenatype,isRated);
- SendPacket(&data);
- }
+ continue;
}
}
- }
- else
- {
- // we should update all queues? .. i'm not sure if this code is correct
- for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ //we are sending update to player about queue - he can be invited there!
+ //get GroupQueueInfo for queue status
+ BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
+ if (itrPlayerStatus == qpMap.end())
+ continue;
+ if (itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
{
- uint32 queue_id = _player->GetBattleGroundQueueId(i);
- if(!queue_id)
- continue;
- uint32 bgTypeId = sBattleGroundMgr.BGTemplateId(queue_id);
- uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);
- uint8 isRated = 0;
- BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
- BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
- if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId);
+ if (!bg)
continue;
- if(itrPlayerStatus->second.GroupInfo)
- {
- arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
- isRated = itrPlayerStatus->second.GroupInfo->IsRated;
- }
- if(bg && queue_id)
- {
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
- SendPacket(&data);
- }
+ uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime);
+ // send status invited to BattleGround
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType);
+ SendPacket(&data);
}
- }
-/* else // not sure if it needed...
- {
- for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ else
{
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0);
+ bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+ if (!bg)
+ continue;
+ uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
+ // send status in BattleGround Queue
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(itrPlayerStatus->second.GroupInfo->JoinTime, getMSTime()), arenaType);
SendPacket(&data);
}
- }*/
+ }
}
void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
@@ -604,14 +590,14 @@ void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
CHECK_PACKET_SIZE(recv_data, 8);
BattleGround *bg = _player->GetBattleGround();
- if(!bg)
+ if (!bg)
return;
uint64 guid;
recv_data >> guid;
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
+ Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
+ if (!unit)
return;
if(!unit->isSpiritService()) // it's not spirit service
@@ -627,14 +613,14 @@ void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
CHECK_PACKET_SIZE(recv_data, 8);
BattleGround *bg = _player->GetBattleGround();
- if(!bg)
+ if (!bg)
return;
uint64 guid;
recv_data >> guid;
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
+ Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
+ if (!unit)
return;
if(!unit->isSpiritService()) // it's not spirit service
@@ -651,19 +637,19 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
recv_data.hexlike();
// ignore if we already in BG or BG queue
- if(_player->InBattleGround())
+ if (_player->InBattleGround())
return;
uint64 guid; // arena Battlemaster guid
- uint8 type; // 2v2, 3v3 or 5v5
+ uint8 arenaslot; // 2v2, 3v3 or 5v5
uint8 asGroup; // asGroup
uint8 isRated; // isRated
Group * grp;
- recv_data >> guid >> type >> asGroup >> isRated;
+ recv_data >> guid >> arenaslot >> asGroup >> isRated;
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
+ Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
+ if (!unit)
return;
if(!unit->isBattleMaster()) // it's not battle master
@@ -672,7 +658,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
uint8 arenatype = 0;
uint32 arenaRating = 0;
- switch(type)
+ switch(arenaslot)
{
case 0:
arenatype = ARENA_TYPE_2v2;
@@ -684,39 +670,39 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
arenatype = ARENA_TYPE_5v5;
break;
default:
- sLog.outError("Unknown arena type %u at HandleBattleGroundArenaJoin()", type);
+ sLog.outError("Unknown arena slot %u at HandleBattleGroundArenaJoin()", arenaslot);
return;
}
//check existance
BattleGround* bg = NULL;
- if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) )
+ if (!(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)))
{
sLog.outError("Battleground: template bg (all arenas) not found");
return;
}
- uint8 bgTypeId = bg->GetTypeID();
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
+ BattleGroundTypeId bgTypeId = bg->GetTypeID();
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype);
// check queueing conditions
- if(!asGroup)
+ if (!asGroup)
{
// check if already in queue
if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
//player is already in this queue
return;
// check if has free queue slots
- if(!_player->HasFreeBattleGroundQueueId())
+ if (!_player->HasFreeBattleGroundQueueId())
return;
}
else
{
grp = _player->GetGroup();
// no group found, error
- if(!grp)
+ if (!grp)
return;
- uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, type);
+ uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot);
if (err != BG_JOIN_ERR_OK)
{
SendBattleGroundOrArenaJoinError(err);
@@ -726,12 +712,12 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
uint32 ateamId = 0;
- if(isRated)
+ if (isRated)
{
- ateamId = _player->GetArenaTeamId(type);
+ ateamId = _player->GetArenaTeamId(arenaslot);
// check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
- if(!at)
+ if (!at)
{
_player->GetSession()->SendNotInArenaTeamPacket(arenatype);
return;
@@ -746,23 +732,24 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
Player *member = itr->getSource();
// calc avg personal rating
- avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (type*6) + 5);
+ avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot*6) + 5);
}
- if( arenatype )
+ if (arenatype)
avg_pers_rating /= arenatype;
// if avg personal rating is more than 150 points below the teams rating, the team will be queued against an opponent matching or similar to the average personal rating
- if(avg_pers_rating + 150 < arenaRating)
+ if (avg_pers_rating + 150 < arenaRating)
arenaRating = avg_pers_rating;
}
- if(asGroup)
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId);
+ uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId));
+ if (asGroup)
{
- GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating, ateamId);
sLog.outDebug("Battleground: arena join as group start");
- if(isRated)
- sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(type),_player->GetName(),arenaRating,arenatype);
+ if (isRated)
+ sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype);
for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
@@ -775,7 +762,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
WorldPacket data;
// send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
member->GetSession()->SendPacket(&data);
sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
member->GetSession()->SendPacket(&data);
@@ -783,7 +770,8 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
}
sLog.outDebug("Battleground: arena join as group end");
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
+ if (isRated)
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true);
}
else
{
@@ -794,13 +782,12 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
WorldPacket data;
// send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype);
SendPacket(&data);
- GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating);
sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
}
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating);
}
void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data )
@@ -811,7 +798,7 @@ void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data )
recv_data >> playerGuid;
Player *reportedPlayer = objmgr.GetPlayer(playerGuid);
- if(!reportedPlayer)
+ if (!reportedPlayer)
{
sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: player not found");
return;
diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp
index 54d2538068d..f0f801c3060 100644
--- a/src/game/BattleGroundMgr.cpp
+++ b/src/game/BattleGroundMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
*/
#include "Common.h"
+#include "SharedDefines.h"
#include "Player.h"
#include "BattleGroundMgr.h"
#include "BattleGroundAV.h"
@@ -29,16 +30,21 @@
#include "BattleGroundBE.h"
#include "BattleGroundAA.h"
#include "BattleGroundRL.h"
-#include "SharedDefines.h"
-#include "Policies/SingletonImp.h"
+#include "BattleGroundSA.h"
+#include "BattleGroundDS.h"
+#include "BattleGroundRV.h"
#include "MapManager.h"
#include "Map.h"
#include "MapInstanced.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
-#include "World.h"
#include "Chat.h"
#include "ArenaTeam.h"
+#include "World.h"
+#include "WorldPacket.h"
+#include "ProgressBar.h"
+
+#include "Policies/SingletonImp.h"
INSTANTIATE_SINGLETON_1( BattleGroundMgr );
@@ -48,96 +54,103 @@ INSTANTIATE_SINGLETON_1( BattleGroundMgr );
BattleGroundQueue::BattleGroundQueue()
{
- //queues are empty, we don't have to call clear()
-/* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
{
- //m_QueuedPlayers[i].Horde = 0;
- //m_QueuedPlayers[i].Alliance = 0;
- //m_QueuedPlayers[i].AverageTime = 0;
- }*/
-}
-
-BattleGroundQueue::~BattleGroundQueue()
-{
- for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
- {
- m_QueuedPlayers[i].clear();
- for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)
+ for(uint32 j = 0; j < MAX_BATTLEGROUND_QUEUES; j++)
{
- delete (*itr);
+ m_SumOfWaitTimes[i][j] = 0;
+ m_WaitTimeLastPlayer[i][j] = 0;
+ for(uint32 k = 0; k < COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME; k++)
+ m_WaitTimes[i][j][k] = 0;
}
- m_QueuedGroups[i].clear();
}
}
-// initialize eligible groups from the given source matching the given specifications
-void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
+BattleGroundQueue::~BattleGroundQueue()
{
- // clear from prev initialization
- clear();
- BattleGroundQueue::QueuedGroupsList::iterator itr, next;
- // iterate through the source
- for(itr = source->begin(); itr!= source->end(); itr = next)
+ m_QueuedPlayers.clear();
+ for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
{
- next = itr;
- ++next;
- if( (*itr)->BgTypeId == BgTypeId && // bg type must match
- (*itr)->ArenaType == ArenaType && // arena type must match
- (*itr)->IsRated == IsRated && // israted must match
- (*itr)->IsInvitedToBGInstanceGUID == 0 && // leave out already invited groups
- (*itr)->Team == side && // match side
- (*itr)->Players.size() <= MaxPlayers && // the group must fit in the bg
- ( !excludeTeam || (*itr)->ArenaTeamId != excludeTeam ) && // if excludeTeam is specified, leave out those arena team ids
- ( !IsRated || (*itr)->Players.size() == MaxPlayers ) && // if rated, then pass only if the player count is exact NEEDS TESTING! (but now this should never happen)
- ( !DisregardTime || (*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time
- || (*itr)->ArenaTeamRating == 0 // pass if no rating info
- || ( (*itr)->ArenaTeamRating >= MinRating // pass if matches the rating range
- && (*itr)->ArenaTeamRating <= MaxRating ) ) )
+ for(uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; j++)
{
- // the group matches the conditions
- // using push_back for proper selecting when inviting
- push_back((*itr));
+ for(GroupsQueueType::iterator itr = m_QueuedGroups[i][j].begin(); itr!= m_QueuedGroups[i][j].end(); ++itr)
+ delete (*itr);
+ m_QueuedGroups[i][j].clear();
}
}
}
+/*********************************************************/
+/*** BATTLEGROUND QUEUE SELECTION POOLS ***/
+/*********************************************************/
+
// selection pool initialization, used to clean up from prev selection
-void BattleGroundQueue::SelectionPool::Init(EligibleGroups * curr)
+void BattleGroundQueue::SelectionPool::Init()
{
- m_CurrEligGroups = curr;
SelectedGroups.clear();
PlayerCount = 0;
}
// remove group info from selection pool
-void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)
+// returns true when we need to try to add new group to selection pool
+// returns false when selection pool is ok or when we kicked smaller group than we need to kick
+// sometimes it can be called on empty selection pool
+bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size)
{
- // find what to remove
- for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
+ //find maxgroup or LAST group with size == size and kick it
+ bool found = false;
+ GroupsQueueType::iterator groupToKick = SelectedGroups.begin();
+ for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr)
{
- if((*itr)==ginfo)
+ if (abs((int32)((*itr)->Players.size() - size)) <= 1)
{
- SelectedGroups.erase(itr);
- // decrease selected players count
- PlayerCount -= ginfo->Players.size();
- return;
+ groupToKick = itr;
+ found = true;
}
+ else if (!found && (*itr)->Players.size() >= (*groupToKick)->Players.size())
+ groupToKick = itr;
+ }
+ //if pool is empty, do nothing
+ if (GetPlayerCount())
+ {
+ //update player count
+ GroupQueueInfo* ginfo = (*groupToKick);
+ SelectedGroups.erase(groupToKick);
+ PlayerCount -= ginfo->Players.size();
+ //return false if we kicked smaller group or there are enough players in selection pool
+ if (ginfo->Players.size() <= size + 1)
+ return false;
}
+ return true;
}
-// add group to selection
+// add group to selection pool
// used when building selection pools
-void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)
+// returns true if we can invite more players, or when we added group to selection pool
+// returns false when selection pool is full
+bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount)
{
- SelectedGroups.push_back(ginfo);
- // increase selected players count
- PlayerCount+=ginfo->Players.size();
+ //if group is larger than desired count - don't allow to add it to pool
+ if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size())
+ {
+ SelectedGroups.push_back(ginfo);
+ // increase selected players count
+ PlayerCount += ginfo->Players.size();
+ return true;
+ }
+ if (PlayerCount < desiredCount)
+ return true;
+ return false;
}
+/*********************************************************/
+/*** BATTLEGROUND QUEUES ***/
+/*********************************************************/
+
// add group to bg queue with the given leader and bg specifications
-GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating, uint32 arenateamid)
+GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 arenateamid)
{
- uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();
+ BGQueueIdBasedOnLevel queue_id = leader->GetBattleGroundQueueIdFromLevel(BgTypeId);
// create new ginfo
// cannot use the method like in addplayer, because that could modify an in-queue group's stats
@@ -147,28 +160,34 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, ui
ginfo->ArenaType = ArenaType;
ginfo->ArenaTeamId = arenateamid;
ginfo->IsRated = isRated;
- ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?
+ ginfo->IsInvitedToBGInstanceGUID = 0;
ginfo->JoinTime = getMSTime();
+ ginfo->RemoveInviteTime = 0;
ginfo->Team = leader->GetTeam();
ginfo->ArenaTeamRating = arenaRating;
- ginfo->OpponentsTeamRating = 0; //initialize it to 0
+ ginfo->OpponentsTeamRating = 0;
ginfo->Players.clear();
- m_QueuedGroups[queue_id].push_back(ginfo);
+ //compute index (if group is premade or joined a rated match) to queues
+ uint32 index = 0;
+ if (!isRated && !isPremade)
+ index += BG_TEAMS_COUNT;
+ if (ginfo->Team == HORDE)
+ index++;
+ sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index);
+
+ m_QueuedGroups[queue_id][index].push_back(ginfo);
// return ginfo, because it is needed to add players to this group info
return ginfo;
}
+//add player to playermap
void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
{
- uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
-
//if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
- PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
- info.InviteTime = 0;
- info.LastInviteTime = 0;
+ PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()];
info.LastOnlineTime = getMSTime();
info.GroupInfo = ginfo;
@@ -176,113 +195,228 @@ void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
ginfo->Players[plr->GetGUID()] = &info;
}
-void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
+void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
{
- Player *plr = objmgr.GetPlayer(guid);
+ uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime());
+ uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
+ if (!ginfo->ArenaType)
+ {
+ if (ginfo->Team == HORDE)
+ team_index = BG_TEAM_HORDE;
+ }
+ else
+ {
+ if (ginfo->IsRated)
+ team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
+ }
- uint32 queue_id = 0;
- QueuedPlayersMap::iterator itr;
- GroupQueueInfo * group;
- QueuedGroupsList::iterator group_itr;
- bool IsSet = false;
- if(plr)
+ //store pointer to arrayindex of player that was added first
+ uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][queue_id]);
+ //remove his time from sum
+ m_SumOfWaitTimes[team_index][queue_id] -= m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)];
+ //set average time to new
+ m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)] = timeInQueue;
+ //add new time to sum
+ m_SumOfWaitTimes[team_index][queue_id] += timeInQueue;
+ //set index of last player added to next one
+ (*lastPlayerAddedPointer)++;
+ (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
+}
+
+uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
+{
+ uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
+ if (!ginfo->ArenaType)
{
- queue_id = plr->GetBattleGroundQueueIdFromLevel();
+ if (ginfo->Team == HORDE)
+ team_index = BG_TEAM_HORDE;
+ }
+ else
+ {
+ if (ginfo->IsRated)
+ team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
+ }
+ //check if there is enought values(we always add values > 0)
+ if (m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] )
+ return (m_SumOfWaitTimes[team_index][queue_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME);
+ else
+ //if there aren't enough values return 0 - not available
+ return 0;
+}
+
+//remove player from queue and from group info, if group info is empty then remove it too
+void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
+{
+ //Player *plr = objmgr.GetPlayer(guid);
+
+ int32 queue_id = -1; // signed for proper for-loop finish
+ QueuedPlayersMap::iterator itr;
- itr = m_QueuedPlayers[queue_id].find(guid);
- if(itr != m_QueuedPlayers[queue_id].end())
- IsSet = true;
+ //remove player from map, if he's there
+ itr = m_QueuedPlayers.find(guid);
+ if (itr == m_QueuedPlayers.end())
+ {
+ sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid));
+ return;
}
- if(!IsSet)
+ GroupQueueInfo* group = itr->second.GroupInfo;
+ GroupsQueueType::iterator group_itr, group_itr_tmp;
+ // mostly people with the highest levels are in battlegrounds, thats why
+ // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
+ // variable index removes useless searching in other team's queue
+ uint32 index = (group->Team == HORDE) ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE;
+
+ for (int32 queue_id_tmp = MAX_BATTLEGROUND_QUEUES - 1; queue_id_tmp >= 0 && queue_id == -1; --queue_id_tmp)
{
- // either player is offline, or he levelled up to another queue category
- // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
- for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
+ //we must check premade and normal team's queue - because when players from premade are joining bg,
+ //they leave groupinfo so we can't use its players size to find out index
+ for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_QUEUE_NORMAL_ALLIANCE)
{
- itr = m_QueuedPlayers[i].find(guid);
- if(itr != m_QueuedPlayers[i].end())
+ for(group_itr_tmp = m_QueuedGroups[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp)
{
- queue_id = i;
- IsSet = true;
- break;
+ if ((*group_itr_tmp) == group)
+ {
+ queue_id = queue_id_tmp;
+ group_itr = group_itr_tmp;
+ //we must store index to be able to erase iterator
+ index = j;
+ break;
+ }
}
}
}
-
- // couldn't find the player in bg queue, return
- if(!IsSet)
+ //player can't be in queue without group, but just in case
+ if (queue_id == -1)
{
- sLog.outError("Battleground: couldn't find player to remove.");
+ sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid));
return;
}
+ sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from queue_id %u", GUID_LOPART(guid), (uint32)queue_id);
- group = itr->second.GroupInfo;
+ // ALL variables are correctly set
+ // We can ignore leveling up in queue - it should not cause crash
+ // remove player from group
+ // if only one player there, remove group
- for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
+ // remove player queue info from group queue info
+ std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
+ if (pitr != group->Players.end())
+ group->Players.erase(pitr);
+
+ // if invited to bg, and should decrease invited count, then do it
+ if (decreaseInvitedCount && group->IsInvitedToBGInstanceGUID)
{
- if(group == (GroupQueueInfo*)(*group_itr))
- break;
+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId);
+ if (bg)
+ bg->DecreaseInvitedCount(group->Team);
}
- // variables are set (what about leveling up when in queue????)
- // remove player from group
- // if only player there, remove group
+ // remove player queue info
+ m_QueuedPlayers.erase(itr);
- // remove player queue info from group queue info
- std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
+ //if we left BG queue(not porting) OR if arena team left queue for rated match
+ if ((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()))
+ AnnounceWorld(group, guid, false);
- if(pitr != group->Players.end())
- group->Players.erase(pitr);
+ //if player leaves queue and he is invited to rated arena match, then he have to loose
+ if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount)
+ {
+ ArenaTeam * at = objmgr.GetArenaTeamById(group->ArenaTeamId);
+ if (at)
+ {
+ sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
+ Player *plr = objmgr.GetPlayer(guid);
+ if (plr)
+ at->MemberLost(plr, group->OpponentsTeamRating);
+ else
+ at->OfflineMemberLost(guid, group->OpponentsTeamRating);
+ at->SaveToDB();
+ }
+ }
- // check for iterator correctness
- if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
+ // remove group queue info if needed
+ if (group->Players.empty())
{
- // used when player left the queue, NOT used when porting to bg
- if (decreaseInvitedCount)
+ m_QueuedGroups[queue_id][index].erase(group_itr);
+ delete group;
+ }
+ // if group wasn't empty, so it wasn't deleted, and player have left a rated
+ // queue -> everyone from the group should leave too
+ // don't remove recursively if already invited to bg!
+ else if (!group->IsInvitedToBGInstanceGUID && group->IsRated)
+ {
+ // remove next player, this is recursive
+ // first send removal information
+ if (Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
{
- // if invited to bg, and should decrease invited count, then do it
- if(group->IsInvitedToBGInstanceGUID)
- {
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);
- if (bg)
- bg->DecreaseInvitedCount(group->Team);
- if (bg && !bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))
- {
- // no more players on battleground, set delete it
- bg->SetDeleteThis();
- }
- }
- // update the join queue, maybe now the player's group fits in a queue!
- // not yet implemented (should store bgTypeId in group queue info?)
+ BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType);
+ uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
+ plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
+ // queue->removeplayer, it causes bugs
+ WorldPacket data;
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
+ plr2->GetSession()->SendPacket(&data);
}
- // remove player queue info
- m_QueuedPlayers[queue_id].erase(itr);
- // remove group queue info if needed
- if(group->Players.empty())
+ // then actually delete, this may delete the group as well!
+ RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
+ }
+}
+
+//Announce world message
+void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
+{
+ if(ginfo->ArenaType) //if Arena
+ {
+ if (sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated)
{
- m_QueuedGroups[queue_id].erase(group_itr);
- delete group;
+ BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
+ if (!bg)
+ return;
+
+ char const* bgName = bg->GetName();
+ if (isAddedToQueue)
+ sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
+ else
+ sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
}
- // NEEDS TESTING!
- // group wasn't empty, so it wasn't deleted, and player have left a rated queue -> everyone from the group should leave too
- // don't remove recursively if already invited to bg!
- else if(!group->IsInvitedToBGInstanceGUID && decreaseInvitedCount && group->IsRated)
+ }
+ else //if BG
+ {
+ if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
{
- // remove next player, this is recursive
- // first send removal information
- if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
+ Player *plr = objmgr.GetPlayer(playerGUID);
+ BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
+ if (!bg || !plr)
+ return;
+
+ BGQueueIdBasedOnLevel queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID());
+ char const* bgName = bg->GetName();
+ uint32 MinPlayers = bg->GetMinPlayersPerTeam();
+ uint32 qHorde = 0;
+ uint32 qAlliance = 0;
+ uint32 q_min_level = (queue_id + 1) * 10;
+ GroupsQueueType::const_iterator itr;
+ for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
+ if (!(*itr)->IsInvitedToBGInstanceGUID)
+ qAlliance += (*itr)->Players.size();
+ for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
+ if (!(*itr)->IsInvitedToBGInstanceGUID)
+ qHorde += (*itr)->Players.size();
+
+ // Show queue status to player only (when joining queue)
+ if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
+ {
+ ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
+ bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
+ }
+ // System message
+ else
{
- BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(group->BgTypeId,group->ArenaType);
- uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
- plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
- plr2->GetSession()->SendPacket(&data);
+ sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
+ bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
}
- // then actually delete, this may delete the group as well!
- RemovePlayer(group->Players.begin()->first,decreaseInvitedCount);
}
}
}
@@ -290,30 +424,48 @@ void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
{
// set side if needed
- if(side)
+ if (side)
ginfo->Team = side;
- if(!ginfo->IsInvitedToBGInstanceGUID)
+ if (!ginfo->IsInvitedToBGInstanceGUID)
{
// not yet invited
// set invitation
ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ BattleGroundTypeId bgTypeId = bg->GetTypeID();
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, bg->GetArenaType());
+ BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
+
+ // set ArenaTeamId for rated matches
+ if (bg->isArena() && bg->isRated())
+ bg->SetArenaTeamIdForTeam(ginfo->Team, ginfo->ArenaTeamId);
+
+ ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME;
+
// loop through the players
for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
{
- // set status
- itr->second->InviteTime = getMSTime();
- itr->second->LastInviteTime = getMSTime();
-
// get the player
Player* plr = objmgr.GetPlayer(itr->first);
- // if offline, skip him
- if(!plr)
+ // if offline, skip him, this should not happen - player is removed from queue when he logs out
+ if (!plr)
continue;
// invite the player
- sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);
+ PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id);
+ //sBattleGroundMgr.InvitePlayer(plr, bg, ginfo->Team);
+
+ // set invited player counters
+ bg->IncreaseInvitedCount(ginfo->Team);
+
+ plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID);
+
+ // create remind invite events
+ BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->RemoveInviteTime);
+ plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME));
+ // create automatic remove events
+ BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime);
+ plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
WorldPacket data;
@@ -322,7 +474,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b
sLog.outDebug("Battleground: invited plr %s (%u) to BG instance %u queueindex %u bgtype %u, I can't help it if they don't press the enter battle button.",plr->GetName(),plr->GetGUIDLow(),bg->GetInstanceID(),queueSlot,bg->GetTypeID());
// send status packet
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType);
plr->GetSession()->SendPacket(&data);
}
return true;
@@ -331,190 +483,292 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b
return false;
}
-// used to recursively select groups from eligible groups
-bool BattleGroundQueue::SelectionPool::Build(uint32 MinPlayers, uint32 MaxPlayers, EligibleGroups::iterator startitr)
+/*
+This function is inviting players to already running battlegrounds
+Invitation type is based on config file
+large groups are disadvantageous, because they will be kicked first if invitation type = 1
+*/
+void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id)
{
- // start from the specified start iterator
- for(EligibleGroups::iterator itr1 = startitr; itr1 != m_CurrEligGroups->end(); ++itr1)
+ int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
+ int32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
+
+ //iterator for iterating through bg queue
+ GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
+ //count of groups in queue - used to stop cycles
+ uint32 aliCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].size();
+ //index to queue which group is current
+ uint32 aliIndex = 0;
+ for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
+ ++Ali_itr;
+ //the same thing for horde
+ GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin();
+ uint32 hordeCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].size();
+ uint32 hordeIndex = 0;
+ for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
+ ++Horde_itr;
+
+ //if ofc like BG queue invitation is set in config, then we are happy
+ if (sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0)
+ return;
+
+ /*
+ if we reached this code, then we have to solve NP - complete problem called Subset sum problem
+ So one solution is to check all possible invitation subgroups, or we can use these conditions:
+ 1. Last time when BattleGroundQueue::Update was executed we invited all possible players - so there is only small possibility
+ that we will invite now whole queue, because only 1 change has been made to queues from the last BattleGroundQueue::Update call
+ 2. Other thing we should consider is group order in queue
+ */
+
+ // At first we need to compare free space in bg and our selection pool
+ int32 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
+ int32 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
+ while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) )
{
- // if it fits in, select it
- if(GetPlayerCount() + (*itr1)->Players.size() <= MaxPlayers)
+ //each cycle execution we need to kick at least 1 group
+ if (diffAli < diffHorde)
{
- EligibleGroups::iterator next = itr1;
- ++next;
- AddGroup((*itr1));
- if(GetPlayerCount() >= MinPlayers)
+ //kick alliance group, add to pool new group if needed
+ if (m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli))
{
- // enough players are selected
- return true;
+ for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
+ ++Ali_itr;
+ }
+ //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
+ if (!m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
+ {
+ if (aliFree <= diffHorde + 1)
+ break;
+ m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli);
}
- // try building from the rest of the elig. groups
- // if that succeeds, return true
- if(Build(MinPlayers,MaxPlayers,next))
- return true;
- // the rest didn't succeed, so this group cannot be included
- RemoveGroup((*itr1));
}
+ else
+ {
+ //kick horde group, add to pool new group if needed
+ if (m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde))
+ {
+ for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
+ ++Horde_itr;
+ }
+ if (!m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
+ {
+ if (hordeFree <= diffAli + 1)
+ break;
+ m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
+ }
+ }
+ //count diffs after small update
+ diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
+ diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
}
- // build didn't succeed
- return false;
}
-// this function is responsible for the selection of queued groups when trying to create new battlegrounds
-bool BattleGroundQueue::BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
+// this method checks if premade versus premade battleground is possible
+// then after 30 mins (default) in queue it moves premade group to normal queue
+// it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
+bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
{
- uint32 side;
- switch(mode)
- {
- case NORMAL_ALLIANCE:
- case ONESIDE_ALLIANCE_TEAM1:
- case ONESIDE_ALLIANCE_TEAM2:
- side = ALLIANCE;
- break;
- case NORMAL_HORDE:
- case ONESIDE_HORDE_TEAM1:
- case ONESIDE_HORDE_TEAM2:
- side = HORDE;
- break;
- default:
- //unknown mode, return false
- sLog.outDebug("Battleground: unknown selection pool build mode, returning...");
- return false;
- break;
- }
-
- // initiate the groups eligible to create the bg
- m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime, excludeTeam);
- // init the selected groups (clear)
- // and set m_CurrEligGroups pointer
- // we set it this way to only have one EligibleGroups object to save some memory
- m_SelectionPools[mode].Init(&m_EligibleGroups);
- // build succeeded
- if(m_SelectionPools[mode].Build(MinPlayers,MaxPlayers,m_EligibleGroups.begin()))
- {
- // the selection pool is set, return
- sLog.outDebug("Battleground-debug: pool build succeeded, return true");
- sLog.outDebug("Battleground-debug: Player size for mode %u is %u", mode, m_SelectionPools[mode].GetPlayerCount());
- for(std::list<GroupQueueInfo* >::iterator itr = m_SelectionPools[mode].SelectedGroups.begin(); itr != m_SelectionPools[mode].SelectedGroups.end(); ++itr)
+ //check match
+ if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
+ {
+ //start premade match
+ //if groups aren't invited
+ GroupsQueueType::const_iterator ali_group, horde_group;
+ for( ali_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group)
+ if (!(*ali_group)->IsInvitedToBGInstanceGUID)
+ break;
+ for( horde_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin(); horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++horde_group)
+ if (!(*horde_group)->IsInvitedToBGInstanceGUID)
+ break;
+
+ if (ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end())
{
- sLog.outDebug("Battleground-debug: queued group in selection with %u players",(*itr)->Players.size());
- for(std::map<uint64, PlayerQueueInfo * >::iterator itr2 = (*itr)->Players.begin(); itr2 != (*itr)->Players.end(); ++itr2)
- sLog.outDebug("Battleground-debug: player in above group GUID %u", (uint32)(itr2->first));
+ m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
+ m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
+ //add groups/players from normal queue to size of bigger group
+ uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
+ GroupsQueueType::const_iterator itr;
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ {
+ for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
+ {
+ //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
+ if (!(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers))
+ break;
+ }
+ }
+ //premade selection pools are set
+ return true;
+ }
+ }
+ // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
+ // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
+ // if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg
+ // and when they click or after 80 seconds the queue info is removed from queue
+ uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ {
+ if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
+ {
+ GroupsQueueType::iterator itr = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin();
+ if (!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
+ {
+ //we must insert group to normal queue and erase pointer from premade queue
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
+ }
}
- return true;
}
- // failed to build a selection pool matching the given values
+ //selection pools are not set
return false;
}
-// used to remove the Enter Battle window if the battle has already, but someone still has it
-// (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
-void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
+// this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
+bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers)
{
- uint32 queue_id = bg->GetQueueType();
- uint32 bgInstanceId = bg->GetInstanceID();
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
- QueuedGroupsList::iterator itr, next;
- for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)
- {
- // must do this way, because the groupinfo will be deleted when all playerinfos are removed
- GroupQueueInfo * ginfo = (*itr);
- next = itr;
- ++next;
- // if group was invited to this bg instance, then remove all references
- if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)
+ GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ {
+ itr_team[i] = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
+ for(; itr_team[i] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
{
- // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
- uint32 to_remove = ginfo->Players.size();
- uint32 team = ginfo->Team;
- for(int i = 0; i < to_remove; ++i)
+ if (!(*(itr_team[i]))->IsInvitedToBGInstanceGUID)
{
- // always remove the first one in the group
- std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
- if(itr2 == ginfo->Players.end())
- {
- sLog.outError("Empty Players in ginfo, this should never happen!");
- return;
- }
+ m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
+ if (m_SelectionPools[i].GetPlayerCount() >= minPlayers)
+ break;
+ }
+ }
+ }
+ //try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg
+ uint32 j = BG_TEAM_ALLIANCE;
+ if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
+ j = BG_TEAM_HORDE;
+ if( sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0
+ && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers )
+ {
+ //we will try to invite more groups to team with less players indexed by j
+ ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break;
+ for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
+ {
+ if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID)
+ if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()))
+ break;
+ }
+ // do not allow to start bg with more than 2 players more on 1 faction
+ if (abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2)
+ return false;
+ }
+ //allow 1v0 if debug bg
+ if (sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()))
+ return true;
+ //return true if there are enough players in selection pools - enable to work .debug bg command correctly
+ return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
+}
- // get the player
- Player * plr = objmgr.GetPlayer(itr2->first);
- if(!plr)
- {
- sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
- continue;
- }
+// this method will check if we can invite players to same faction skirmish match
+bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam)
+{
+ if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam)
+ return false;
+ uint32 teamIndex = BG_TEAM_ALLIANCE;
+ uint32 otherTeam = BG_TEAM_HORDE;
+ uint32 otherTeamId = HORDE;
+ if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam )
+ {
+ teamIndex = BG_TEAM_HORDE;
+ otherTeam = BG_TEAM_ALLIANCE;
+ otherTeamId = ALLIANCE;
+ }
+ //clear other team's selection
+ m_SelectionPools[otherTeam].Init();
+ //store last ginfo pointer
+ GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
+ //set itr_team to group that was added to selection pool latest
+ GroupsQueueType::iterator itr_team = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
+ for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
+ if (ginfo == *itr_team)
+ break;
+ if (itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end())
+ return false;
+ GroupsQueueType::iterator itr_team2 = itr_team;
+ ++itr_team2;
+ //invite players to other selection pool
+ for(; itr_team2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
+ {
+ //if selection pool is full then break;
+ if (!(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam))
+ break;
+ }
+ if (m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam)
+ return false;
- // get the queueslot
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
- {
- plr->RemoveBattleGroundQueueId(bgQueueTypeId);
- // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
- RemovePlayer(itr2->first, true);
- // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups
- // but updating the queue can't hurt
- Update(bgQueueTypeId, bg->GetQueueType());
- // send info to client
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);
- plr->GetSession()->SendPacket(&data);
- }
+ //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
+ for(GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
+ {
+ //set correct team
+ (*itr)->Team = otherTeamId;
+ //add team to other queue
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
+ //remove team from old queue
+ GroupsQueueType::iterator itr2 = itr_team;
+ ++itr2;
+ for(; itr2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
+ {
+ if (*itr2 == *itr)
+ {
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
+ break;
}
}
}
+ return true;
}
/*
this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
it must be called after fully adding the members of a group to ensure group joining
-should be called after removeplayer functions in some cases
+should be called from BattleGround::RemovePlayer function in some cases
*/
-void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
+void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating)
{
- if (queue_id >= MAX_BATTLEGROUND_QUEUES)
- {
- //this is error, that caused crashes (not in , but now it shouldn't)
- sLog.outError("BattleGroundQueue::Update() called for non existing queue type - this can cause crash, pls report problem, if this is the last line of error log before crash");
- return;
- }
-
- //if no players in queue ... do nothing
- if (m_QueuedGroups[queue_id].empty())
+ //if no players in queue - do nothing
+ if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() &&
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].empty() )
return;
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
-
- //battleground with free slot for player should be always the last in this queue
+ //battleground with free slot for player should be always in the beggining of the queue
+ // maybe it would be better to create bgfreeslotqueue for each queue_id_based_on_level
BGFreeSlotQueueType::iterator itr, next;
for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
{
next = itr;
++next;
- // battleground is running, so if:
- // DO NOT allow queue manager to invite new player to running arena
- if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
+ // DO NOT allow queue manager to invite new player to arena
+ if( (*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id &&
+ (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE )
{
- //we must check both teams
BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
// and iterator is invalid
- for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
- {
- // did the group join for this bg type?
- if((*itr)->BgTypeId != bgTypeId)
- continue;
- // if so, check if fits in
- if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())
- {
- // if group fits in, invite it
- InviteGroupToBG((*itr),bg,(*itr)->Team);
- }
- }
+ // clear selection pools
+ m_SelectionPools[BG_TEAM_ALLIANCE].Init();
+ m_SelectionPools[BG_TEAM_HORDE].Init();
+
+ // call a function that does the job for us
+ FillPlayersToBG(bg, queue_id);
+
+ // now everything is set, invite players
+ for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++citr)
+ InviteGroupToBG((*citr), bg, (*citr)->Team);
+ for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++citr)
+ InviteGroupToBG((*citr), bg, (*citr)->Team);
if (!bg->HasFreeSlots())
{
- //remove BG from BGFreeSlotQueue
+ // remove BG from BGFreeSlotQueue
bg->RemoveFromBGFreeSlotQueue();
}
}
@@ -523,25 +777,29 @@ void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype
// finished iterating through the bgs with free slots, maybe we need to create a new bg
BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
- if(!bg_template)
+ if (!bg_template)
{
sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
return;
}
-
// get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
- if(bg_template->isArena())
+ if (sBattleGroundMgr.isTesting())
+ MinPlayersPerTeam = 1;
+ if (bg_template->isArena())
{
- if(sBattleGroundMgr.isArenaTesting())
+ if (sBattleGroundMgr.isArenaTesting())
{
MaxPlayersPerTeam = 1;
MinPlayersPerTeam = 1;
}
else
{
- switch(arenatype)
+ //this switch can be much shorter
+ MaxPlayersPerTeam = arenaType;
+ MinPlayersPerTeam = arenaType;
+ /*switch(arenaType)
{
case ARENA_TYPE_2v2:
MaxPlayersPerTeam = 2;
@@ -555,293 +813,192 @@ void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype
MaxPlayersPerTeam = 5;
MinPlayersPerTeam = 5;
break;
- }
+ }*/
}
}
- // found out the minimum and maximum ratings the newly added team should battle against
- // arenaRating is the rating of the latest joined team
- uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
- // if no rating is specified, set maxrating to 0
- uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
- uint32 discardTime = 0;
- // if max rating difference is set and the time past since server startup is greater than the rating discard time
- // (after what time the ratings aren't taken into account when making teams) then
- // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
- // else leave the discard time on 0, this way all ratings will be discarded
- if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())
- discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
-
- // try to build the selection pools
- bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
- if(bAllyOK)
- sLog.outDebug("Battleground: ally pool successfully built");
- else
- sLog.outDebug("Battleground: ally pool wasn't created");
- bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
- if(bHordeOK)
- sLog.outDebug("Battleground: horde pool successfully built");
- else
- sLog.outDebug("Battleground: horde pool wasn't created");
+ m_SelectionPools[BG_TEAM_ALLIANCE].Init();
+ m_SelectionPools[BG_TEAM_HORDE].Init();
- // if selection pools are ready, create the new bg
- if (bAllyOK && bHordeOK)
+ if (bg_template->isBattleGround())
{
- BattleGround * bg2 = 0;
- // special handling for arenas
- if(bg_template->isArena())
+ //check if there is premade against premade match
+ if (CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam))
{
- // Find a random arena, that can be created
- uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
- uint32 arena_num = urand(0,2);
- if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
- !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
- !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
+ //create new battleground
+ BattleGround * bg2 = NULL;
+ if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)))
{
- sLog.outError("Battleground: couldn't create any arena instance!");
+ sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
return;
}
-
- // set the MaxPlayersPerTeam values based on arenatype
- // setting the min player values isn't needed, since we won't be using that value later on.
- if(sBattleGroundMgr.isArenaTesting())
- {
- bg2->SetMaxPlayersPerTeam(1);
- bg2->SetMaxPlayers(2);
- }
- else
- {
- switch(arenatype)
- {
- case ARENA_TYPE_2v2:
- bg2->SetMaxPlayersPerTeam(2);
- bg2->SetMaxPlayers(4);
- break;
- case ARENA_TYPE_3v3:
- bg2->SetMaxPlayersPerTeam(3);
- bg2->SetMaxPlayers(6);
- break;
- case ARENA_TYPE_5v5:
- bg2->SetMaxPlayersPerTeam(5);
- bg2->SetMaxPlayers(10);
- break;
- default:
- break;
- }
- }
- }
- else
- {
- // create new battleground
- bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);
- }
-
- if(!bg2)
- {
- sLog.outError("Battleground: couldn't create bg %u",bgTypeId);
- return;
- }
-
- // start the joining of the bg
- bg2->SetStatus(STATUS_WAIT_JOIN);
- bg2->SetQueueType(queue_id);
- // initialize arena / rating info
- bg2->SetArenaType(arenatype);
- // set rating
- bg2->SetRated(isRated);
-
- std::list<GroupQueueInfo* >::iterator itr;
-
- // Send amount of invites based on the difference between the sizes of the two faction's queues
- uint32 QUEUED_HORDE = m_SelectionPools[NORMAL_HORDE].SelectedGroups.size();
- uint32 QUEUED_ALLIANCE = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.size();
- uint16 maxbginvites = 0;
-
- if(QUEUED_ALLIANCE <= QUEUED_HORDE)
- maxbginvites = QUEUED_ALLIANCE;
- else
- maxbginvites = QUEUED_HORDE;
-
- // invite groups from horde selection pool
- uint16 invitecounter = 0;
- for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
- {
- if (invitecounter >= maxbginvites)
- return;
- InviteGroupToBG((*itr),bg2,HORDE);
- ++invitecounter;
- }
-
- // invite groups from ally selection pool
- invitecounter = 0;
- for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
- {
- if (invitecounter >= maxbginvites)
- return;
- InviteGroupToBG((*itr),bg2,ALLIANCE);
- ++invitecounter;
- }
-
- if (isRated)
- {
- std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin();
- std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin();
- (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
- sLog.outDebug("setting opposite team rating for team %u to %u", (*itr_alliance)->ArenaTeamId, (*itr_alliance)->OpponentsTeamRating);
- (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
- sLog.outDebug("setting opposite team rating for team %u to %u", (*itr_horde)->ArenaTeamId, (*itr_horde)->OpponentsTeamRating);
+ //invite those selection pools
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
+ InviteGroupToBG((*citr), bg2, (*citr)->Team);
+ //start bg
+ bg2->StartBattleGround();
+ //clear structures
+ m_SelectionPools[BG_TEAM_ALLIANCE].Init();
+ m_SelectionPools[BG_TEAM_HORDE].Init();
}
-
- // start the battleground
- bg2->StartBattleGround();
}
- // there weren't enough players for a "normal" match
- // if arena, enable horde versus horde or alliance versus alliance teams here
-
- else if(bg_template->isArena())
+ // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
+ if (!isRated)
{
- bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;
- bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;
- bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
- if(bOneSideHordeTeam1)
- {
- // one team has been selected, find out if other can be selected too
- std::list<GroupQueueInfo* >::iterator itr;
- // temporarily change the team side to enable building the next pool excluding the already selected groups
- for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
- (*itr)->Team=ALLIANCE;
-
- bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
-
- // change back the team to horde
- for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
- (*itr)->Team=HORDE;
-
- if(!bOneSideHordeTeam2)
- bOneSideHordeTeam1 = false;
- }
- if(!bOneSideHordeTeam1)
+ // if there are enough players in pools, start new battleground or non rated arena
+ if (CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
+ || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
{
- // check for one sided ally
- bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
- if(bOneSideAllyTeam1)
+ // we successfully created a pool
+ BattleGround * bg2 = NULL;
+ if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)))
{
- // one team has been selected, find out if other can be selected too
- std::list<GroupQueueInfo* >::iterator itr;
- // temporarily change the team side to enable building the next pool excluding the already selected groups
- for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
- (*itr)->Team=HORDE;
-
- bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime,(*(m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
-
- // change back the team to ally
- for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
- (*itr)->Team=ALLIANCE;
+ sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
+ return;
}
- if(!bOneSideAllyTeam2)
- bOneSideAllyTeam1 = false;
+ // invite those selection pools
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
+ InviteGroupToBG((*citr), bg2, (*citr)->Team);
+ // start bg
+ bg2->StartBattleGround();
}
- // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
- if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
- (bOneSideAllyTeam1 && bOneSideAllyTeam2) )
+ }
+ else if (bg_template->isArena())
+ {
+ // found out the minimum and maximum ratings the newly added team should battle against
+ // arenaRating is the rating of the latest joined team, or 0
+ // 0 is on (automatic update call) and we must set it to team's with longest wait time
+ if (!arenaRating )
{
- // which side has enough players?
- uint32 side = 0;
- SelectionPoolBuildMode mode1, mode2;
- // find out what pools are we using
- if(bOneSideAllyTeam1 && bOneSideAllyTeam2)
+ GroupQueueInfo* front1 = NULL;
+ GroupQueueInfo* front2 = NULL;
+ if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty())
{
- side = ALLIANCE;
- mode1 = ONESIDE_ALLIANCE_TEAM1;
- mode2 = ONESIDE_ALLIANCE_TEAM2;
+ front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front();
+ arenaRating = front1->ArenaTeamRating;
}
- else
+ if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
{
- side = HORDE;
- mode1 = ONESIDE_HORDE_TEAM1;
- mode2 = ONESIDE_HORDE_TEAM2;
+ front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front();
+ arenaRating = front2->ArenaTeamRating;
}
-
- // create random arena
- uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
- uint32 arena_num = urand(0,2);
- BattleGround* bg2 = NULL;
- if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
- !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
- !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
+ if (front1 && front2)
{
- sLog.outError("Could not create arena.");
- return;
+ if (front1->JoinTime < front2->JoinTime)
+ arenaRating = front1->ArenaTeamRating;
}
+ else if (!front1 && !front2)
+ return; //queues are empty
+ }
+
+ //set rating range
+ uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
+ uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
+ // if max rating difference is set and the time past since server startup is greater than the rating discard time
+ // (after what time the ratings aren't taken into account when making teams) then
+ // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
+ // else leave the discard time on 0, this way all ratings will be discarded
+ uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
+
+ // we need to find 2 teams which will play next game
+
+ GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT];
- sLog.outDebug("Battleground: One-faction arena created.");
- // init stats
- if(sBattleGroundMgr.isArenaTesting())
+ //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
+
+ for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
+ {
+ // take the group that joined first
+ itr_team[i] = m_QueuedGroups[queue_id][i].begin();
+ for(; itr_team[i] != m_QueuedGroups[queue_id][i].end(); ++(itr_team[i]))
{
- bg2->SetMaxPlayersPerTeam(1);
- bg2->SetMaxPlayers(2);
+ // if group match conditions, then add it to pool
+ if( !(*itr_team[i])->IsInvitedToBGInstanceGUID
+ && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating)
+ || (*itr_team[i])->JoinTime < discardTime) )
+ {
+ m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam);
+ // break for cycle to be able to start selecting another group from same faction queue
+ break;
+ }
}
- else
+ }
+ // now we are done if we have 2 groups - ali vs horde!
+ // if we don't have, we must try to continue search in same queue
+ // tmp variables are correctly set
+ // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
+ if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
+ {
+ itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE];
+ ++itr_team[BG_TEAM_ALLIANCE];
+ for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
{
- switch(arenatype)
+ if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID
+ && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
+ || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) )
{
- case ARENA_TYPE_2v2:
- bg2->SetMaxPlayersPerTeam(2);
- bg2->SetMaxPlayers(4);
- break;
- case ARENA_TYPE_3v3:
- bg2->SetMaxPlayersPerTeam(3);
- bg2->SetMaxPlayers(6);
- break;
- case ARENA_TYPE_5v5:
- bg2->SetMaxPlayersPerTeam(5);
- bg2->SetMaxPlayers(10);
+ m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam);
break;
- default:
+ }
+ }
+ }
+ // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
+ if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
+ {
+ itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE];
+ ++itr_team[BG_TEAM_HORDE];
+ for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
+ {
+ if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID
+ && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
+ || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) )
+ {
+ m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam);
break;
}
}
+ }
- bg2->SetRated(isRated);
-
- // assigned team of the other group
- uint32 other_side;
- if(side == ALLIANCE)
- other_side = HORDE;
- else
- other_side = ALLIANCE;
-
- // start the joining of the bg
- bg2->SetStatus(STATUS_WAIT_JOIN);
- bg2->SetQueueType(queue_id);
- // initialize arena / rating info
- bg2->SetArenaType(arenatype);
-
- std::list<GroupQueueInfo* >::iterator itr;
-
- // invite players from the first group as horde players (actually green team)
- for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)
+ //if we have 2 teams, then start new arena and invite players!
+ if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
+ {
+ BattleGround* arena = NULL;
+ if (!(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)))
{
- InviteGroupToBG((*itr),bg2,HORDE);
+ sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
+ return;
}
- // invite players from the second group as ally players (actually gold team)
- for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)
+ (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
+ sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
+ (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
+ sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
+ // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer
+ if ((*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE)
{
- InviteGroupToBG((*itr),bg2,ALLIANCE);
+ // add to alliance queue
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
+ // erase from horde queue
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
+ itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
}
-
- if (isRated)
+ if ((*(itr_team[BG_TEAM_HORDE]))->Team != HORDE)
{
- std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[mode1].SelectedGroups.begin();
- std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[mode2].SelectedGroups.begin();
- (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
- (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
+ itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin();
}
- bg2->StartBattleGround();
+ InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
+ InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE);
+
+ sLog.outDebug("Starting rated arena match!");
+
+ arena->StartBattleGround();
}
}
}
@@ -853,36 +1010,29 @@ void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype
bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
Player* plr = objmgr.GetPlayer( m_PlayerGuid );
-
// player logged off (we should do nothing, he is correctly removed from queue in another procedure)
if (!plr)
return true;
- // Player can be in another BG queue and must be removed in normal way in any case
- // // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
- // if (plr->GetBattleGroundId() > 0)
- // return true;
-
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
+ //if battleground ended and its instance deleted - do nothing
if (!bg)
return true;
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
+ if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue or in battleground
{
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
+ // check if player is invited to this bg
+ BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
+ BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
+ if( qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
+ && qItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
{
- // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
- BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
- BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
- if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
- {
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
- plr->GetSession()->SendPacket(&data);
- }
+ WorldPacket data;
+ //we must send remaining time in queue
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType);
+ plr->GetSession()->SendPacket(&data);
}
}
return true; //event will be deleted
@@ -890,10 +1040,18 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
{
- //this should not be called
- sLog.outError("Battleground invite event ABORTED!");
+ //do nothing
}
+/*
+ this event has many possibilities when it is executed:
+ 1. player is in battleground ( he clicked enter on invitation window )
+ 2. player left battleground queue and he isn't there any more
+ 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
+ 4. player left queue and he joined again and he has been invited to same battleground again -> we should not remove him from queue yet
+ 5. player is invited to bg and he didn't choose what to do and timer expired - only in this condition we should call queue::RemovePlayer
+ we must remove player in the 5. case even if battleground object doesn't exist!
+*/
bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
Player* plr = objmgr.GetPlayer( m_PlayerGuid );
@@ -901,40 +1059,33 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
// player logged off (we should do nothing, he is correctly removed from queue in another procedure)
return true;
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
- if (!bg)
- return true;
-
- sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
+ //battleground can be deleted already when we are removing queue info
+ //bg pointer can be NULL! so use it carefully!
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId);
+ if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue, or in Battleground
{
- // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
- BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid);
- if (qMapItr != sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
+ // check if player is in queue for this BG and if we are removing his invite event
+ BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].m_QueuedPlayers;
+ BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid);
+ if( qMapItr != qpMap.end() && qMapItr->second.GroupInfo
+ && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
+ && qMapItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
{
- if (qMapItr->second.GroupInfo->IsRated)
- {
- ArenaTeam * at = objmgr.GetArenaTeamById(qMapItr->second.GroupInfo->ArenaTeamId);
- if (at)
- {
- sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(plr->GetGUID()), qMapItr->second.GroupInfo->OpponentsTeamRating);
- at->MemberLost(plr, qMapItr->second.GroupInfo->OpponentsTeamRating);
- at->SaveToDB();
- }
- }
- plr->RemoveBattleGroundQueueId(bgQueueTypeId);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType());
+ sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
+
+ plr->RemoveBattleGroundQueueId(m_BgQueueTypeId);
+ sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
+ //update queues if battleground isn't ended
+ if (bg)
+ sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].Update(m_BgTypeId, bg->GetQueueId());
+
WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
plr->GetSession()->SendPacket(&data);
}
}
- else
- sLog.outDebug("Battleground: Player was already removed from queue");
//event will be deleted
return true;
@@ -942,76 +1093,98 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
{
- //this should not be called
- sLog.outError("Battleground remove event ABORTED!");
+ //do nothing
}
/*********************************************************/
/*** BATTLEGROUND MANAGER ***/
/*********************************************************/
-BattleGroundMgr::BattleGroundMgr()
+BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
{
- m_BattleGrounds.clear();
- m_AutoDistributePoints = (bool)sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS);
- m_MaxRatingDifference = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
- m_RatingDiscardTimer = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
- m_PrematureFinishTimer = sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
- m_NextRatingDiscardUpdate = m_RatingDiscardTimer;
- m_AutoDistributionTimeChecker = 0;
- m_ArenaTesting = false;
+ for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
+ m_BattleGrounds[i].clear();
+ m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
+ m_Testing=false;
}
BattleGroundMgr::~BattleGroundMgr()
{
- BattleGroundSet::iterator itr, next;
- for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
+ DeleteAllBattleGrounds();
+}
+
+void BattleGroundMgr::DeleteAllBattleGrounds()
+{
+ for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
{
- next = itr;
- ++next;
- BattleGround * bg = itr->second;
- m_BattleGrounds.erase(itr);
- delete bg;
+ for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();)
+ {
+ BattleGround * bg = itr->second;
+ m_BattleGrounds[i].erase(itr++);
+ if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
+ m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
+ delete bg;
+ }
+ }
+
+ // destroy template battlegrounds that listed only in queues (other already terminated)
+ for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
+ {
+ // ~BattleGround call unregistring BG from queue
+ while(!BGFreeSlotQueue[bgTypeId].empty())
+ delete BGFreeSlotQueue[bgTypeId].front();
}
- m_BattleGrounds.clear();
}
// used to update running battlegrounds, and delete finished ones
-void BattleGroundMgr::Update(time_t diff)
+void BattleGroundMgr::Update(uint32 diff)
{
BattleGroundSet::iterator itr, next;
- for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
+ for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
{
- next = itr;
- ++next;
- itr->second->Update(diff);
- // use the SetDeleteThis variable
- // direct deletion caused crashes
- if(itr->second->m_SetDeleteThis)
+ itr = m_BattleGrounds[i].begin();
+ // skip updating battleground template
+ if (itr != m_BattleGrounds[i].end())
+ ++itr;
+ for(; itr != m_BattleGrounds[i].end(); itr = next)
{
- BattleGround * bg = itr->second;
- m_BattleGrounds.erase(itr);
- delete bg;
+ next = itr;
+ ++next;
+ itr->second->Update(diff);
+ // use the SetDeleteThis variable
+ // direct deletion caused crashes
+ if (itr->second->m_SetDeleteThis)
+ {
+ BattleGround * bg = itr->second;
+ m_BattleGrounds[i].erase(itr);
+ if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
+ m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
+ delete bg;
+ }
}
}
// if rating difference counts, maybe force-update queues
- if(m_MaxRatingDifference)
+ if (sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
{
// it's time to force update
- if(m_NextRatingDiscardUpdate < diff)
+ if (m_NextRatingDiscardUpdate < diff)
{
// forced update for level 70 rated arenas
- m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);
- m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);
- m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);
- m_NextRatingDiscardUpdate = m_RatingDiscardTimer;
+ sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
+ m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
}
else
m_NextRatingDiscardUpdate -= diff;
}
- if(m_AutoDistributePoints)
+ if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
{
- if(m_AutoDistributionTimeChecker < diff)
+ if (m_AutoDistributionTimeChecker < diff)
{
if(time(NULL) > m_NextAutoDistributionTime)
{
@@ -1026,10 +1199,11 @@ void BattleGroundMgr::Update(time_t diff)
}
}
-void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
+void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
{
// we can be in 3 queues in same time...
- if(StatusID == 0)
+
+ if (StatusID == 0 || !bg)
{
data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
*data << uint32(QueueSlot); // queue id (0...2)
@@ -1040,10 +1214,11 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
*data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
// uint64 in client
- *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
- *data << uint32(0); // unknown
+ *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
+ *data << uint32(bg->GetClientInstanceID());
// alliance/horde for BG and skirmish/rated for Arenas
- *data << uint8(bg->isArena() ? ( israted ? israted : bg->isRated() ) : bg->GetTeamIndexByTeamId(team));
+ // following displays the minimap-icon 0 = faction icon 1 = arenaicon
+ *data << uint8(bg->isRated());
/* *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!!
switch(bg->GetTypeID()) // value depends on bg id
{
@@ -1071,12 +1246,21 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
case BATTLEGROUND_RL:
*data << uint8(8);
break;
+ case BATTLEGROUND_SA:
+ *data << uint8(9);
+ break;
+ case BATTLEGROUND_DS:
+ *data << uint8(10);
+ break;
+ case BATTLEGROUND_RV:
+ *data << uint8(11);
+ break;
default: // unknown
*data << uint8(0);
break;
}
- if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
+ if (bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
*data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
else
*data << uint32(bg->GetTypeID()); // BG id from DBC
@@ -1084,17 +1268,14 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
*data << uint16(0x1F90); // unk value 8080
*data << uint32(bg->GetInstanceID()); // instance id
- if(bg->isBattleGround())
- *data << uint8(bg->GetTeamIndexByTeamId(team)); // team
- else
- *data << uint8(israted?israted:bg->isRated()); // is rated battle
+ *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena
*/
*data << uint32(StatusID); // status
switch(StatusID)
{
case STATUS_WAIT_QUEUE: // status_in_queue
*data << uint32(Time1); // average wait time, milliseconds
- *data << uint32(Time2); // time in queue, updated every minute?
+ *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
break;
case STATUS_WAIT_JOIN: // status_invite
*data << uint32(bg->GetMapId()); // map id
@@ -1102,7 +1283,7 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
break;
case STATUS_IN_PROGRESS: // status_in_progress
*data << uint32(bg->GetMapId()); // map id
- *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
+ *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
*data << uint32(Time2); // time from bg start, milliseconds
*data << uint8(0x1); // unk sometimes 0x0!
break;
@@ -1115,16 +1296,16 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
{
uint8 type = (bg->isArena() ? 1 : 0);
- // last check on 2.4.1
+ // last check on 3.0.3
data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
- *data << uint8(type); // seems to be type (battleground=0/arena=1)
+ *data << uint8(type); // type (battleground=0/arena=1)
if(type) // arena
{
// it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
for(int i = 1; i >= 0; --i)
{
- *data << uint32(3000-bg->m_ArenaTeamRatingChanges[i]); // rating change: showed value - 3000
+ *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
*data << uint32(3999); // huge thanks for TOM_RUS for this!
sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
}
@@ -1132,16 +1313,16 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
{
uint32 at_id = bg->m_ArenaTeamIds[i];
ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
- if(at)
+ if (at)
*data << at->GetName();
- else//*/
+ else
*data << (uint8)0;
}
}
- if(bg->GetWinner() == 2)
+ if (bg->GetStatus() != STATUS_WAIT_LEAVE)
{
- *data << uint8(0); // bg in progress
+ *data << uint8(0); // bg not ended
}
else
{
@@ -1155,10 +1336,7 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
{
*data << (uint64)itr->first;
*data << (int32)itr->second->KillingBlows;
- Player *plr = objmgr.GetPlayer(itr->first);
- uint32 team = bg->GetPlayerTeam(itr->first);
- if(!team && plr) team = plr->GetTeam();
- if(type == 0)
+ if (type == 0)
{
*data << (int32)itr->second->HonorableKills;
*data << (int32)itr->second->Deaths;
@@ -1166,18 +1344,12 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
}
else
{
- // that part probably wrong
- if(plr)
- {
- if(team == HORDE)
- *data << uint8(0);
- else if(team == ALLIANCE)
- {
- *data << uint8(1);
- }
- else
- *data << uint8(0);
- }
+ Player *plr = objmgr.GetPlayer(itr->first);
+ uint32 team = bg->GetPlayerTeam(itr->first);
+ if (!team && plr)
+ team = plr->GetTeam();
+ if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ))
+ *data << uint8(1);
else
*data << uint8(0);
}
@@ -1204,13 +1376,16 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
*data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
break;
case BATTLEGROUND_EY:
- *data << (uint32)0x00000001; // count of next fields
+ *data << (uint32)0x00000001; // count of next fields
*data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
break;
case BATTLEGROUND_NA:
case BATTLEGROUND_BE:
case BATTLEGROUND_AA:
case BATTLEGROUND_RL:
+ case BATTLEGROUND_SA: // wotlk
+ case BATTLEGROUND_DS: // wotlk
+ case BATTLEGROUND_RV: // wotlk
*data << (int32)0; // 0
break;
default:
@@ -1221,7 +1396,7 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
}
}
-void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId)
+void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
{
/*bgTypeId is:
0 - Your group has joined a battleground queue, but you are not eligible
@@ -1249,10 +1424,10 @@ void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
*data << uint32(soundid);
}
-void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr)
+void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
{
data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
- *data << uint64(plr->GetGUID());
+ *data << uint64(guid);
}
void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
@@ -1261,62 +1436,97 @@ void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Pla
*data << uint64(plr->GetGUID());
}
-void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team)
+BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId)
{
- // set invited player counters:
- BattleGround* bg = GetBattleGround(bgInstanceGUID);
- if(!bg)
- return;
- bg->IncreaseInvitedCount(team);
+ //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
+ //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
+ BattleGround* bg = GetBattleGroundTemplate(bgTypeId);
+ if (!bg)
+ return NULL;
- plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID);
+ if (bg->isArena())
+ return GetBattleGround(instanceId, bgTypeId);
- // set the arena teams for rated matches
- if(bg->isArena() && bg->isRated())
+ for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
+ {
+ if (itr->second->GetClientInstanceID() == instanceId)
+ return itr->second;
+ }
+ return NULL;
+}
+
+BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
+{
+ //search if needed
+ BattleGroundSet::iterator itr;
+ if (bgTypeId == BATTLEGROUND_TYPE_NONE)
{
- switch(bg->GetArenaType())
+ for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
{
- case ARENA_TYPE_2v2:
- bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
- break;
- case ARENA_TYPE_3v3:
- bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
- break;
- case ARENA_TYPE_5v5:
- bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
- break;
- default:
- break;
+ itr = m_BattleGrounds[i].find(InstanceID);
+ if (itr != m_BattleGrounds[i].end())
+ return itr->second;
}
+ return NULL;
}
+ itr = m_BattleGrounds[bgTypeId].find(InstanceID);
+ return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
+}
- // create invite events:
- //add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events
- BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);
- plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2));
- BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);
- plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
+BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
+{
+ //map is sorted and we can be sure that lowest instance id has only BG template
+ return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
}
-BattleGround * BattleGroundMgr::GetBattleGroundTemplate(uint32 bgTypeId)
+uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
{
- return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();
+ if (IsArenaType(bgTypeId))
+ return 0; //arenas don't have client-instanceids
+
+ // we create here an instanceid, which is just for
+ // displaying this to the client and without any other use..
+ // the client-instanceIds are unique for each battleground-type
+ // the instance-id just needs to be as low as possible, beginning with 1
+ // the following works, because std::set is default ordered with "<"
+ // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
+ uint32 lastId = 0;
+ for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();)
+ {
+ if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
+ break;
+ lastId = *itr;
+ }
+ m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1);
+ return lastId + 1;
}
// create a new battleground that will really be used to play
-BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)
+BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated)
{
- BattleGround *bg = NULL;
-
// get the template BG
BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
-
- if(!bg_template)
+ if (!bg_template)
{
sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
- return 0;
+ return NULL;
}
+ //for arenas there is random map used
+ if (bg_template->isArena())
+ {
+ BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
+ uint32 arena_num = urand(0,2);
+ bgTypeId = arenas[arena_num];
+ bg_template = GetBattleGroundTemplate(bgTypeId);
+ if (!bg_template)
+ {
+ sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
+ return NULL;
+ }
+ }
+
+ BattleGround *bg = NULL;
// create a copy of the BG template
switch(bgTypeId)
{
@@ -1344,42 +1554,47 @@ BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)
case BATTLEGROUND_RL:
bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
break;
+ case BATTLEGROUND_SA:
+ bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
+ break;
+ case BATTLEGROUND_DS:
+ bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
+ break;
+ case BATTLEGROUND_RV:
+ bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
+ break;
default:
- //bg = new BattleGround;
+ //error, but it is handled few lines above
return 0;
- break; // placeholder for non implemented BG
}
// generate a new instance id
bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
+ bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id));
// reset the new bg (set status to status_wait_queue from status_none)
bg->Reset();
- /* will be setup in BG::Update() when the first player is ported in
- if(!(bg->SetupBattleGround()))
- {
- sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);
- delete bg;
- return 0;
- }
- */
+ // start the joining of the bg
+ bg->SetStatus(STATUS_WAIT_JOIN);
+ bg->SetQueueId(queue_id);
+ bg->SetArenaType(arenaType);
+ bg->SetRated(isRated);
// add BG to free slot queue
bg->AddToBGFreeSlotQueue();
// add bg to update list
- AddBattleGround(bg->GetInstanceID(), bg);
+ AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
return bg;
}
// used to create the BG templates
-uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
+uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
{
// Create the BG
BattleGround *bg = NULL;
-
switch(bgTypeId)
{
case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
@@ -1390,35 +1605,27 @@ uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPer
case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
+ case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
+ case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
+ case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
default:bg = new BattleGround; break; // placeholder for non implemented BG
}
bg->SetMapId(MapID);
-
- bg->Reset();
-
- BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId);
- //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed
- if (bl)
- {
- bg->SetArenaorBGType(bl->type == TYPE_ARENA);
- }
-
bg->SetTypeID(bgTypeId);
- bg->SetInstanceID(0); // template bg, instance id is 0
+ bg->SetInstanceID(0);
+ bg->SetArenaorBGType(IsArena);
bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
- bg->SetMinPlayers(MinPlayersPerTeam*2);
- bg->SetMaxPlayers(MaxPlayersPerTeam*2);
+ bg->SetMinPlayers(MinPlayersPerTeam * 2);
+ bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
bg->SetName(BattleGroundName);
bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
bg->SetLevelRange(LevelMin, LevelMax);
- //add BattleGround instance to FreeSlotQueue (.back() will return the template!)
- bg->AddToBGFreeSlotQueue();
-
- // do NOT add to update list, since this is a template battleground!
+ // add bg to update list
+ AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
// return some not-null value, bgTypeId is good enough for me
return bgTypeId;
@@ -1431,13 +1638,14 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
BattlemasterListEntry const *bl;
WorldSafeLocsEntry const *start;
+ bool IsArena;
uint32 count = 0;
// 0 1 2 3 4 5 6 7 8
QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
- if(!result)
+ if (!result)
{
barGoLink bar(1);
@@ -1455,44 +1663,46 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
Field *fields = result->Fetch();
bar.step();
- uint32 bgTypeID = fields[0].GetUInt32();
+ uint32 bgTypeID_ = fields[0].GetUInt32();
- // can be overwrited by values from DB
- bl = sBattlemasterListStore.LookupEntry(bgTypeID);
- if(!bl)
+ // can be overwrite by values from DB
+ bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
+ if (!bl)
{
- sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.",bgTypeID);
+ sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
continue;
}
- MaxPlayersPerTeam = bl->maxplayersperteam;
- MinPlayersPerTeam = bl->maxplayersperteam/2;
- MinLvl = bl->minlvl;
- MaxLvl = bl->maxlvl;
-
- if(fields[1].GetUInt32())
- MinPlayersPerTeam = fields[1].GetUInt32();
-
- if(fields[2].GetUInt32())
- MaxPlayersPerTeam = fields[2].GetUInt32();
-
- if(fields[3].GetUInt32())
- MinLvl = fields[3].GetUInt32();
+ BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
- if(fields[4].GetUInt32())
- MaxLvl = fields[4].GetUInt32();
+ IsArena = (bl->type == TYPE_ARENA);
+ MinPlayersPerTeam = fields[1].GetUInt32();
+ MaxPlayersPerTeam = fields[2].GetUInt32();
+ MinLvl = fields[3].GetUInt32();
+ MaxLvl = fields[4].GetUInt32();
+ //check values from DB
+ if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam)
+ {
+ MaxPlayersPerTeam = bl->maxplayersperteam;
+ MinPlayersPerTeam = bl->maxplayersperteam / 2;
+ }
+ if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl)
+ {
+ MinLvl = bl->minlvl;
+ MaxLvl = bl->maxlvl;
+ }
start1 = fields[5].GetUInt32();
start = sWorldSafeLocsStore.LookupEntry(start1);
- if(start)
+ if (start)
{
AStartLoc[0] = start->x;
AStartLoc[1] = start->y;
AStartLoc[2] = start->z;
AStartLoc[3] = fields[6].GetFloat();
}
- else if(bgTypeID == BATTLEGROUND_AA)
+ else if (bgTypeID == BATTLEGROUND_AA)
{
AStartLoc[0] = 0;
AStartLoc[1] = 0;
@@ -1501,21 +1711,21 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
}
else
{
- sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.",bgTypeID,start1);
+ sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
continue;
}
start2 = fields[7].GetUInt32();
start = sWorldSafeLocsStore.LookupEntry(start2);
- if(start)
+ if (start)
{
HStartLoc[0] = start->x;
HStartLoc[1] = start->y;
HStartLoc[2] = start->z;
HStartLoc[3] = fields[8].GetFloat();
}
- else if(bgTypeID == BATTLEGROUND_AA)
+ else if (bgTypeID == BATTLEGROUND_AA)
{
HStartLoc[0] = 0;
HStartLoc[1] = 0;
@@ -1524,12 +1734,12 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
}
else
{
- sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.",bgTypeID,start2);
+ sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
continue;
}
//sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
- if(!CreateBattleGround(bgTypeID, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3]))
+ if (!CreateBattleGround(bgTypeID, IsArena, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3]))
continue;
++count;
@@ -1543,11 +1753,11 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
void BattleGroundMgr::InitAutomaticArenaPointDistribution()
{
- if(m_AutoDistributePoints)
+ if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
{
sLog.outDebug("Initializing Automatic Arena Point Distribution");
QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
- if(!result)
+ if (!result)
{
sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
@@ -1555,7 +1765,7 @@ void BattleGroundMgr::InitAutomaticArenaPointDistribution()
}
else
{
- m_NextAutoDistributionTime = (*result)[0].GetUInt64();
+ m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64());
delete result;
}
sLog.outDebug("Automatic Arena Point Distribution initialized.");
@@ -1565,9 +1775,9 @@ void BattleGroundMgr::InitAutomaticArenaPointDistribution()
void BattleGroundMgr::DistributeArenaPoints()
{
// used to distribute arena points based on last week's stats
- sWorld.SendGlobalText("Flushing Arena points based on team ratings, this may take a few minutes. Please stand by...", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
- sWorld.SendGlobalText("Distributing arena points to players...", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
//temporary structure for storing maximum points to add values for all players
std::map<uint32, uint32> PlayerPoints;
@@ -1575,7 +1785,7 @@ void BattleGroundMgr::DistributeArenaPoints()
//at first update all points for all team members
for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
{
- if(ArenaTeam * at = team_itr->second)
+ if (ArenaTeam * at = team_itr->second)
{
at->UpdateArenaPointsHelper(PlayerPoints);
}
@@ -1585,7 +1795,7 @@ void BattleGroundMgr::DistributeArenaPoints()
for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
{
//update to database
- CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE `guid` = '%u'", plr_itr->second, plr_itr->first);
+ CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
//add points if player is online
Player* pl = objmgr.GetPlayer(plr_itr->first);
if (pl)
@@ -1594,12 +1804,12 @@ void BattleGroundMgr::DistributeArenaPoints()
PlayerPoints.clear();
- sWorld.SendGlobalText("Finished setting arena points for online players.", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
- sWorld.SendGlobalText("Modifying played count, arena points etc. for loaded arena teams, sending updated stats to online players...", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
{
- if(ArenaTeam * at = titr->second)
+ if (ArenaTeam * at = titr->second)
{
at->FinishWeek(); // set played this week etc values to 0 in memory, too
at->SaveToDB(); // save changes
@@ -1607,17 +1817,18 @@ void BattleGroundMgr::DistributeArenaPoints()
}
}
- sWorld.SendGlobalText("Modification done.", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
- sWorld.SendGlobalText("Done flushing Arena points.", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
}
-void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId)
+void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId)
{
- uint32 PlayerLevel = 10;
+ if (!plr)
+ return;
- if(plr)
- PlayerLevel = plr->getLevel();
+ uint32 PlayerLevel = 10;
+ PlayerLevel = plr->getLevel();
data->Initialize(SMSG_BATTLEFIELD_LIST);
*data << uint64(guid); // battlemaster guid
@@ -1635,27 +1846,25 @@ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid
uint32 count = 0;
*data << uint32(0x00); // number of bg instances
- for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
+ uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bgTypeId);
+ for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr)
{
- if(itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel()))
- {
- *data << uint32(itr->second->GetInstanceID());
- ++count;
- }
+ *data << uint32(*itr);
+ ++count;
}
data->put<uint32>( count_pos , count);
}
}
-void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
+void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
{
- BattleGround *bg = GetBattleGround(instanceId);
- if(bg)
+ BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
+ if (bg)
{
uint32 mapid = bg->GetMapId();
float x, y, z, O;
uint32 team = pl->GetBGTeam();
- if(team==0)
+ if (team==0)
team = pl->GetTeam();
bg->GetTeamStartLoc(team, x, y, z, O);
@@ -1668,24 +1877,17 @@ void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
}
}
-void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid)
+void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
{
WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
- if(time_ == uint32(-1))
+ if (time_ == uint32(-1))
time_ = 0;
data << guid << time_;
pl->GetSession()->SendPacket(&data);
}
-void BattleGroundMgr::RemoveBattleGround(uint32 instanceID)
-{
- BattleGroundSet::iterator itr = m_BattleGrounds.find(instanceID);
- if(itr!=m_BattleGrounds.end())
- m_BattleGrounds.erase(itr);
-}
-
-bool BattleGroundMgr::IsArenaType(uint32 bgTypeId) const
+bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
{
return ( bgTypeId == BATTLEGROUND_AA ||
bgTypeId == BATTLEGROUND_BE ||
@@ -1693,96 +1895,169 @@ bool BattleGroundMgr::IsArenaType(uint32 bgTypeId) const
bgTypeId == BATTLEGROUND_RL );
}
-bool BattleGroundMgr::IsBattleGroundType(uint32 bgTypeId) const
-{
- return !IsArenaType(bgTypeId);
-}
-
-uint32 BattleGroundMgr::BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const
+BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
{
switch(bgTypeId)
{
- case BATTLEGROUND_WS:
- return BATTLEGROUND_QUEUE_WS;
- case BATTLEGROUND_AB:
- return BATTLEGROUND_QUEUE_AB;
- case BATTLEGROUND_AV:
- return BATTLEGROUND_QUEUE_AV;
- case BATTLEGROUND_EY:
- return BATTLEGROUND_QUEUE_EY;
- case BATTLEGROUND_AA:
- case BATTLEGROUND_NA:
- case BATTLEGROUND_RL:
- case BATTLEGROUND_BE:
- switch(arenaType)
- {
- case ARENA_TYPE_2v2:
- return BATTLEGROUND_QUEUE_2v2;
- case ARENA_TYPE_3v3:
- return BATTLEGROUND_QUEUE_3v3;
- case ARENA_TYPE_5v5:
- return BATTLEGROUND_QUEUE_5v5;
+ case BATTLEGROUND_WS:
+ return BATTLEGROUND_QUEUE_WS;
+ case BATTLEGROUND_AB:
+ return BATTLEGROUND_QUEUE_AB;
+ case BATTLEGROUND_AV:
+ return BATTLEGROUND_QUEUE_AV;
+ case BATTLEGROUND_EY:
+ return BATTLEGROUND_QUEUE_EY;
+ case BATTLEGROUND_SA:
+ return BATTLEGROUND_QUEUE_SA;
+ case BATTLEGROUND_AA:
+ case BATTLEGROUND_NA:
+ case BATTLEGROUND_RL:
+ case BATTLEGROUND_BE:
+ case BATTLEGROUND_DS:
+ case BATTLEGROUND_RV:
+ switch(arenaType)
+ {
+ case ARENA_TYPE_2v2:
+ return BATTLEGROUND_QUEUE_2v2;
+ case ARENA_TYPE_3v3:
+ return BATTLEGROUND_QUEUE_3v3;
+ case ARENA_TYPE_5v5:
+ return BATTLEGROUND_QUEUE_5v5;
+ default:
+ return BATTLEGROUND_QUEUE_NONE;
+ }
default:
- return 0;
- }
- default:
- return 0;
+ return BATTLEGROUND_QUEUE_NONE;
}
}
-uint32 BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId) const
+BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
{
switch(bgQueueTypeId)
{
- case BATTLEGROUND_QUEUE_WS:
- return BATTLEGROUND_WS;
- case BATTLEGROUND_QUEUE_AB:
- return BATTLEGROUND_AB;
- case BATTLEGROUND_QUEUE_AV:
- return BATTLEGROUND_AV;
- case BATTLEGROUND_QUEUE_EY:
- return BATTLEGROUND_EY;
- case BATTLEGROUND_QUEUE_2v2:
- case BATTLEGROUND_QUEUE_3v3:
- case BATTLEGROUND_QUEUE_5v5:
- return BATTLEGROUND_AA;
- default:
- return 0;
+ case BATTLEGROUND_QUEUE_WS:
+ return BATTLEGROUND_WS;
+ case BATTLEGROUND_QUEUE_AB:
+ return BATTLEGROUND_AB;
+ case BATTLEGROUND_QUEUE_AV:
+ return BATTLEGROUND_AV;
+ case BATTLEGROUND_QUEUE_EY:
+ return BATTLEGROUND_EY;
+ case BATTLEGROUND_QUEUE_SA:
+ return BATTLEGROUND_SA;
+ case BATTLEGROUND_QUEUE_2v2:
+ case BATTLEGROUND_QUEUE_3v3:
+ case BATTLEGROUND_QUEUE_5v5:
+ return BATTLEGROUND_AA;
+ default:
+ return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
}
}
-uint8 BattleGroundMgr::BGArenaType(uint32 bgQueueTypeId) const
+uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
{
switch(bgQueueTypeId)
{
- case BATTLEGROUND_QUEUE_2v2:
- return ARENA_TYPE_2v2;
- case BATTLEGROUND_QUEUE_3v3:
- return ARENA_TYPE_3v3;
- case BATTLEGROUND_QUEUE_5v5:
- return ARENA_TYPE_5v5;
- default:
- return 0;
+ case BATTLEGROUND_QUEUE_2v2:
+ return ARENA_TYPE_2v2;
+ case BATTLEGROUND_QUEUE_3v3:
+ return ARENA_TYPE_3v3;
+ case BATTLEGROUND_QUEUE_5v5:
+ return ARENA_TYPE_5v5;
+ default:
+ return 0;
}
}
+void BattleGroundMgr::ToggleTesting()
+{
+ m_Testing = !m_Testing;
+ if (m_Testing)
+ sWorld.SendWorldText(LANG_DEBUG_BG_ON);
+ else
+ sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
+}
+
void BattleGroundMgr::ToggleArenaTesting()
{
m_ArenaTesting = !m_ArenaTesting;
- if(m_ArenaTesting)
- sWorld.SendGlobalText("Arenas are set to 1v1 for debugging. So, don't join as group.", NULL);
+ if (m_ArenaTesting)
+ sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
else
- sWorld.SendGlobalText("Arenas are set to normal playercount.", NULL);
+ sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
}
void BattleGroundMgr::SetHolidayWeekends(uint32 mask)
{
- for(uint32 bgtype = 1; bgtype <= 8; ++bgtype)
+ for(uint32 bgtype = 1; bgtype < MAX_BATTLEGROUND_TYPE_ID; ++bgtype)
{
- if(BattleGround * bg = GetBattleGroundTemplate(bgtype))
+ if(BattleGround * bg = GetBattleGroundTemplate(BattleGroundTypeId(bgtype)))
{
bg->SetHoliday(mask & (1 << bgtype));
}
}
}
+uint32 BattleGroundMgr::GetMaxRatingDifference() const
+{
+ // this is for stupid people who can't use brain and set max rating difference to 0
+ uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
+ if (diff == 0)
+ diff = 5000;
+ return diff;
+}
+
+uint32 BattleGroundMgr::GetRatingDiscardTimer() const
+{
+ return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
+}
+
+uint32 BattleGroundMgr::GetPrematureFinishTime() const
+{
+ return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
+}
+
+void BattleGroundMgr::LoadBattleMastersEntry()
+{
+ mBattleMastersMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ ++count;
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 entry = fields[0].GetUInt32();
+ uint32 bgTypeId = fields[1].GetUInt32();
+ if (!sBattlemasterListStore.LookupEntry(bgTypeId))
+ {
+ sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
+ continue;
+ }
+
+ mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
+
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u battlemaster entries", count );
+}
diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h
index 5edcc1457d3..d9cc9deae13 100644
--- a/src/game/BattleGroundMgr.h
+++ b/src/game/BattleGroundMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,30 +21,23 @@
#ifndef __BATTLEGROUNDMGR_H
#define __BATTLEGROUNDMGR_H
-#include "BattleGround.h"
+#include "Common.h"
#include "Policies/Singleton.h"
+#include "BattleGround.h"
-class BattleGround;
-
-//TODO it is not possible to have this structure, because we should have BattlegroundSet for each queue
-//so i propose to change this type to array 1..MAX_BATTLEGROUND_TYPES of sets or maps..
typedef std::map<uint32, BattleGround*> BattleGroundSet;
-//typedef std::map<uint32, BattleGroundQueue*> BattleGroundQueueSet;
-typedef std::deque<BattleGround*> BGFreeSlotQueueType;
-#define MAX_BATTLEGROUND_QUEUES 7 // for level ranges 10-19, 20-29, 30-39, 40-49, 50-59, 60-69, 70+
+//this container can't be deque, because deque doesn't like removing the last element - if you remove it, it invalidates next iterator and crash appears
+typedef std::list<BattleGround*> BGFreeSlotQueueType;
-#define MAX_BATTLEGROUND_TYPES 9 // each BG type will be in array
+typedef UNORDERED_MAP<uint32, BattleGroundTypeId> BattleMastersMap;
-#define MAX_BATTLEGROUND_QUEUE_TYPES 8
-
-#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day
+#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day
+#define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME 10
struct GroupQueueInfo; // type predefinition
struct PlayerQueueInfo // stores information for players in queue
{
- uint32 InviteTime; // first invite time
- uint32 LastInviteTime; // last invite time
uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes
GroupQueueInfo * GroupInfo; // pointer to the associated groupqueueinfo
};
@@ -53,16 +46,26 @@ struct GroupQueueInfo // stores informatio
{
std::map<uint64, PlayerQueueInfo*> Players; // player queue info map
uint32 Team; // Player team (ALLIANCE/HORDE)
- uint32 BgTypeId; // battleground type id
+ BattleGroundTypeId BgTypeId; // battleground type id
bool IsRated; // rated
uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG
uint32 ArenaTeamId; // team id if rated match
uint32 JoinTime; // time when group was added
+ uint32 RemoveInviteTime; // time when we will remove invite for players in group
uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG
uint32 ArenaTeamRating; // if rated match, inited to the rating of the team
uint32 OpponentsTeamRating; // for rated arena matches
};
+enum BattleGroundQueueGroupTypes
+{
+ BG_QUEUE_PREMADE_ALLIANCE = 0,
+ BG_QUEUE_PREMADE_HORDE = 1,
+ BG_QUEUE_NORMAL_ALLIANCE = 2,
+ BG_QUEUE_NORMAL_HORDE = 3
+};
+#define BG_QUEUE_GROUP_TYPES_COUNT 4
+
class BattleGround;
class BattleGroundQueue
{
@@ -70,64 +73,61 @@ class BattleGroundQueue
BattleGroundQueue();
~BattleGroundQueue();
- void Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype = 0, bool isRated = false, uint32 minRating = 0);
+ void Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType = 0, bool isRated = false, uint32 minRating = 0);
- GroupQueueInfo * AddGroup(Player * leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 ArenaRating, uint32 ArenaTeamId = 0);
+ void FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id);
+ bool CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam);
+ bool CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers);
+ bool CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam);
+ GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0);
void AddPlayer(Player *plr, GroupQueueInfo *ginfo);
- void RemovePlayer(uint64 guid, bool decreaseInvitedCount);
+ void RemovePlayer(const uint64& guid, bool decreaseInvitedCount);
+ void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id);
+ uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id);
+
void DecreaseGroupLength(uint32 queueId, uint32 AsGroup);
- void BGEndedRemoveInvites(BattleGround * bg);
+ void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue);
typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap;
- QueuedPlayersMap m_QueuedPlayers[MAX_BATTLEGROUND_QUEUES];
-
- typedef std::list<GroupQueueInfo*> QueuedGroupsList;
- QueuedGroupsList m_QueuedGroups[MAX_BATTLEGROUND_QUEUES];
-
- // class to hold pointers to the groups eligible for a specific selection pool building mode
- class EligibleGroups : public std::list<GroupQueueInfo *>
- {
- public:
- void Init(QueuedGroupsList * source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType = 0, bool IsRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0, uint32 excludeTeam = 0);
- };
-
- EligibleGroups m_EligibleGroups;
+ QueuedPlayersMap m_QueuedPlayers;
+
+ //we need constant add to begin and constant remove / add from the end, therefore deque suits our problem well
+ typedef std::list<GroupQueueInfo*> GroupsQueueType;
+
+ /*
+ This two dimensional array is used to store All queued groups
+ First dimension specifies the bgTypeId
+ Second dimension specifies the player's group types -
+ BG_QUEUE_PREMADE_ALLIANCE is used for premade alliance groups and alliance rated arena teams
+ BG_QUEUE_PREMADE_HORDE is used for premade horde groups and horde rated arena teams
+ BG_QUEUE_NORMAL_ALLIANCE is used for normal (or small) alliance groups or non-rated arena matches
+ BG_QUEUE_NORMAL_HORDE is used for normal (or small) horde groups or non-rated arena matches
+ */
+ GroupsQueueType m_QueuedGroups[MAX_BATTLEGROUND_QUEUES][BG_QUEUE_GROUP_TYPES_COUNT];
// class to select and invite groups to bg
class SelectionPool
{
public:
- void Init(EligibleGroups * curr);
- void AddGroup(GroupQueueInfo * group);
- void RemoveGroup(GroupQueueInfo * group);
+ void Init();
+ bool AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount);
+ bool KickGroup(uint32 size);
uint32 GetPlayerCount() const {return PlayerCount;}
- bool Build(uint32 MinPlayers, uint32 MaxPlayers, EligibleGroups::iterator startitr);
public:
- std::list<GroupQueueInfo *> SelectedGroups;
+ GroupsQueueType SelectedGroups;
private:
uint32 PlayerCount;
- EligibleGroups * m_CurrEligGroups;
- };
-
- enum SelectionPoolBuildMode
- {
- NORMAL_ALLIANCE,
- NORMAL_HORDE,
- ONESIDE_ALLIANCE_TEAM1,
- ONESIDE_ALLIANCE_TEAM2,
- ONESIDE_HORDE_TEAM1,
- ONESIDE_HORDE_TEAM2,
-
- NUM_SELECTION_POOL_TYPES
};
- SelectionPool m_SelectionPools[NUM_SELECTION_POOL_TYPES];
-
- bool BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType = 0, bool isRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0, uint32 excludeTeam = 0);
+ //one selection pool for horde, other one for alliance
+ SelectionPool m_SelectionPools[BG_TEAMS_COUNT];
private:
bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side);
+ uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
+ uint32 m_WaitTimeLastPlayer[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES];
+ uint32 m_SumOfWaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES];
};
/*
@@ -137,7 +137,10 @@ class BattleGroundQueue
class BGQueueInviteEvent : public BasicEvent
{
public:
- BGQueueInviteEvent(uint64 pl_guid, uint32 BgInstanceGUID) : m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID) {};
+ BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId, uint32 removeTime) :
+ m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId), m_RemoveTime(removeTime)
+ {
+ };
virtual ~BGQueueInviteEvent() {};
virtual bool Execute(uint64 e_time, uint32 p_time);
@@ -145,23 +148,32 @@ class BGQueueInviteEvent : public BasicEvent
private:
uint64 m_PlayerGuid;
uint32 m_BgInstanceGUID;
+ uint32 m_RemoveTime;
+ BattleGroundTypeId m_BgTypeId;
};
/*
- This class is used to remove player from BG queue after 2 minutes from first invitation
+ This class is used to remove player from BG queue after 1 minute 20 seconds from first invitation
+ We must store removeInvite time in case player left queue and joined and is invited again
+ We must store bgQueueTypeId, because battleground can be deleted already, when player entered it
*/
class BGQueueRemoveEvent : public BasicEvent
{
public:
- BGQueueRemoveEvent(uint64 pl_guid, uint32 bgInstanceGUID, uint32 playersTeam) : m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_PlayersTeam(playersTeam) {};
- virtual ~BGQueueRemoveEvent() {};
+ BGQueueRemoveEvent(const uint64& pl_guid, uint32 bgInstanceGUID, BattleGroundTypeId BgTypeId, BattleGroundQueueTypeId bgQueueTypeId, uint32 removeTime)
+ : m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_RemoveTime(removeTime), m_BgTypeId(BgTypeId), m_BgQueueTypeId(bgQueueTypeId)
+ {}
+
+ virtual ~BGQueueRemoveEvent() {}
virtual bool Execute(uint64 e_time, uint32 p_time);
virtual void Abort(uint64 e_time);
private:
uint64 m_PlayerGuid;
uint32 m_BgInstanceGUID;
- uint32 m_PlayersTeam;
+ uint32 m_RemoveTime;
+ BattleGroundTypeId m_BgTypeId;
+ BattleGroundQueueTypeId m_BgQueueTypeId;
};
class BattleGroundMgr
@@ -170,83 +182,81 @@ class BattleGroundMgr
/* Construction */
BattleGroundMgr();
~BattleGroundMgr();
- void Update(time_t diff);
+ void Update(uint32 diff);
/* Packet Building */
void BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr);
- void BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr);
- void BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player *plr, uint32 bgTypeId);
- void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId);
+ void BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid);
+ void BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player *plr, BattleGroundTypeId bgTypeId);
+ void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId);
void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value);
void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg);
- void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0, uint8 israted = 0);
+ void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype);
void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid);
-
- /* Player invitation */
- // called from Queue update, or from Addplayer to queue
- void InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team);
+ void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid);
/* Battlegrounds */
- BattleGroundSet::iterator GetBattleGroundsBegin() { return m_BattleGrounds.begin(); };
- BattleGroundSet::iterator GetBattleGroundsEnd() { return m_BattleGrounds.end(); };
+ BattleGround* GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId);
+ BattleGround* GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId); //there must be uint32 because MAX_BATTLEGROUND_TYPE_ID means unknown
- BattleGround* GetBattleGround(uint32 ID)
- {
- BattleGroundSet::iterator i = m_BattleGrounds.find(ID);
- if(i != m_BattleGrounds.end())
- return i->second;
- else
- return NULL;
- };
-
- BattleGround * GetBattleGroundTemplate(uint32 bgTypeId);
- BattleGround * CreateNewBattleGround(uint32 bgTypeId);
+ BattleGround* GetBattleGroundTemplate(BattleGroundTypeId bgTypeId);
+ BattleGround* CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated);
- uint32 CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO);
+ uint32 CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO);
- inline void AddBattleGround(uint32 ID, BattleGround* BG) { m_BattleGrounds[ID] = BG; };
- void RemoveBattleGround(uint32 instanceID);
+ void AddBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId, BattleGround* BG) { m_BattleGrounds[bgTypeId][InstanceID] = BG; };
+ void RemoveBattleGround(uint32 instanceID, BattleGroundTypeId bgTypeId) { m_BattleGrounds[bgTypeId].erase(instanceID); }
+ uint32 CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id);
void CreateInitialBattleGrounds();
+ void DeleteAllBattleGrounds();
- void SendToBattleGround(Player *pl, uint32 bgTypeId);
+ void SendToBattleGround(Player *pl, uint32 InstanceID, BattleGroundTypeId bgTypeId);
/* Battleground queues */
//these queues are instantiated when creating BattlegroundMrg
BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES]; // public, because we need to access them in BG handler code
- BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPES];
+ BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPE_ID];
- void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid);
-
- bool IsArenaType(uint32 bgTypeId) const;
- bool IsBattleGroundType(uint32 bgTypeId) const;
- uint32 BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const;
- uint32 BGTemplateId(uint32 bgQueueTypeId) const;
- uint8 BGArenaType(uint32 bgQueueTypeId) const;
-
- uint32 GetMaxRatingDifference() const {return m_MaxRatingDifference;}
- uint32 GetRatingDiscardTimer() const {return m_RatingDiscardTimer;}
+ uint32 GetMaxRatingDifference() const;
+ uint32 GetRatingDiscardTimer() const;
+ uint32 GetPrematureFinishTime() const;
void InitAutomaticArenaPointDistribution();
void DistributeArenaPoints();
- uint32 GetPrematureFinishTime() const {return m_PrematureFinishTimer;}
void ToggleArenaTesting();
- const bool isArenaTesting() const { return m_ArenaTesting; }
+ void ToggleTesting();
void SetHolidayWeekends(uint32 mask);
+ void LoadBattleMastersEntry();
+ BattleGroundTypeId GetBattleMasterBG(uint32 entry) const
+ {
+ BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry);
+ if (itr != mBattleMastersMap.end())
+ return itr->second;
+ return BATTLEGROUND_WS;
+ }
+
+ bool isArenaTesting() const { return m_ArenaTesting; }
+ bool isTesting() const { return m_Testing; }
+
+ static bool IsArenaType(BattleGroundTypeId bgTypeId);
+ static bool IsBattleGroundType(BattleGroundTypeId bgTypeId) { return !BattleGroundMgr::IsArenaType(bgTypeId); }
+ static BattleGroundQueueTypeId BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType);
+ static BattleGroundTypeId BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId);
+ static uint8 BGArenaType(BattleGroundQueueTypeId bgQueueTypeId);
private:
+ BattleMastersMap mBattleMastersMap;
/* Battlegrounds */
- BattleGroundSet m_BattleGrounds;
- uint32 m_MaxRatingDifference;
- uint32 m_RatingDiscardTimer;
+ BattleGroundSet m_BattleGrounds[MAX_BATTLEGROUND_TYPE_ID];
+ std::set<uint32> m_ClientBattleGroundIds[MAX_BATTLEGROUND_TYPE_ID][MAX_BATTLEGROUND_QUEUES]; //the instanceids just visible for the client
uint32 m_NextRatingDiscardUpdate;
- bool m_AutoDistributePoints;
- uint64 m_NextAutoDistributionTime;
+ time_t m_NextAutoDistributionTime;
uint32 m_AutoDistributionTimeChecker;
- uint32 m_PrematureFinishTimer;
bool m_ArenaTesting;
+ bool m_Testing;
};
#define sBattleGroundMgr Trinity::Singleton<BattleGroundMgr>::Instance()
diff --git a/src/game/BattleGroundNA.cpp b/src/game/BattleGroundNA.cpp
index 5debaa3c6a5..f46746829e7 100644
--- a/src/game/BattleGroundNA.cpp
+++ b/src/game/BattleGroundNA.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,14 +22,23 @@
#include "Player.h"
#include "BattleGround.h"
#include "BattleGroundNA.h"
-#include "Creature.h"
#include "ObjectMgr.h"
-#include "MapManager.h"
+#include "WorldPacket.h"
#include "Language.h"
BattleGroundNA::BattleGroundNA()
{
m_BgObjects.resize(BG_NA_OBJECT_MAX);
+
+ m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
+ m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
+ m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
+ m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
+ //we must set messageIds
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
}
BattleGroundNA::~BattleGroundNA()
@@ -37,74 +46,31 @@ BattleGroundNA::~BattleGroundNA()
}
-void BattleGroundNA::Update(time_t diff)
+void BattleGroundNA::Update(uint32 diff)
{
BattleGround::Update(diff);
- // after bg start we get there
- if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
- {
- ModifyStartDelayTime(diff);
-
- if (!(m_Events & 0x01))
- {
- m_Events |= 0x01;
- // setup here, only when at least one player has ported to the map
- if(!SetupBattleGround())
- {
- EndNow();
- return;
- }
- for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; i++)
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
-
- SetStartDelayTime(START_DELAY1);
- SendMessageToAll(LANG_ARENA_ONE_MINUTE);
- }
- // After 30 seconds, warning is signalled
- else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04))
- {
- m_Events |= 0x04;
- SendMessageToAll(LANG_ARENA_THIRTY_SECONDS);
- }
- // After 15 seconds, warning is signalled
- else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08))
- {
- m_Events |= 0x08;
- SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS);
- }
- // delay expired (1 minute)
- else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
- {
- m_Events |= 0x10;
-
- for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; i++)
- DoorOpen(i);
-
- for(uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; i++)
- SpawnBGObject(i, 60);
-
- SendMessageToAll(LANG_ARENA_BEGUN);
- SetStatus(STATUS_IN_PROGRESS);
- SetStartDelayTime(0);
-
- for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if(Player *plr = objmgr.GetPlayer(itr->first))
- plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
-
- if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
- EndBattleGround(HORDE);
- else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
- EndBattleGround(ALLIANCE);
- }
- }
-
- /*if(GetStatus() == STATUS_IN_PROGRESS)
+ /*if (GetStatus() == STATUS_IN_PROGRESS)
{
// update something
}*/
}
+void BattleGroundNA::StartingEventCloseDoors()
+{
+ for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; ++i)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+}
+
+void BattleGroundNA::StartingEventOpenDoors()
+{
+ for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; ++i)
+ DoorOpen(i);
+
+ for(uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; ++i)
+ SpawnBGObject(i, 60);
+}
+
void BattleGroundNA::AddPlayer(Player *plr)
{
BattleGround::AddPlayer(plr);
@@ -119,24 +85,21 @@ void BattleGroundNA::AddPlayer(Player *plr)
void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/)
{
- if(GetStatus() == STATUS_WAIT_LEAVE)
+ if (GetStatus() == STATUS_WAIT_LEAVE)
return;
UpdateWorldState(0xa0f, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xa10, GetAlivePlayersCountByTeam(HORDE));
- if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
- EndBattleGround(HORDE);
- else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
- EndBattleGround(ALLIANCE);
+ CheckArenaWinConditions();
}
void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
- if(!killer)
+ if (!killer)
{
sLog.outError("BattleGroundNA: Killer player not found");
return;
@@ -147,16 +110,7 @@ void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)
UpdateWorldState(0xa0f, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xa10, GetAlivePlayersCountByTeam(HORDE));
- if(!GetAlivePlayersCountByTeam(ALLIANCE))
- {
- // all opponents killed
- EndBattleGround(HORDE);
- }
- else if(!GetAlivePlayersCountByTeam(HORDE))
- {
- // all opponents killed
- EndBattleGround(ALLIANCE);
- }
+ CheckArenaWinConditions();
}
bool BattleGroundNA::HandlePlayerUnderMap(Player *player)
@@ -167,7 +121,7 @@ bool BattleGroundNA::HandlePlayerUnderMap(Player *player)
void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
//uint32 SpellId = 0;
@@ -183,7 +137,7 @@ void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger)
break;
}
- //if(buff_guid)
+ //if (buff_guid)
// HandleTriggerBuff(buff_guid,Source);
}
@@ -194,15 +148,16 @@ void BattleGroundNA::FillInitialWorldStates(WorldPacket &data)
data << uint32(0xa11) << uint32(1); // 9
}
-void BattleGroundNA::ResetBGSubclass()
+void BattleGroundNA::Reset()
{
-
+ //call parent's class reset
+ BattleGround::Reset();
}
bool BattleGroundNA::SetupBattleGround()
{
// gates
- if( !AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY)
+ if (!AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179, 2874.97, 12.39171, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709, 2981.777, 10.70117, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY)
diff --git a/src/game/BattleGroundNA.h b/src/game/BattleGroundNA.h
index ae419b9fc44..56e2cf373c4 100644
--- a/src/game/BattleGroundNA.h
+++ b/src/game/BattleGroundNA.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,15 +58,17 @@ class BattleGroundNA : public BattleGround
public:
BattleGroundNA();
~BattleGroundNA();
- void Update(time_t diff);
+ void Update(uint32 diff);
/* inherited from BattlegroundClass */
virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
void RemovePlayer(Player *plr, uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
- virtual void ResetBGSubclass();
+ virtual void Reset();
virtual void FillInitialWorldStates(WorldPacket &d);
void HandleKillPlayer(Player* player, Player *killer);
bool HandlePlayerUnderMap(Player * plr);
diff --git a/src/game/BattleGroundRL.cpp b/src/game/BattleGroundRL.cpp
index 6d68403fe4c..f8f8bd9fef5 100644
--- a/src/game/BattleGroundRL.cpp
+++ b/src/game/BattleGroundRL.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,14 +22,23 @@
#include "Player.h"
#include "BattleGround.h"
#include "BattleGroundRL.h"
-#include "Creature.h"
#include "ObjectMgr.h"
-#include "MapManager.h"
#include "Language.h"
+#include "WorldPacket.h"
BattleGroundRL::BattleGroundRL()
{
m_BgObjects.resize(BG_RL_OBJECT_MAX);
+
+ m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
+ m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
+ m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
+ m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
+ //we must set messageIds
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
}
BattleGroundRL::~BattleGroundRL()
@@ -37,75 +46,31 @@ BattleGroundRL::~BattleGroundRL()
}
-void BattleGroundRL::Update(time_t diff)
+void BattleGroundRL::Update(uint32 diff)
{
BattleGround::Update(diff);
- if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
- {
- ModifyStartDelayTime(diff);
-
- if (!(m_Events & 0x01))
- {
- m_Events |= 0x01;
-
- // setup here, only when at least one player has ported to the map
- if(!SetupBattleGround())
- {
- EndNow();
- return;
- }
-
- for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++)
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
-
- SetStartDelayTime(START_DELAY1);
- SendMessageToAll(LANG_ARENA_ONE_MINUTE);
- }
- // After 30 seconds, warning is signalled
- else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04))
- {
- m_Events |= 0x04;
- SendMessageToAll(LANG_ARENA_THIRTY_SECONDS);
- }
- // After 15 seconds, warning is signalled
- else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08))
- {
- m_Events |= 0x08;
- SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS);
- }
- // delay expired (1 minute)
- else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
- {
- m_Events |= 0x10;
-
- for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++)
- DoorOpen(i);
-
- for(uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; i++)
- SpawnBGObject(i, 60);
-
- SendMessageToAll(LANG_ARENA_BEGUN);
- SetStatus(STATUS_IN_PROGRESS);
- SetStartDelayTime(0);
-
- for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if(Player *plr = objmgr.GetPlayer(itr->first))
- plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
-
- if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
- EndBattleGround(HORDE);
- else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))
- EndBattleGround(ALLIANCE);
- }
- }
-
- /*if(GetStatus() == STATUS_IN_PROGRESS)
+ /*if (GetStatus() == STATUS_IN_PROGRESS)
{
// update something
}*/
}
+void BattleGroundRL::StartingEventCloseDoors()
+{
+ for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+}
+
+void BattleGroundRL::StartingEventOpenDoors()
+{
+ for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i)
+ DoorOpen(i);
+
+ for(uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; ++i)
+ SpawnBGObject(i, 60);
+}
+
void BattleGroundRL::AddPlayer(Player *plr)
{
BattleGround::AddPlayer(plr);
@@ -120,24 +85,21 @@ void BattleGroundRL::AddPlayer(Player *plr)
void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/)
{
- if(GetStatus() == STATUS_WAIT_LEAVE)
+ if (GetStatus() == STATUS_WAIT_LEAVE)
return;
UpdateWorldState(0xbb8, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xbb9, GetAlivePlayersCountByTeam(HORDE));
- if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
- EndBattleGround(HORDE);
- else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
- EndBattleGround(ALLIANCE);
+ CheckArenaWinConditions();
}
void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
- if(!killer)
+ if (!killer)
{
sLog.outError("Killer player not found");
return;
@@ -148,16 +110,7 @@ void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)
UpdateWorldState(0xbb8, GetAlivePlayersCountByTeam(ALLIANCE));
UpdateWorldState(0xbb9, GetAlivePlayersCountByTeam(HORDE));
- if(!GetAlivePlayersCountByTeam(ALLIANCE))
- {
- // all opponents killed
- EndBattleGround(HORDE);
- }
- else if(!GetAlivePlayersCountByTeam(HORDE))
- {
- // all opponents killed
- EndBattleGround(ALLIANCE);
- }
+ CheckArenaWinConditions();
}
bool BattleGroundRL::HandlePlayerUnderMap(Player *player)
@@ -169,7 +122,7 @@ bool BattleGroundRL::HandlePlayerUnderMap(Player *player)
void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger)
{
// this is wrong way to implement these things. On official it done by gameobject spell cast.
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
//uint32 SpellId = 0;
@@ -185,7 +138,7 @@ void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger)
break;
}
- //if(buff_guid)
+ //if (buff_guid)
// HandleTriggerBuff(buff_guid,Source);
}
@@ -196,15 +149,16 @@ void BattleGroundRL::FillInitialWorldStates(WorldPacket &data)
data << uint32(0xbba) << uint32(1); // 9
}
-void BattleGroundRL::ResetBGSubclass()
+void BattleGroundRL::Reset()
{
-
+ //call parent's reset
+ BattleGround::Reset();
}
bool BattleGroundRL::SetupBattleGround()
{
// gates
- if( !AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY)
+ if (!AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY)
// buffs
|| !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971, 1632.719971, 36.730400, -1.448624, 0, 0, 0.6626201, -0.7489557, 120)
diff --git a/src/game/BattleGroundRL.h b/src/game/BattleGroundRL.h
index 599cb53dc63..772c9dd0879 100644
--- a/src/game/BattleGroundRL.h
+++ b/src/game/BattleGroundRL.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,16 +54,18 @@ class BattleGroundRL : public BattleGround
public:
BattleGroundRL();
~BattleGroundRL();
- void Update(time_t diff);
+ void Update(uint32 diff);
/* inherited from BattlegroundClass */
virtual void AddPlayer(Player *plr);
+ virtual void Reset();
+ virtual void FillInitialWorldStates(WorldPacket &d);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
void RemovePlayer(Player *plr, uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
bool SetupBattleGround();
- virtual void ResetBGSubclass();
- virtual void FillInitialWorldStates(WorldPacket &d);
void HandleKillPlayer(Player* player, Player *killer);
bool HandlePlayerUnderMap(Player * plr);
};
diff --git a/src/game/BattleGroundRV.cpp b/src/game/BattleGroundRV.cpp
new file mode 100644
index 00000000000..8c252c35c97
--- /dev/null
+++ b/src/game/BattleGroundRV.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Player.h"
+#include "BattleGround.h"
+#include "BattleGroundRV.h"
+#include "Language.h"
+
+BattleGroundRV::BattleGroundRV()
+{
+
+ m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
+ m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
+ m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
+ m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
+ //we must set messageIds
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
+}
+
+BattleGroundRV::~BattleGroundRV()
+{
+
+}
+
+void BattleGroundRV::Update(uint32 diff)
+{
+ BattleGround::Update(diff);
+}
+
+void BattleGroundRV::StartingEventCloseDoors()
+{
+}
+
+void BattleGroundRV::StartingEventOpenDoors()
+{
+}
+
+void BattleGroundRV::AddPlayer(Player *plr)
+{
+ BattleGround::AddPlayer(plr);
+ //create score and add it to map, default values are set in constructor
+ BattleGroundRVScore* sc = new BattleGroundRVScore;
+
+ m_PlayerScores[plr->GetGUID()] = sc;
+}
+
+void BattleGroundRV::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
+{
+}
+
+void BattleGroundRV::HandleKillPlayer(Player* player, Player* killer)
+{
+ BattleGround::HandleKillPlayer(player, killer);
+}
+
+void BattleGroundRV::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/)
+{
+}
+
+bool BattleGroundRV::SetupBattleGround()
+{
+ return true;
+}
diff --git a/src/game/BattleGroundRV.h b/src/game/BattleGroundRV.h
new file mode 100644
index 00000000000..e3e94baf101
--- /dev/null
+++ b/src/game/BattleGroundRV.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __BATTLEGROUNDRV_H
+#define __BATTLEGROUNDRV_H
+
+class BattleGround;
+
+class BattleGroundRVScore : public BattleGroundScore
+{
+ public:
+ BattleGroundRVScore() {};
+ virtual ~BattleGroundRVScore() {};
+ //TODO fix me
+};
+
+class BattleGroundRV : public BattleGround
+{
+ friend class BattleGroundMgr;
+
+ public:
+ BattleGroundRV();
+ ~BattleGroundRV();
+ void Update(uint32 diff);
+
+ /* inherited from BattlegroundClass */
+ virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
+
+ void RemovePlayer(Player *plr, uint64 guid);
+ void HandleAreaTrigger(Player *Source, uint32 Trigger);
+ bool SetupBattleGround();
+ void HandleKillPlayer(Player* player, Player *killer);
+};
+#endif
diff --git a/src/game/BattleGroundSA.cpp b/src/game/BattleGroundSA.cpp
new file mode 100644
index 00000000000..c52635a04c7
--- /dev/null
+++ b/src/game/BattleGroundSA.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Player.h"
+#include "BattleGround.h"
+#include "BattleGroundSA.h"
+#include "Language.h"
+
+BattleGroundSA::BattleGroundSA()
+{
+ //TODO FIX ME!
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN;
+}
+
+BattleGroundSA::~BattleGroundSA()
+{
+
+}
+
+void BattleGroundSA::Update(uint32 diff)
+{
+ BattleGround::Update(diff);
+}
+
+void BattleGroundSA::StartingEventCloseDoors()
+{
+}
+
+void BattleGroundSA::StartingEventOpenDoors()
+{
+}
+
+void BattleGroundSA::AddPlayer(Player *plr)
+{
+ BattleGround::AddPlayer(plr);
+ //create score and add it to map, default values are set in constructor
+ BattleGroundSAScore* sc = new BattleGroundSAScore;
+
+ m_PlayerScores[plr->GetGUID()] = sc;
+}
+
+void BattleGroundSA::RemovePlayer(Player* /*plr*/,uint64 /*guid*/)
+{
+
+}
+
+void BattleGroundSA::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/)
+{
+ // this is wrong way to implement these things. On official it done by gameobject spell cast.
+ if (GetStatus() != STATUS_IN_PROGRESS)
+ return;
+}
+
+void BattleGroundSA::UpdatePlayerScore(Player* Source, uint32 type, uint32 value)
+{
+
+ std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
+
+ if(itr == m_PlayerScores.end()) // player not found...
+ return;
+
+ BattleGround::UpdatePlayerScore(Source,type,value);
+}
diff --git a/src/game/BattleGroundSA.h b/src/game/BattleGroundSA.h
new file mode 100644
index 00000000000..3ba23d02656
--- /dev/null
+++ b/src/game/BattleGroundSA.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __BATTLEGROUNDSA_H
+#define __BATTLEGROUNDSA_H
+
+class BattleGround;
+
+class BattleGroundSAScore : public BattleGroundScore
+{
+ public:
+ BattleGroundSAScore() {};
+ virtual ~BattleGroundSAScore() {};
+};
+
+class BattleGroundSA : public BattleGround
+{
+ friend class BattleGroundMgr;
+
+ public:
+ BattleGroundSA();
+ ~BattleGroundSA();
+ void Update(uint32 diff);
+
+ /* inherited from BattlegroundClass */
+ virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
+
+ void RemovePlayer(Player *plr,uint64 guid);
+ void HandleAreaTrigger(Player *Source, uint32 Trigger);
+ //bool SetupBattleGround();
+
+ /* Scorekeeping */
+ void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
+
+ private:
+};
+#endif
diff --git a/src/game/BattleGroundWS.cpp b/src/game/BattleGroundWS.cpp
index 3a8c5668a7a..76ecde6527b 100644
--- a/src/game/BattleGroundWS.cpp
+++ b/src/game/BattleGroundWS.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,8 +24,8 @@
#include "BattleGroundWS.h"
#include "Creature.h"
#include "GameObject.h"
-#include "Chat.h"
-#include "MapManager.h"
+#include "ObjectMgr.h"
+#include "WorldPacket.h"
#include "Language.h"
#include "World.h"
@@ -52,123 +52,58 @@ BattleGroundWS::BattleGroundWS()
{
m_BgObjects.resize(BG_WS_OBJECT_MAX);
m_BgCreatures.resize(BG_CREATURES_MAX_WS);
+
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN;
}
BattleGroundWS::~BattleGroundWS()
{
}
-void BattleGroundWS::Update(time_t diff)
+void BattleGroundWS::Update(uint32 diff)
{
BattleGround::Update(diff);
- // after bg start we get there (once)
- if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
- {
- ModifyStartDelayTime(diff);
-
- if(!(m_Events & 0x01))
- {
- m_Events |= 0x01;
-
- // setup here, only when at least one player has ported to the map
- if(!SetupBattleGround())
- {
- EndNow();
- return;
- }
-
-// for(uint32 i = WS_SPIRIT_MAIN_ALLIANCE; i <= WS_SPIRIT_MAIN_HORDE; i++)
-// SpawnBGCreature(i, RESPAWN_IMMEDIATELY);
-
- for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++)
- {
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
- DoorClose(i);
- }
- for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++)
- SpawnBGObject(i, RESPAWN_ONE_DAY);
-
- SetStartDelayTime(START_DELAY0);
- }
- // After 1 minute, warning is signalled
- else if(GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04))
- {
- m_Events |= 0x04;
- SendMessageToAll(GetTrinityString(LANG_BG_WS_ONE_MINUTE));
- }
- // After 1,5 minute, warning is signalled
- else if(GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08))
- {
- m_Events |= 0x08;
- SendMessageToAll(GetTrinityString(LANG_BG_WS_HALF_MINUTE));
- }
- // After 2 minutes, gates OPEN ! x)
- else if(GetStartDelayTime() < 0 && !(m_Events & 0x10))
- {
- m_Events |= 0x10;
- for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; i++)
- DoorOpen(i);
- for(uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; i++)
- DoorOpen(i);
-
- SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY);
- SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY);
- SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY);
- SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY);
-
- for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++)
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
-
- SendMessageToAll(GetTrinityString(LANG_BG_WS_BEGIN));
-
- PlaySoundToAll(SOUND_BG_START);
- if(sWorld.getConfig(CONFIG_BG_START_MUSIC))
- PlaySoundToAll(SOUND_BG_START_L70ETC); //MUSIC - Custom config
- SetStatus(STATUS_IN_PROGRESS);
-
- for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if(Player* plr = objmgr.GetPlayer(itr->first))
- plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
- }
- }
- else if(GetStatus() == STATUS_IN_PROGRESS)
+ if (GetStatus() == STATUS_IN_PROGRESS)
{
- if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN)
+ if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN)
{
m_FlagsTimer[BG_TEAM_ALLIANCE] -= diff;
- if(m_FlagsTimer[BG_TEAM_ALLIANCE] < 0)
+ if (m_FlagsTimer[BG_TEAM_ALLIANCE] < 0)
{
m_FlagsTimer[BG_TEAM_ALLIANCE] = 0;
RespawnFlag(ALLIANCE, true);
}
}
- if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND)
+ if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND)
{
m_FlagsDropTimer[BG_TEAM_ALLIANCE] -= diff;
- if(m_FlagsDropTimer[BG_TEAM_ALLIANCE] < 0)
+ if (m_FlagsDropTimer[BG_TEAM_ALLIANCE] < 0)
{
m_FlagsDropTimer[BG_TEAM_ALLIANCE] = 0;
RespawnFlagAfterDrop(ALLIANCE);
}
}
- if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN)
+ if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN)
{
m_FlagsTimer[BG_TEAM_HORDE] -= diff;
- if(m_FlagsTimer[BG_TEAM_HORDE] < 0)
+ if (m_FlagsTimer[BG_TEAM_HORDE] < 0)
{
m_FlagsTimer[BG_TEAM_HORDE] = 0;
RespawnFlag(HORDE, true);
}
}
- if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND)
+ if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND)
{
m_FlagsDropTimer[BG_TEAM_HORDE] -= diff;
- if(m_FlagsDropTimer[BG_TEAM_HORDE] < 0)
+ if (m_FlagsDropTimer[BG_TEAM_HORDE] < 0)
{
m_FlagsDropTimer[BG_TEAM_HORDE] = 0;
RespawnFlagAfterDrop(HORDE);
@@ -177,6 +112,33 @@ void BattleGroundWS::Update(time_t diff)
}
}
+void BattleGroundWS::StartingEventCloseDoors()
+{
+ for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; ++i)
+ {
+ DoorClose(i);
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ }
+ for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; ++i)
+ SpawnBGObject(i, RESPAWN_ONE_DAY);
+}
+
+void BattleGroundWS::StartingEventOpenDoors()
+{
+ for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; ++i)
+ DoorOpen(i);
+ for(uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; ++i)
+ DoorOpen(i);
+
+ SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY);
+
+ for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; ++i)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+}
+
void BattleGroundWS::AddPlayer(Player *plr)
{
BattleGround::AddPlayer(plr);
@@ -188,7 +150,7 @@ void BattleGroundWS::AddPlayer(Player *plr)
void BattleGroundWS::RespawnFlag(uint32 Team, bool captured)
{
- if(Team == ALLIANCE)
+ if (Team == ALLIANCE)
{
sLog.outDebug("Respawn Alliance flag");
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE;
@@ -199,37 +161,37 @@ void BattleGroundWS::RespawnFlag(uint32 Team, bool captured)
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE;
}
- if(captured)
+ if (captured)
{
//when map_update will be allowed for battlegrounds this code will be useless
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY);
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY);
- SendMessageToAll(GetTrinityString(LANG_BG_WS_F_PLACED));
+ SendMessageToAll(LANG_BG_WS_F_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); // flag respawned sound...
}
}
void BattleGroundWS::RespawnFlagAfterDrop(uint32 team)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
RespawnFlag(team,false);
- if(team == ALLIANCE)
+ if (team == ALLIANCE)
{
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY);
- SendMessageToAll(GetTrinityString(LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED));
+ SendMessageToAll(LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
else
{
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY);
- SendMessageToAll(GetTrinityString(LANG_BG_WS_HORDE_FLAG_RESPAWNED));
+ SendMessageToAll(LANG_BG_WS_HORDE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED);
GameObject *obj = HashMapHolder<GameObject>::Find(GetDroppedFlagGUID(team));
- if(obj)
+ if (obj)
obj->Delete();
else
sLog.outError("unknown droped flag bg, guid: %u",GUID_LOPART(GetDroppedFlagGUID(team)));
@@ -239,17 +201,13 @@ void BattleGroundWS::RespawnFlagAfterDrop(uint32 team)
void BattleGroundWS::EventPlayerCapturedFlag(Player *Source)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
- uint8 type = 0;
uint32 winner = 0;
- const char *message = "";
-
- //TODO FIX reputation and honor gains for low level players!
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
- if(Source->GetTeam() == ALLIANCE)
+ if (Source->GetTeam() == ALLIANCE)
{
if (!this->IsHordeFlagPickedup())
return;
@@ -258,13 +216,10 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source)
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_WAIT_RESPAWN;
// Drop Horde Flag from Player
Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
- message = GetTrinityString(LANG_BG_WS_CAPTURED_HF);
- type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
- if(GetTeamScore(ALLIANCE) < BG_WS_MAX_TEAM_SCORE)
+ if (GetTeamScore(ALLIANCE) < BG_WS_MAX_TEAM_SCORE)
AddPoint(ALLIANCE, 1);
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE);
- RewardReputationToTeam(890, BG_WSG_Reputation[m_HonorMode][BG_WSG_FLAG_CAP], ALLIANCE); // +35 reputation
- RewardHonorToTeam(BG_WSG_Honor[m_HonorMode][BG_WSG_FLAG_CAP], ALLIANCE); // +40 bonushonor
+ RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE);
}
else
{
@@ -275,34 +230,34 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source)
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_WAIT_RESPAWN;
// Drop Alliance Flag from Player
Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
- message = GetTrinityString(LANG_BG_WS_CAPTURED_AF);
- type = CHAT_MSG_BG_SYSTEM_HORDE;
- if(GetTeamScore(HORDE) < BG_WS_MAX_TEAM_SCORE)
+ if (GetTeamScore(HORDE) < BG_WS_MAX_TEAM_SCORE)
AddPoint(HORDE, 1);
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE);
- RewardReputationToTeam(889, BG_WSG_Reputation[m_HonorMode][BG_WSG_FLAG_CAP], HORDE); // +35 reputation
- RewardHonorToTeam(BG_WSG_Honor[m_HonorMode][BG_WSG_FLAG_CAP], HORDE); // +40 bonushonor
+ RewardReputationToTeam(889, m_ReputationCapture, HORDE);
}
+ //for flag capture is reward 2 honorable kills
+ RewardHonorToTeam(GetBonusHonorFromKill(2), Source->GetTeam());
SpawnBGObject(BG_WS_OBJECT_H_FLAG, BG_WS_FLAG_RESPAWN_TIME);
SpawnBGObject(BG_WS_OBJECT_A_FLAG, BG_WS_FLAG_RESPAWN_TIME);
- WorldPacket data;
- ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
- SendPacketToAll(&data);
+ if (Source->GetTeam() == ALLIANCE)
+ SendMessageToAll(LANG_BG_WS_CAPTURED_HF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source);
+ else
+ SendMessageToAll(LANG_BG_WS_CAPTURED_AF, CHAT_MSG_BG_SYSTEM_HORDE, Source);
UpdateFlagState(Source->GetTeam(), 1); // flag state none
UpdateTeamScore(Source->GetTeam());
// only flag capture should be updated
- UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures...
+ UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures
- if(GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE)
+ if (GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE)
winner = ALLIANCE;
- if(GetTeamScore(HORDE) == BG_WS_MAX_TEAM_SCORE)
+ if (GetTeamScore(HORDE) == BG_WS_MAX_TEAM_SCORE)
winner = HORDE;
- if(winner)
+ if (winner)
{
UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 0);
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 0);
@@ -320,15 +275,15 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source)
void BattleGroundWS::EventPlayerDroppedFlag(Player *Source)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
{
// if not running, do not cast things at the dropper player (prevent spawning the "dropped" flag), neither send unnecessary messages
// just take off the aura
- if(Source->GetTeam() == ALLIANCE)
+ if (Source->GetTeam() == ALLIANCE)
{
- if(!this->IsHordeFlagPickedup())
+ if (!this->IsHordeFlagPickedup())
return;
- if(GetHordeFlagPickerGUID() == Source->GetGUID())
+ if (GetHordeFlagPickerGUID() == Source->GetGUID())
{
SetHordeFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
@@ -336,9 +291,9 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source)
}
else
{
- if(!this->IsAllianceFlagPickedup())
+ if (!this->IsAllianceFlagPickedup())
return;
- if(GetAllianceFlagPickerGUID() == Source->GetGUID())
+ if (GetAllianceFlagPickerGUID() == Source->GetGUID())
{
SetAllianceFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
@@ -347,36 +302,30 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source)
return;
}
- const char *message = "";
- uint8 type = 0;
bool set = false;
- if(Source->GetTeam() == ALLIANCE)
+ if (Source->GetTeam() == ALLIANCE)
{
- if(!this->IsHordeFlagPickedup())
+ if (!IsHordeFlagPickedup())
return;
- if(GetHordeFlagPickerGUID() == Source->GetGUID())
+ if (GetHordeFlagPickerGUID() == Source->GetGUID())
{
SetHordeFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG);
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_GROUND;
- message = GetTrinityString(LANG_BG_WS_DROPPED_HF);
- type = CHAT_MSG_BG_SYSTEM_HORDE;
Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true);
set = true;
}
}
else
{
- if(!this->IsAllianceFlagPickedup())
+ if (!IsAllianceFlagPickedup())
return;
- if(GetAllianceFlagPickerGUID() == Source->GetGUID())
+ if (GetAllianceFlagPickerGUID() == Source->GetGUID())
{
SetAllianceFlagPicker(0);
Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG);
m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_GROUND;
- message = GetTrinityString(LANG_BG_WS_DROPPED_AF);
- type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true);
set = true;
}
@@ -387,14 +336,16 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source)
Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true);
UpdateFlagState(Source->GetTeam(), 1);
- WorldPacket data;
- ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
- SendPacketToAll(&data);
-
- if(Source->GetTeam() == ALLIANCE)
+ if (Source->GetTeam() == ALLIANCE)
+ {
+ SendMessageToAll(LANG_BG_WS_DROPPED_HF, CHAT_MSG_BG_SYSTEM_HORDE, Source);
UpdateWorldState(BG_WS_FLAG_UNK_HORDE, uint32(-1));
+ }
else
+ {
+ SendMessageToAll(LANG_BG_WS_DROPPED_AF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source);
UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, uint32(-1));
+ }
m_FlagsDropTimer[GetTeamIndexByTeamId(Source->GetTeam()) ? 0 : 1] = BG_WS_FLAG_DROP_TIME;
}
@@ -402,17 +353,17 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source)
void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
- const char *message;
- uint8 type = 0;
+ int32 message_id = 0;
+ ChatMsg type;
//alliance flag picked up from base
if(Source->GetTeam() == HORDE && this->GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_BASE
&& this->m_BgObjects[BG_WS_OBJECT_A_FLAG] == target_obj->GetGUID())
{
- message = GetTrinityString(LANG_BG_WS_PICKEDUP_AF);
+ message_id = LANG_BG_WS_PICKEDUP_AF;
type = CHAT_MSG_BG_SYSTEM_HORDE;
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY);
@@ -428,7 +379,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target
if (Source->GetTeam() == ALLIANCE && this->GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_BASE
&& this->m_BgObjects[BG_WS_OBJECT_H_FLAG] == target_obj->GetGUID())
{
- message = GetTrinityString(LANG_BG_WS_PICKEDUP_HF);
+ message_id = LANG_BG_WS_PICKEDUP_HF;
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP);
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY);
@@ -441,11 +392,11 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target
}
//Alliance flag on ground(not in base) (returned or picked up again from ground!)
- if(this->GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10) && target_obj->GetGOInfo()->id == BG_OBJECT_A_FLAG_GROUND_WS_ENTRY)
+ if (GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10))
{
- if(Source->GetTeam() == ALLIANCE)
+ if (Source->GetTeam() == ALLIANCE)
{
- message = GetTrinityString(LANG_BG_WS_RETURNED_AF);
+ message_id = LANG_BG_WS_RETURNED_AF;
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
UpdateFlagState(HORDE, BG_WS_FLAG_STATE_WAIT_RESPAWN);
RespawnFlag(ALLIANCE, false);
@@ -455,7 +406,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target
}
else
{
- message = GetTrinityString(LANG_BG_WS_PICKEDUP_AF);
+ message_id = LANG_BG_WS_PICKEDUP_AF;
type = CHAT_MSG_BG_SYSTEM_HORDE;
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY);
@@ -470,11 +421,11 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target
}
//Horde flag on ground(not in base) (returned or picked up again)
- if(this->GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10) && target_obj->GetGOInfo()->id == BG_OBJECT_H_FLAG_GROUND_WS_ENTRY)
+ if (GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10))
{
- if(Source->GetTeam() == HORDE)
+ if (Source->GetTeam() == HORDE)
{
- message = GetTrinityString(LANG_BG_WS_RETURNED_HF);
+ message_id = LANG_BG_WS_RETURNED_HF;
type = CHAT_MSG_BG_SYSTEM_HORDE;
UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_WAIT_RESPAWN);
RespawnFlag(HORDE, false);
@@ -484,7 +435,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target
}
else
{
- message = GetTrinityString(LANG_BG_WS_PICKEDUP_HF);
+ message_id = LANG_BG_WS_PICKEDUP_HF;
type = CHAT_MSG_BG_SYSTEM_ALLIANCE;
PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP);
SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY);
@@ -498,21 +449,19 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target
//target_obj->Delete();
}
- if (!type)
+ if (!message_id)
return;
- WorldPacket data;
- ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL);
- SendPacketToAll(&data);
+ SendMessageToAll(message_id, type, Source);
Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
}
void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid)
{
// sometimes flag aura not removed :(
- if(IsAllianceFlagPickedup() && m_FlagKeepers[BG_TEAM_ALLIANCE] == guid)
+ if (IsAllianceFlagPickedup() && m_FlagKeepers[BG_TEAM_ALLIANCE] == guid)
{
- if(!plr)
+ if (!plr)
{
sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!");
this->SetAllianceFlagPicker(0);
@@ -521,9 +470,9 @@ void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid)
else
this->EventPlayerDroppedFlag(plr);
}
- if(IsHordeFlagPickedup() && m_FlagKeepers[BG_TEAM_HORDE] == guid)
+ if (IsHordeFlagPickedup() && m_FlagKeepers[BG_TEAM_HORDE] == guid)
{
- if(!plr)
+ if (!plr)
{
sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!");
this->SetHordeFlagPicker(0);
@@ -536,7 +485,7 @@ void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid)
void BattleGroundWS::UpdateFlagState(uint32 team, uint32 value)
{
- if(team == ALLIANCE)
+ if (team == ALLIANCE)
UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, value);
else
UpdateWorldState(BG_WS_FLAG_STATE_HORDE, value);
@@ -544,7 +493,7 @@ void BattleGroundWS::UpdateFlagState(uint32 team, uint32 value)
void BattleGroundWS::UpdateTeamScore(uint32 team)
{
- if(team == ALLIANCE)
+ if (team == ALLIANCE)
UpdateWorldState(BG_WS_FLAG_CAPTURES_ALLIANCE, GetTeamScore(team));
else
UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, GetTeamScore(team));
@@ -553,7 +502,7 @@ void BattleGroundWS::UpdateTeamScore(uint32 team)
void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger)
{
// this is wrong way to implement these things. On official it done by gameobject spell cast.
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
//uint32 SpellId = 0;
@@ -579,13 +528,13 @@ void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger)
//buff_guid = m_BgObjects[BG_WS_OBJECT_BERSERKBUFF_2];
break;
case 3646: // Alliance Flag spawn
- if(m_FlagState[BG_TEAM_HORDE] && !m_FlagState[BG_TEAM_ALLIANCE])
- if(GetHordeFlagPickerGUID() == Source->GetGUID())
+ if (m_FlagState[BG_TEAM_HORDE] && !m_FlagState[BG_TEAM_ALLIANCE])
+ if (GetHordeFlagPickerGUID() == Source->GetGUID())
EventPlayerCapturedFlag(Source);
break;
case 3647: // Horde Flag spawn
- if(m_FlagState[BG_TEAM_ALLIANCE] && !m_FlagState[BG_TEAM_HORDE])
- if(GetAllianceFlagPickerGUID() == Source->GetGUID())
+ if (m_FlagState[BG_TEAM_ALLIANCE] && !m_FlagState[BG_TEAM_HORDE])
+ if (GetAllianceFlagPickerGUID() == Source->GetGUID())
EventPlayerCapturedFlag(Source);
break;
case 3649: // unk1
@@ -599,14 +548,14 @@ void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger)
break;
}
- //if(buff_guid)
+ //if (buff_guid)
// HandleTriggerBuff(buff_guid,Source);
}
bool BattleGroundWS::SetupBattleGround()
{
// flags
- if( !AddObject(BG_WS_OBJECT_A_FLAG, BG_OBJECT_A_FLAG_WS_ENTRY, 1540.423f, 1481.325f, 351.8284f, 3.089233f, 0, 0, 0.9996573f, 0.02617699f, BG_WS_FLAG_RESPAWN_TIME/1000)
+ if (!AddObject(BG_WS_OBJECT_A_FLAG, BG_OBJECT_A_FLAG_WS_ENTRY, 1540.423f, 1481.325f, 351.8284f, 3.089233f, 0, 0, 0.9996573f, 0.02617699f, BG_WS_FLAG_RESPAWN_TIME/1000)
|| !AddObject(BG_WS_OBJECT_H_FLAG, BG_OBJECT_H_FLAG_WS_ENTRY, 916.0226f, 1434.405f, 345.413f, 0.01745329f, 0, 0, 0.008726535f, 0.9999619f, BG_WS_FLAG_RESPAWN_TIME/1000)
// buffs
|| !AddObject(BG_WS_OBJECT_SPEEDBUFF_1, BG_OBJECTID_SPEEDBUFF_ENTRY, 1449.93f, 1470.71f, 342.6346f, -1.64061f, 0, 0, 0.7313537f, -0.6819983f, BUFF_RESPAWN_TIME)
@@ -634,14 +583,14 @@ bool BattleGroundWS::SetupBattleGround()
}
WorldSafeLocsEntry const *sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE);
- if(!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE))
+ if (!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE))
{
sLog.outErrorDb("BatteGroundWS: Failed to spawn Alliance spirit guide! BattleGround not created!");
return false;
}
sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE);
- if(!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE))
+ if (!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE))
{
sLog.outErrorDb("BatteGroundWS: Failed to spawn Horde spirit guide! BattleGround not created!");
return false;
@@ -652,8 +601,11 @@ bool BattleGroundWS::SetupBattleGround()
return true;
}
-void BattleGroundWS::ResetBGSubclass()
+void BattleGroundWS::Reset()
{
+ //call parent's class reset
+ BattleGround::Reset();
+
m_FlagKeepers[BG_TEAM_ALLIANCE] = 0;
m_FlagKeepers[BG_TEAM_HORDE] = 0;
m_DroppedFlagGUID[BG_TEAM_ALLIANCE] = 0;
@@ -662,19 +614,36 @@ void BattleGroundWS::ResetBGSubclass()
m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE;
m_TeamScores[BG_TEAM_ALLIANCE] = 0;
m_TeamScores[BG_TEAM_HORDE] = 0;
+ bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call!
+ m_ReputationCapture = (isBGWeekend) ? 45 : 35;
+ m_HonorWinKills = (isBGWeekend) ? 3 : 1;
+ m_HonorEndKills = (isBGWeekend) ? 4 : 2;
/* Spirit nodes is static at this BG and then not required deleting at BG reset.
- if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE])
+ if (m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE])
DelCreature(WS_SPIRIT_MAIN_ALLIANCE);
-
- if(m_BgCreatures[WS_SPIRIT_MAIN_HORDE])
+ if (m_BgCreatures[WS_SPIRIT_MAIN_HORDE])
DelCreature(WS_SPIRIT_MAIN_HORDE);
*/
}
+void BattleGroundWS::EndBattleGround(uint32 winner)
+{
+ //win reward
+ if (winner == ALLIANCE)
+ RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), ALLIANCE);
+ if (winner == HORDE)
+ RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), HORDE);
+ //complete map_end rewards (even if no team wins)
+ RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), ALLIANCE);
+ RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), HORDE);
+
+ BattleGround::EndBattleGround(winner);
+}
+
void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer)
{
- if(GetStatus() != STATUS_IN_PROGRESS)
+ if (GetStatus() != STATUS_IN_PROGRESS)
return;
EventPlayerDroppedFlag(player);
@@ -704,19 +673,42 @@ void BattleGroundWS::UpdatePlayerScore(Player *Source, uint32 type, uint32 value
}
}
+WorldSafeLocsEntry const* BattleGroundWS::GetClosestGraveYard(Player* player)
+{
+ //if status in progress, it returns main graveyards with spiritguides
+ //else it will return the graveyard in the flagroom - this is especially good
+ //if a player dies in preparation phase - then the player can't cheat
+ //and teleport to the graveyard outside the flagroom
+ //and start running around, while the doors are still closed
+ if (player->GetTeam() == ALLIANCE)
+ {
+ if (GetStatus() == STATUS_IN_PROGRESS)
+ return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE);
+ else
+ return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_ALLIANCE);
+ }
+ else
+ {
+ if (GetStatus() == STATUS_IN_PROGRESS)
+ return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE);
+ else
+ return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_HORDE);
+ }
+}
+
void BattleGroundWS::FillInitialWorldStates(WorldPacket& data)
{
data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(ALLIANCE));
data << uint32(BG_WS_FLAG_CAPTURES_HORDE) << uint32(GetTeamScore(HORDE));
- if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND)
+ if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND)
data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(-1);
else if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER)
data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(1);
else
data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(0);
- if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND)
+ if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND)
data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(-1);
else if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER)
data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(1);
diff --git a/src/game/BattleGroundWS.h b/src/game/BattleGroundWS.h
index 4e57826cd30..906bccfe6ab 100644
--- a/src/game/BattleGroundWS.h
+++ b/src/game/BattleGroundWS.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@ enum BG_WS_TimerOrScore
BG_WS_FLAG_RESPAWN_TIME = 23000,
BG_WS_FLAG_DROP_TIME = 10000,
BG_WS_SPELL_FORCE_TIME = 600000,
- BG_WS_SPELL_BRUTAL_TIME = 900000
+ BG_WS_SPELL_BRUTAL_TIME = 900000
};
enum BG_WS_Sound
@@ -116,8 +116,10 @@ enum BG_WS_FlagState
enum BG_WS_Graveyards
{
- WS_GRAVEYARD_MAIN_ALLIANCE = 771,
- WS_GRAVEYARD_MAIN_HORDE = 772
+ WS_GRAVEYARD_FLAGROOM_ALLIANCE = 769,
+ WS_GRAVEYARD_FLAGROOM_HORDE = 770,
+ WS_GRAVEYARD_MAIN_ALLIANCE = 771,
+ WS_GRAVEYARD_MAIN_HORDE = 772
};
enum BG_WS_CreatureTypes
@@ -145,10 +147,12 @@ class BattleGroundWS : public BattleGround
/* Construction */
BattleGroundWS();
~BattleGroundWS();
- void Update(time_t diff);
+ void Update(uint32 diff);
/* inherited from BattlegroundClass */
virtual void AddPlayer(Player *plr);
+ virtual void StartingEventCloseDoors();
+ virtual void StartingEventOpenDoors();
/* BG Flags */
uint64 GetAllianceFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_ALLIANCE]; }
@@ -174,7 +178,9 @@ class BattleGroundWS : public BattleGround
void HandleAreaTrigger(Player *Source, uint32 Trigger);
void HandleKillPlayer(Player *player, Player *killer);
bool SetupBattleGround();
- virtual void ResetBGSubclass();
+ virtual void Reset();
+ void EndBattleGround(uint32 winner);
+ virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
void UpdateFlagState(uint32 team, uint32 value);
void UpdateTeamScore(uint32 team);
@@ -185,9 +191,9 @@ class BattleGroundWS : public BattleGround
/* Scorekeeping */
uint32 GetTeamScore(uint32 TeamID) const { return m_TeamScores[GetTeamIndexByTeamId(TeamID)]; }
- void AddPoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] += Points; m_score[GetTeamIndexByTeamId(TeamID)] = m_TeamScores[GetTeamIndexByTeamId(TeamID)];}
- void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; m_score[GetTeamIndexByTeamId(TeamID)] = m_TeamScores[GetTeamIndexByTeamId(TeamID)];}
- void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; m_score[GetTeamIndexByTeamId(TeamID)] = m_TeamScores[GetTeamIndexByTeamId(TeamID)]; }
+ void AddPoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] += Points; }
+ void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; }
+ void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; }
private:
uint64 m_FlagKeepers[2]; // 0 - alliance, 1 - horde
@@ -197,8 +203,9 @@ class BattleGroundWS : public BattleGround
int32 m_FlagsTimer[2];
int32 m_FlagsDropTimer[2];
- int32 m_FlagSpellForceTimer;
- int32 m_FlagSpellBrutalTimer;
+ uint32 m_ReputationCapture;
+ uint32 m_HonorWinKills;
+ uint32 m_HonorEndKills;
};
#endif
diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt
index 621ce3def3e..44e692b71ba 100644
--- a/src/game/CMakeLists.txt
+++ b/src/game/CMakeLists.txt
@@ -4,6 +4,8 @@
SET(game_STAT_SRCS
AccountMgr.cpp
AccountMgr.h
+ AchievementMgr.h
+ AchievementMgr.cpp
AddonHandler.cpp
AddonHandler.h
AggressorAI.cpp
@@ -12,9 +14,9 @@ SET(game_STAT_SRCS
ArenaTeam.cpp
ArenaTeam.h
ArenaTeamHandler.cpp
+ AuctionHouseHandler.cpp
AuctionHouseBot.cpp
AuctionHouseBot.h
- AuctionHouseHandler.cpp
AuctionHouseMgr.cpp
AuctionHouseMgr.h
Bag.cpp
@@ -24,22 +26,31 @@ SET(game_STAT_SRCS
BattleGroundAB.cpp
BattleGroundAV.cpp
BattleGroundBE.cpp
+ BattleGroundDS.cpp
BattleGroundEY.cpp
BattleGroundNA.cpp
BattleGroundRL.cpp
+ BattleGroundRV.cpp
+ BattleGroundSA.cpp
BattleGroundWS.cpp
BattleGround.h
BattleGroundAA.h
BattleGroundAB.h
BattleGroundAV.h
BattleGroundBE.h
+ BattleGroundDS.h
BattleGroundEY.h
BattleGroundNA.h
BattleGroundRL.h
+ BattleGroundRV.h
+ BattleGroundSA.h
BattleGroundWS.h
BattleGroundHandler.cpp
BattleGroundMgr.cpp
BattleGroundMgr.h
+ Calendar.cpp
+ Calendar.h
+ CalendarHandler.cpp
Cell.h
CellImpl.h
Channel.cpp
@@ -57,15 +68,23 @@ SET(game_STAT_SRCS
Corpse.h
CreatureAI.cpp
CreatureAI.h
+ CreatureAIFactory.h
CreatureAIImpl.h
CreatureAIRegistry.cpp
CreatureAIRegistry.h
CreatureAISelector.cpp
CreatureAISelector.h
+ CreatureEventAI.cpp
+ CreatureEventAIMgr.cpp
Creature.cpp
Creature.h
CreatureGroups.cpp
CreatureGroups.h
+ DBCEnums.h
+ DBCStores.cpp
+ DBCStores.h
+ DBCStructure.h
+ DBCfmt.h
Debugcmds.cpp
DestinationHolder.cpp
DestinationHolder.h
@@ -76,8 +95,8 @@ SET(game_STAT_SRCS
FleeingMovementGenerator.cpp
FleeingMovementGenerator.h
Formulas.h
- GameEvent.cpp
- GameEvent.h
+ GameEventMgr.cpp
+ GameEventMgr.h
GameObject.cpp
GameObject.h
GlobalEvents.cpp
@@ -131,6 +150,8 @@ SET(game_STAT_SRCS
MapInstanced.h
MapManager.cpp
MapManager.h
+ MapReference.h
+ MapRefManager.h
MiscHandler.cpp
MotionMaster.cpp
MotionMaster.h
@@ -151,6 +172,8 @@ SET(game_STAT_SRCS
Object.h
ObjectMgr.cpp
ObjectMgr.h
+ ObjectPosSelector.cpp
+ ObjectPosSelector.h
Opcodes.cpp
Opcodes.h
OutdoorPvP.cpp
@@ -184,8 +207,8 @@ SET(game_STAT_SRCS
PlayerDump.h
PointMovementGenerator.cpp
PointMovementGenerator.h
- PossessedAI.cpp
- PossessedAI.h
+ PoolHandler.cpp
+ PoolHandler.h
QueryHandler.cpp
QuestDef.cpp
QuestDef.h
@@ -194,6 +217,8 @@ SET(game_STAT_SRCS
RandomMovementGenerator.h
ReactorAI.cpp
ReactorAI.h
+ ReputationMgr.cpp
+ ReputationMgr.h
ScriptCalls.cpp
ScriptCalls.h
SharedDefines.h
@@ -221,7 +246,7 @@ SET(game_STAT_SRCS
TemporarySummon.h
TicketHandler.cpp
TicketMgr.cpp
- TicketMgr.h
+ TicketMgr.h
Tools.cpp
Tools.h
TotemAI.cpp
@@ -236,11 +261,15 @@ SET(game_STAT_SRCS
Traveller.h
Unit.cpp
Unit.h
+ UnitAI.cpp
+ UnitAI.h
UnitEvents.h
UpdateData.cpp
UpdateData.h
UpdateFields.h
UpdateMask.h
+ Vehicle.cpp
+ Vehicle.h
VoiceChatHandler.cpp
WaypointManager.cpp
WaypointManager.h
@@ -264,6 +293,9 @@ SET(game_STAT_SRCS
GroupReference.cpp
GroupReference.h
GroupRefManager.h
+ OutdoorPvPImpl.h
+ Wintergrasp.h
+ Wintergrasp.cpp
)
add_library(game STATIC ${game_STAT_SRCS})
diff --git a/src/game/PossessedAI.cpp b/src/game/Calendar.cpp
index bda0de88882..0c1efb20f87 100644
--- a/src/game/PossessedAI.cpp
+++ b/src/game/Calendar.cpp
@@ -1,7 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * Thanks to the original authors: MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,11 +8,10 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
diff --git a/src/game/PossessedAI.h b/src/game/Calendar.h
index bbfacb6454c..7a86afa7db7 100644
--- a/src/game/PossessedAI.h
+++ b/src/game/Calendar.h
@@ -1,7 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * Thanks to the original authors: MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,16 +8,19 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef MANGOS_POSSESSEDAI_H
-#define MANGOS_POSSESSEDAI_H
+#ifndef MANGOS_CALENDAR_H
+#define MANGOS_CALENDAR_H
+class Calendar
+{
+};
#endif
diff --git a/src/game/CalendarHandler.cpp b/src/game/CalendarHandler.cpp
new file mode 100644
index 00000000000..3cd186c15d3
--- /dev/null
+++ b/src/game/CalendarHandler.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Common.h"
+#include "Log.h"
+#include "Player.h"
+#include "WorldPacket.h"
+#include "WorldSession.h"
+#include "Opcodes.h"
+#include "InstanceSaveMgr.h"
+
+void WorldSession::HandleCalendarGetCalendar(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_GET_CALENDAR");
+ recv_data.hexlike();
+
+ time_t cur_time = time(NULL);
+
+ WorldPacket data(SMSG_CALENDAR_SEND_CALENDAR,4+4*0+4+4*0+4+4);
+
+ // TODO: calendar invite event output
+ data << (uint32) 0; //invite node count
+ // TODO: calendar event output
+ data << (uint32) 0; //event count
+
+ data << (uint32) 0; //wtf??
+ data << (uint32) secsToTimeBitFields(cur_time); // current time
+
+ uint32 counter = 0;
+ size_t p_counter = data.wpos();
+ data << uint32(counter); // instance save count
+
+ for(int i = 0; i < TOTAL_DIFFICULTIES; ++i)
+ {
+ for (Player::BoundInstancesMap::const_iterator itr = _player->m_boundInstances[i].begin(); itr != _player->m_boundInstances[i].end(); ++itr)
+ {
+ if(itr->second.perm)
+ {
+ InstanceSave *save = itr->second.save;
+ data << uint32(save->GetMapId());
+ data << uint32(save->GetDifficulty());
+ data << uint32(save->GetResetTime() - cur_time);
+ data << uint64(save->GetInstanceId()); // instance save id as unique instance copy id
+ ++counter;
+ }
+ }
+ }
+ data.put<uint32>(p_counter,counter);
+
+ data << (uint32) 1135753200; //wtf?? (28.12.2005 12:00)
+ data << (uint32) 0; // unk counter 4
+ data << (uint32) 0; // unk counter 5
+ //sLog.outDebug("Sending calendar");
+ //data.hexlike();
+ SendPacket(&data);
+}
+
+void WorldSession::HandleCalendarGetEvent(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_GET_EVENT");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarGuildFilter(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_GUILD_FILTER");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarArenaTeam(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_ARENA_TEAM");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarAddEvent(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_ADD_EVENT");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarUpdateEvent(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_UPDATE_EVENT");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarRemoveEvent(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_REMOVE_EVENT");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarCopyEvent(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_COPY_EVENT");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarEventInvite(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_INVITE");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarEventRsvp(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_RSVP");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarEventRemoveInvite(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_REMOVE_INVITE");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarEventStatus(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_STATUS");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_MODERATOR_STATUS");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarComplain(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_COMPLAIN");
+ recv_data.hexlike();
+}
+
+void WorldSession::HandleCalendarGetNumPending(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: CMSG_CALENDAR_GET_NUM_PENDING");
+ recv_data.hexlike();
+
+ WorldPacket data(SMSG_CALENDAR_SEND_NUM_PENDING, 4);
+ data << uint32(0); // 0 - no pending invites, 1 - some pending invites
+ SendPacket(&data);
+}
diff --git a/src/game/Cell.h b/src/game/Cell.h
index 160e037bcfb..7e66d5d9f73 100644
--- a/src/game/Cell.h
+++ b/src/game/Cell.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -93,13 +93,13 @@ struct TRINITY_DLL_DECL Cell
y = data.Part.grid_y*MAX_NUMBER_OF_CELLS + data.Part.cell_y;
}
- inline bool DiffCell(const Cell &cell) const
+ bool DiffCell(const Cell &cell) const
{
return( data.Part.cell_x != cell.data.Part.cell_x ||
data.Part.cell_y != cell.data.Part.cell_y );
}
- inline bool DiffGrid(const Cell &cell) const
+ bool DiffGrid(const Cell &cell) const
{
return( data.Part.grid_x != cell.data.Part.grid_x ||
data.Part.grid_y != cell.data.Part.grid_y );
diff --git a/src/game/CellImpl.h b/src/game/CellImpl.h
index 463b051f7ac..e74e0013a19 100644
--- a/src/game/CellImpl.h
+++ b/src/game/CellImpl.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Channel.cpp b/src/game/Channel.cpp
index bf787d7d25d..588eb15f0cc 100644
--- a/src/game/Channel.cpp
+++ b/src/game/Channel.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
#include "SocialMgr.h"
Channel::Channel(const std::string& name, uint32 channel_id)
-: m_name(name), m_announce(true), m_moderate(false), m_channelId(channel_id), m_ownerGUID(0), m_password(""), m_flags(0)
+: m_announce(true), m_moderate(false), m_name(name), m_flags(0), m_channelId(channel_id), m_ownerGUID(0)
{
// set special flags if built-in channel
ChatChannelsEntry const* ch = GetChannelEntryFor(channel_id);
@@ -171,7 +171,7 @@ void Channel::Leave(uint64 p, bool send)
void Channel::KickOrBan(uint64 good, const char *badname, bool ban)
{
- uint32 sec = 0;
+ AccountTypes sec = SEC_PLAYER;
Player *gplr = objmgr.GetPlayer(good);
if(gplr)
sec = gplr->GetSession()->GetSecurity();
@@ -300,10 +300,11 @@ void Channel::Password(uint64 p, const char *pass)
void Channel::SetMode(uint64 p, const char *p2n, bool mod, bool set)
{
- uint32 sec = 0;
Player *plr = objmgr.GetPlayer(p);
- if(plr)
- sec = plr->GetSession()->GetSecurity();
+ if (!plr)
+ return;
+
+ uint32 sec = plr->GetSession()->GetSecurity();
if(!IsOn(p))
{
@@ -368,10 +369,11 @@ void Channel::SetMode(uint64 p, const char *p2n, bool mod, bool set)
void Channel::SetOwner(uint64 p, const char *newname)
{
- uint32 sec = 0;
Player *plr = objmgr.GetPlayer(p);
- if(plr)
- sec = plr->GetSession()->GetSecurity();
+ if (!plr)
+ return;
+
+ uint32 sec = plr->GetSession()->GetSecurity();
if(!IsOn(p))
{
@@ -449,13 +451,13 @@ void Channel::List(Player* player)
bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || player->GetSession()->GetSecurity() > SEC_PLAYER;
uint32 count = 0;
- for(PlayerList::iterator i = players.begin(); i != players.end(); ++i)
+ for(PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
{
Player *plr = objmgr.GetPlayer(i->first);
// PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
- if( plr && ( plr->GetSession()->GetSecurity() == SEC_PLAYER || gmInWhoList && plr->IsVisibleGloballyFor(player) ) )
+ if (plr && ( plr->GetSession()->GetSecurity() == SEC_PLAYER || (gmInWhoList && plr->IsVisibleGloballyFor(player))))
{
data << uint64(i->first);
data << uint8(i->second.flags); // flags seems to be changed...
@@ -662,7 +664,7 @@ void Channel::SetOwner(uint64 guid, bool exclaim)
void Channel::SendToAll(WorldPacket *data, uint64 p)
{
- for(PlayerList::iterator i = players.begin(); i != players.end(); ++i)
+ for(PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
{
Player *plr = objmgr.GetPlayer(i->first);
if(plr)
@@ -675,7 +677,7 @@ void Channel::SendToAll(WorldPacket *data, uint64 p)
void Channel::SendToAllButOne(WorldPacket *data, uint64 who)
{
- for(PlayerList::iterator i = players.begin(); i != players.end(); ++i)
+ for(PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
{
if(i->first != who)
{
@@ -693,12 +695,12 @@ void Channel::SendToOne(WorldPacket *data, uint64 who)
plr->GetSession()->SendPacket(data);
}
-void Channel::Voice(uint64 guid1, uint64 guid2)
+void Channel::Voice(uint64 /*guid1*/, uint64 /*guid2*/)
{
}
-void Channel::DeVoice(uint64 guid1, uint64 guid2)
+void Channel::DeVoice(uint64 /*guid1*/, uint64 /*guid2*/)
{
}
diff --git a/src/game/Channel.h b/src/game/Channel.h
index 82b62df12c4..924046e4739 100644
--- a/src/game/Channel.h
+++ b/src/game/Channel.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@
#include "Common.h"
#include "WorldPacket.h"
-#include "WorldSession.h"
#include "Opcodes.h"
#include "Player.h"
@@ -31,95 +30,95 @@
#include <map>
#include <string>
-class Channel
+enum ChatNotify
{
- enum ChatNotify
- {
- CHAT_JOINED_NOTICE = 0x00, //+ "%s joined channel.";
- CHAT_LEFT_NOTICE = 0x01, //+ "%s left channel.";
- //CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel.";
- CHAT_YOU_JOINED_NOTICE = 0x02, //+ "Joined Channel: [%s]"; -- You joined
- //CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]";
- CHAT_YOU_LEFT_NOTICE = 0x03, //+ "Left Channel: [%s]"; -- You left
- CHAT_WRONG_PASSWORD_NOTICE = 0x04, //+ "Wrong password for %s.";
- CHAT_NOT_MEMBER_NOTICE = 0x05, //+ "Not on channel %s.";
- CHAT_NOT_MODERATOR_NOTICE = 0x06, //+ "Not a moderator of %s.";
- CHAT_PASSWORD_CHANGED_NOTICE = 0x07, //+ "[%s] Password changed by %s.";
- CHAT_OWNER_CHANGED_NOTICE = 0x08, //+ "[%s] Owner changed to %s.";
- CHAT_PLAYER_NOT_FOUND_NOTICE = 0x09, //+ "[%s] Player %s was not found.";
- CHAT_NOT_OWNER_NOTICE = 0x0A, //+ "[%s] You are not the channel owner.";
- CHAT_CHANNEL_OWNER_NOTICE = 0x0B, //+ "[%s] Channel owner is %s.";
- CHAT_MODE_CHANGE_NOTICE = 0x0C, //?
- CHAT_ANNOUNCEMENTS_ON_NOTICE = 0x0D, //+ "[%s] Channel announcements enabled by %s.";
- CHAT_ANNOUNCEMENTS_OFF_NOTICE = 0x0E, //+ "[%s] Channel announcements disabled by %s.";
- CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s.";
- CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s.";
- CHAT_MUTED_NOTICE = 0x11, //+ "[%s] You do not have permission to speak.";
- CHAT_PLAYER_KICKED_NOTICE = 0x12, //? "[%s] Player %s kicked by %s.";
- CHAT_BANNED_NOTICE = 0x13, //+ "[%s] You are banned from that channel.";
- CHAT_PLAYER_BANNED_NOTICE = 0x14, //? "[%s] Player %s banned by %s.";
- CHAT_PLAYER_UNBANNED_NOTICE = 0x15, //? "[%s] Player %s unbanned by %s.";
- CHAT_PLAYER_NOT_BANNED_NOTICE = 0x16, //+ "[%s] Player %s is not banned.";
- CHAT_PLAYER_ALREADY_MEMBER_NOTICE = 0x17, //+ "[%s] Player %s is already on the channel.";
- CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'.";
- CHAT_INVITE_WRONG_FACTION_NOTICE = 0x19, //+ "Target is in the wrong alliance for %s.";
- CHAT_WRONG_FACTION_NOTICE = 0x1A, //+ "Wrong alliance for %s.";
- CHAT_INVALID_NAME_NOTICE = 0x1B, //+ "Invalid channel name";
- CHAT_NOT_MODERATED_NOTICE = 0x1C, //+ "%s is not moderated";
- CHAT_PLAYER_INVITED_NOTICE = 0x1D, //+ "[%s] You invited %s to join the channel";
- CHAT_PLAYER_INVITE_BANNED_NOTICE = 0x1E, //+ "[%s] %s has been banned.";
- CHAT_THROTTLED_NOTICE = 0x1F, //+ "[%s] The number of messages that can be sent to this channel is limited, please wait to send another message.";
- CHAT_NOT_IN_AREA_NOTICE = 0x20, //+ "[%s] You are not in the correct area for this channel."; -- The user is trying to send a chat to a zone specific channel, and they're not physically in that zone.
- CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels.
- CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s.";
- CHAT_VOICE_OFF_NOTICE = 0x23, //+ "[%s] Channel voice disabled by %s.";
- };
+ CHAT_JOINED_NOTICE = 0x00, //+ "%s joined channel.";
+ CHAT_LEFT_NOTICE = 0x01, //+ "%s left channel.";
+ //CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel.";
+ CHAT_YOU_JOINED_NOTICE = 0x02, //+ "Joined Channel: [%s]"; -- You joined
+ //CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]";
+ CHAT_YOU_LEFT_NOTICE = 0x03, //+ "Left Channel: [%s]"; -- You left
+ CHAT_WRONG_PASSWORD_NOTICE = 0x04, //+ "Wrong password for %s.";
+ CHAT_NOT_MEMBER_NOTICE = 0x05, //+ "Not on channel %s.";
+ CHAT_NOT_MODERATOR_NOTICE = 0x06, //+ "Not a moderator of %s.";
+ CHAT_PASSWORD_CHANGED_NOTICE = 0x07, //+ "[%s] Password changed by %s.";
+ CHAT_OWNER_CHANGED_NOTICE = 0x08, //+ "[%s] Owner changed to %s.";
+ CHAT_PLAYER_NOT_FOUND_NOTICE = 0x09, //+ "[%s] Player %s was not found.";
+ CHAT_NOT_OWNER_NOTICE = 0x0A, //+ "[%s] You are not the channel owner.";
+ CHAT_CHANNEL_OWNER_NOTICE = 0x0B, //+ "[%s] Channel owner is %s.";
+ CHAT_MODE_CHANGE_NOTICE = 0x0C, //?
+ CHAT_ANNOUNCEMENTS_ON_NOTICE = 0x0D, //+ "[%s] Channel announcements enabled by %s.";
+ CHAT_ANNOUNCEMENTS_OFF_NOTICE = 0x0E, //+ "[%s] Channel announcements disabled by %s.";
+ CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s.";
+ CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s.";
+ CHAT_MUTED_NOTICE = 0x11, //+ "[%s] You do not have permission to speak.";
+ CHAT_PLAYER_KICKED_NOTICE = 0x12, //? "[%s] Player %s kicked by %s.";
+ CHAT_BANNED_NOTICE = 0x13, //+ "[%s] You are banned from that channel.";
+ CHAT_PLAYER_BANNED_NOTICE = 0x14, //? "[%s] Player %s banned by %s.";
+ CHAT_PLAYER_UNBANNED_NOTICE = 0x15, //? "[%s] Player %s unbanned by %s.";
+ CHAT_PLAYER_NOT_BANNED_NOTICE = 0x16, //+ "[%s] Player %s is not banned.";
+ CHAT_PLAYER_ALREADY_MEMBER_NOTICE = 0x17, //+ "[%s] Player %s is already on the channel.";
+ CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'.";
+ CHAT_INVITE_WRONG_FACTION_NOTICE = 0x19, //+ "Target is in the wrong alliance for %s.";
+ CHAT_WRONG_FACTION_NOTICE = 0x1A, //+ "Wrong alliance for %s.";
+ CHAT_INVALID_NAME_NOTICE = 0x1B, //+ "Invalid channel name";
+ CHAT_NOT_MODERATED_NOTICE = 0x1C, //+ "%s is not moderated";
+ CHAT_PLAYER_INVITED_NOTICE = 0x1D, //+ "[%s] You invited %s to join the channel";
+ CHAT_PLAYER_INVITE_BANNED_NOTICE = 0x1E, //+ "[%s] %s has been banned.";
+ CHAT_THROTTLED_NOTICE = 0x1F, //+ "[%s] The number of messages that can be sent to this channel is limited, please wait to send another message.";
+ CHAT_NOT_IN_AREA_NOTICE = 0x20, //+ "[%s] You are not in the correct area for this channel."; -- The user is trying to send a chat to a zone specific channel, and they're not physically in that zone.
+ CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels.
+ CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s.";
+ CHAT_VOICE_OFF_NOTICE = 0x23, //+ "[%s] Channel voice disabled by %s.";
+};
- enum ChannelFlags
- {
- CHANNEL_FLAG_NONE = 0x00,
- CHANNEL_FLAG_CUSTOM = 0x01,
- // 0x02
- CHANNEL_FLAG_TRADE = 0x04,
- CHANNEL_FLAG_NOT_LFG = 0x08,
- CHANNEL_FLAG_GENERAL = 0x10,
- CHANNEL_FLAG_CITY = 0x20,
- CHANNEL_FLAG_LFG = 0x40,
- CHANNEL_FLAG_VOICE = 0x80
- // General 0x18 = 0x10 | 0x08
- // Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04
- // LocalDefence 0x18 = 0x10 | 0x08
- // GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08
- // LookingForGroup 0x50 = 0x40 | 0x10
- };
+enum ChannelFlags
+{
+ CHANNEL_FLAG_NONE = 0x00,
+ CHANNEL_FLAG_CUSTOM = 0x01,
+ // 0x02
+ CHANNEL_FLAG_TRADE = 0x04,
+ CHANNEL_FLAG_NOT_LFG = 0x08,
+ CHANNEL_FLAG_GENERAL = 0x10,
+ CHANNEL_FLAG_CITY = 0x20,
+ CHANNEL_FLAG_LFG = 0x40,
+ CHANNEL_FLAG_VOICE = 0x80
+ // General 0x18 = 0x10 | 0x08
+ // Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04
+ // LocalDefence 0x18 = 0x10 | 0x08
+ // GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08
+ // LookingForGroup 0x50 = 0x40 | 0x10
+};
- enum ChannelDBCFlags
- {
- CHANNEL_DBC_FLAG_NONE = 0x00000,
- CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG
- CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment
- CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense
- CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade
- CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment
- CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment
- CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense
- CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment
- CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup
- };
+enum ChannelDBCFlags
+{
+ CHANNEL_DBC_FLAG_NONE = 0x00000,
+ CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG
+ CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment
+ CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense
+ CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade
+ CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment
+ CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment
+ CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense
+ CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment
+ CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup
+};
- enum ChannelMemberFlags
- {
- MEMBER_FLAG_NONE = 0x00,
- MEMBER_FLAG_OWNER = 0x01,
- MEMBER_FLAG_MODERATOR = 0x02,
- MEMBER_FLAG_VOICED = 0x04,
- MEMBER_FLAG_MUTED = 0x08,
- MEMBER_FLAG_CUSTOM = 0x10,
- MEMBER_FLAG_MIC_MUTED = 0x20,
- // 0x40
- // 0x80
- };
+enum ChannelMemberFlags
+{
+ MEMBER_FLAG_NONE = 0x00,
+ MEMBER_FLAG_OWNER = 0x01,
+ MEMBER_FLAG_MODERATOR = 0x02,
+ MEMBER_FLAG_VOICED = 0x04,
+ MEMBER_FLAG_MUTED = 0x08,
+ MEMBER_FLAG_CUSTOM = 0x10,
+ MEMBER_FLAG_MIC_MUTED = 0x20,
+ // 0x40
+ // 0x80
+};
+class Channel
+{
struct PlayerInfo
{
uint64 player;
@@ -204,11 +203,8 @@ class Channel
void SendToAllButOne(WorldPacket *data, uint64 who);
void SendToOne(WorldPacket *data, uint64 who);
- bool IsOn(uint64 who) const { return players.count(who) != 0; }
-
- bool IsBanned(const uint64 guid) const {return banned.count(guid) != 0; }
-
- bool IsFirst() const { return !(players.size() > 1); }
+ bool IsOn(uint64 who) const { return players.find(who) != players.end(); }
+ bool IsBanned(uint64 guid) const { return banned.find(guid) != banned.end(); }
uint8 GetPlayerFlags(uint64 p) const
{
diff --git a/src/game/ChannelHandler.cpp b/src/game/ChannelHandler.cpp
index 71e7ea365c2..9b06693c589 100644
--- a/src/game/ChannelHandler.cpp
+++ b/src/game/ChannelHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/ChannelMgr.h b/src/game/ChannelMgr.h
index 453ee144d86..73e69c371ab 100644
--- a/src/game/ChannelMgr.h
+++ b/src/game/ChannelMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,13 +34,13 @@ class ChannelMgr
ChannelMgr() {}
~ChannelMgr()
{
- for(ChannelMap::iterator itr = channels.begin();itr!=channels.end(); ++itr)
+ for(ChannelMap::const_iterator itr = channels.begin();itr!=channels.end(); ++itr)
delete itr->second;
channels.clear();
}
Channel *GetJoinChannel(const std::string& name, uint32 channel_id)
{
- if(channels.count(name) == 0)
+ if (channels.find(name) == channels.end())
{
Channel *nchan = new Channel(name,channel_id);
channels[name] = nchan;
diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp
index 4aef21df530..75e5611ea07 100644
--- a/src/game/CharacterHandler.cpp
+++ b/src/game/CharacterHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,7 +31,6 @@
#include "Guild.h"
#include "UpdateMask.h"
#include "Auth/md5.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Group.h"
#include "Database/DatabaseImpl.h"
@@ -64,11 +63,11 @@ bool LoginQueryHolder::Initialize()
// NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure.
// !!! NOTE: including unused `zone`,`online`
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo,instance_id FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,slot,active,disabled FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_mask,stackcount,amount0, amount1, amount2 ,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,active,disabled FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTUTORIALS, "SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetAccountId(), realmID);
@@ -85,6 +84,8 @@ bool LoginQueryHolder::Initialize()
// in other case still be dummy query
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGUILD, "SELECT guildid,rank FROM guild_member WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, "SELECT arenateamid, played_week, played_season, personal_rating FROM arena_team_member WHERE guid='%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS,"SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'", GUID_LOPART(m_guid));
return res;
}
@@ -162,22 +163,22 @@ void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ )
// ------- Query Without Declined Names --------
// 0 1 2 3 4 5 6 7 8
"SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, "
- // 9 10 11 12 13
- "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid "
- "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='0' "
+ // 9 10 11 12 13 14
+ "characters.at_login, characters.zone, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid "
+ "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 "
"WHERE characters.account = '%u' ORDER BY characters.guid"
:
// --------- Query With Declined Names ---------
// 0 1 2 3 4 5 6 7 8
"SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, "
- // 9 10 11 12 13 14
- "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, genitive "
- "FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='0' "
+ // 9 10 11 12 13 14 15
+ "characters.at_login, characters.zone, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, 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 "
"WHERE characters.account = '%u' ORDER BY characters.guid",
- GetAccountId());
+ PET_SAVE_AS_CURRENT,GetAccountId());
}
void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
@@ -234,17 +235,16 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
if (raceEntry->addon > Expansion())
{
data << (uint8)CHAR_CREATE_EXPANSION;
- sLog.outError("Not Expansion 1 account:[%d] but tried to Create character with expansion 1 race (%u)",GetAccountId(),race_);
+ sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)",Expansion(),GetAccountId(),raceEntry->addon,race_);
SendPacket( &data );
return;
}
// prevent character creating Expansion class without Expansion account
- // TODO: use possible addon field in ChrClassesEntry in next dbc version
- if (Expansion() < 2 && class_ == CLASS_DEATH_KNIGHT)
+ if (classEntry->addon > Expansion())
{
- data << (uint8)CHAR_CREATE_EXPANSION;
- sLog.outError("Not Expansion 2 account:[%d] but tried to Create character with expansion 2 class (%u)",GetAccountId(),class_);
+ data << (uint8)CHAR_CREATE_EXPANSION_CLASS;
+ sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)",Expansion(),GetAccountId(),classEntry->addon,class_);
SendPacket( &data );
return;
}
@@ -311,29 +311,77 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
}
}
+ // speedup check for heroic class disabled case
+ uint32 heroic_free_slots = sWorld.getConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM);
+ if(heroic_free_slots==0 && GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT)
+ {
+ data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT;
+ SendPacket( &data );
+ return;
+ }
+
+ // speedup check for heroic class disabled case
+ uint32 req_level_for_heroic = sWorld.getConfig(CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING);
+ if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT;
+ SendPacket( &data );
+ return;
+ }
+
bool AllowTwoSideAccounts = !sWorld.IsPvPRealm() || sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER;
uint32 skipCinematics = sWorld.getConfig(CONFIG_SKIP_CINEMATICS);
bool have_same_race = false;
- if(!AllowTwoSideAccounts || skipCinematics == 1)
+
+ // if 0 then allowed creating without any characters
+ bool have_req_level_for_heroic = (req_level_for_heroic==0);
+
+ if(!AllowTwoSideAccounts || skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT)
{
- QueryResult *result2 = CharacterDatabase.PQuery("SELECT DISTINCT race FROM characters WHERE account = '%u' %s", GetAccountId(),skipCinematics == 1 ? "" : "LIMIT 1");
+ QueryResult *result2 = CharacterDatabase.PQuery("SELECT guid,race,class FROM characters WHERE account = '%u' %s",
+ GetAccountId(), (skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) ? "" : "LIMIT 1");
if(result2)
{
uint32 team_= Player::TeamForRace(race_);
Field* field = result2->Fetch();
- uint8 race = field[0].GetUInt32();
+ uint8 acc_race = field[1].GetUInt32();
+
+ if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT)
+ {
+ uint8 acc_class = field[2].GetUInt32();
+ if(acc_class == CLASS_DEATH_KNIGHT)
+ {
+ if(heroic_free_slots > 0)
+ --heroic_free_slots;
+
+ if(heroic_free_slots==0)
+ {
+ data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT;
+ SendPacket( &data );
+ return;
+ }
+ }
+
+ if(!have_req_level_for_heroic)
+ {
+ uint32 acc_guid = field[0].GetUInt32();
+ uint32 acc_level = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,acc_guid);
+ if(acc_level >= req_level_for_heroic)
+ have_req_level_for_heroic = true;
+ }
+ }
// need to check team only for first character
// TODO: what to if account already has characters of both races?
if (!AllowTwoSideAccounts)
{
- uint32 team=0;
- if(race > 0)
- team = Player::TeamForRace(race);
+ uint32 acc_team=0;
+ if(acc_race > 0)
+ acc_team = Player::TeamForRace(acc_race);
- if(team != team_)
+ if(acc_team != team_)
{
data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION;
SendPacket( &data );
@@ -342,20 +390,55 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
}
}
- if (skipCinematics == 1)
+ // search same race for cinematic or same class if need
+ // TODO: check if cinematic already shown? (already logged in?; cinematic field)
+ while ((skipCinematics == 1 && !have_same_race) || class_ == CLASS_DEATH_KNIGHT)
{
- // TODO: check if cinematic already shown? (already logged in?; cinematic field)
- while (race_ != race && result2->NextRow())
+ if(!result2->NextRow())
+ break;
+
+ field = result2->Fetch();
+ acc_race = field[1].GetUInt32();
+
+ if(!have_same_race)
+ have_same_race = race_ == acc_race;
+
+ if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT)
{
- field = result2->Fetch();
- race = field[0].GetUInt32();
+ uint8 acc_class = field[2].GetUInt32();
+ if(acc_class == CLASS_DEATH_KNIGHT)
+ {
+ if(heroic_free_slots > 0)
+ --heroic_free_slots;
+
+ if(heroic_free_slots==0)
+ {
+ data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT;
+ SendPacket( &data );
+ return;
+ }
+ }
+
+ if(!have_req_level_for_heroic)
+ {
+ uint32 acc_guid = field[0].GetUInt32();
+ uint32 acc_level = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,acc_guid);
+ if(acc_level >= req_level_for_heroic)
+ have_req_level_for_heroic = true;
+ }
}
- have_same_race = race_ == race;
}
delete result2;
}
}
+ if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && !have_req_level_for_heroic)
+ {
+ data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT;
+ SendPacket( &data );
+ return;
+ }
+
// extract other data required for player creating
uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId;
recv_data >> gender >> skin >> face;
@@ -373,7 +456,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
return;
}
- if(have_same_race && skipCinematics == 1 || skipCinematics == 2)
+ if ((have_same_race && skipCinematics == 1) || skipCinematics == 2)
pNewChar->setCinematic(1); // not show intro
// Player created, save it now
@@ -439,7 +522,7 @@ void WorldSession::HandleCharDeleteOpcode( WorldPacket & recv_data )
return;
std::string IP_str = GetRemoteAddress();
- sLog.outDetail("Account: %d (IP: %s) Delete Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid));
+ sLog.outDetail("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid));
sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid));
if(sLog.IsOutCharDump()) // optimize GetPlayerDump call
@@ -488,7 +571,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
uint64 playerGuid = holder->GetGuid();
Player* pCurrChar = new Player(this);
- pCurrChar->GetMotionMaster()->Initialize();
// for send server info and strings (config)
ChatHandler chH = ChatHandler(pCurrChar);
@@ -502,6 +584,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
return;
}
+ pCurrChar->GetMotionMaster()->Initialize();
+
SetPlayer(pCurrChar);
pCurrChar->SendDungeonDifficulty(false);
@@ -514,9 +598,11 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
data << pCurrChar->GetOrientation();
SendPacket(&data);
- data.Initialize( SMSG_ACCOUNT_DATA_TIMES, 128 );
- for(int i = 0; i < 32; i++)
- data << uint32(0);
+ data.Initialize( SMSG_ACCOUNT_DATA_TIMES, 4+1+8*4 ); // changed in WotLK
+ data << uint32(time(NULL)); // unix time of something
+ data << uint8(1);
+ for(int i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
+ data << uint32(GetAccountData(i)->Time); // also unix time
SendPacket(&data);
data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0
@@ -562,6 +648,11 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
DEBUG_LOG( "WORLD: Sent server info" );
}
+ data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4);
+ data << uint32(0);
+ data << uint32(0);
+ SendPacket(&data);
+
//QueryResult *result = CharacterDatabase.PQuery("SELECT guildid,rank FROM guild_member WHERE guid = '%u'",pCurrChar->GetGUIDLow());
QueryResult *resultGuild = holder->GetResult(PLAYER_LOGIN_QUERY_LOADGUILD);
@@ -619,12 +710,12 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
{
pCurrChar->setCinematic(1);
- ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace());
- if(rEntry)
+ if(ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(pCurrChar->getClass()))
{
- data.Initialize( SMSG_TRIGGER_CINEMATIC,4 );
- data << uint32(rEntry->startmovie);
- SendPacket( &data );
+ if (cEntry->CinematicSequence)
+ pCurrChar->SendCinematicStart(cEntry->CinematicSequence);
+ else if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace()))
+ pCurrChar->SendCinematicStart(rEntry->CinematicSequence);
// send new char string if not empty
if (!sWorld.GetNewCharString().empty())
@@ -672,31 +763,14 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURA+41, 8326);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURA+42, 20584);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURAFLAGS+6, 238);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURALEVELS+11, 514);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS+11, 65535);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_DISPLAYID, 1825);
- //if (pCurrChar->getRace() == RACE_NIGHTELF)
- //{
- // pCurrChar->SetSpeed(MOVE_RUN, 1.5f*1.2f, true);
- // pCurrChar->SetSpeed(MOVE_SWIM, 1.5f*1.2f, true);
- //}
- //else
- //{
- // pCurrChar->SetSpeed(MOVE_RUN, 1.5f, true);
- // pCurrChar->SetSpeed(MOVE_SWIM, 1.5f, true);
- //}
pCurrChar->SetMovement(MOVE_WATER_WALK);
}
if(uint32 sourceNode = pCurrChar->m_taxi.GetTaxiSource())
{
-
sLog.outDebug( "WORLD: Restart character %u taxi flight", pCurrChar->GetGUIDLow() );
- uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam());
+ uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam(),true);
uint32 path = pCurrChar->m_taxi.GetCurrentTaxiPath();
// search appropriate start path node
@@ -741,13 +815,12 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
SendDoFlight( MountId, path, startNode );
}
- // Load pet if any and player is alive and not in taxi flight
- if(pCurrChar->isAlive() && pCurrChar->m_taxi.GetTaxiSource()==0)
- pCurrChar->LoadPet();
+ // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned)
+ pCurrChar->LoadPet();
// Set FFA PvP for non GM in non-rest mode
if(sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_RESTING) )
- pCurrChar->SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
+ pCurrChar->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
if(pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP))
pCurrChar->SetContestedPvP();
@@ -795,15 +868,7 @@ void WorldSession::HandleSetFactionAtWar( WorldPacket & recv_data )
recv_data >> repListID;
recv_data >> flag;
- FactionStateList::iterator itr = GetPlayer()->m_factions.find(repListID);
- if (itr == GetPlayer()->m_factions.end())
- return;
-
- // always invisible or hidden faction can't change war state
- if(itr->second.Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN) )
- return;
-
- GetPlayer()->SetFactionAtWar(&itr->second,flag);
+ GetPlayer()->GetReputationMgr().SetAtWar(repListID,flag);
}
//I think this function is never used :/ I dunno, but i guess this opcode not exists
@@ -811,7 +876,7 @@ void WorldSession::HandleSetFactionCheat( WorldPacket & /*recv_data*/ )
{
//CHECK_PACKET_SIZE(recv_data,4+4);
- //sLog.outDebug("WORLD SESSION: HandleSetFactionCheat");
+ sLog.outError("WORLD SESSION: HandleSetFactionCheat, not expected call, please report.");
/*
uint32 FactionID;
uint32 Standing;
@@ -831,7 +896,7 @@ void WorldSession::HandleSetFactionCheat( WorldPacket & /*recv_data*/ )
}
}
*/
- GetPlayer()->UpdateReputation();
+ GetPlayer()->GetReputationMgr().SendStates();
}
void WorldSession::HandleMeetingStoneInfo( WorldPacket & /*recv_data*/ )
@@ -867,14 +932,14 @@ void WorldSession::HandleTutorialFlag( WorldPacket & recv_data )
void WorldSession::HandleTutorialClear( WorldPacket & /*recv_data*/ )
{
- for ( uint32 iI = 0; iI < 8; iI++)
- GetPlayer()->SetTutorialInt( iI, 0xFFFFFFFF );
+ for (int i = 0; i < 8; ++i)
+ GetPlayer()->SetTutorialInt( i, 0xFFFFFFFF );
}
void WorldSession::HandleTutorialReset( WorldPacket & /*recv_data*/ )
{
- for ( uint32 iI = 0; iI < 8; iI++)
- GetPlayer()->SetTutorialInt( iI, 0x00000000 );
+ for (int i = 0; i < 8; ++i)
+ GetPlayer()->SetTutorialInt( i, 0x00000000 );
}
void WorldSession::HandleSetWatchedFactionIndexOpcode(WorldPacket & recv_data)
@@ -896,11 +961,7 @@ void WorldSession::HandleSetWatchedFactionInactiveOpcode(WorldPacket & recv_data
uint8 inactive;
recv_data >> replistid >> inactive;
- FactionStateList::iterator itr = _player->m_factions.find(replistid);
- if (itr == _player->m_factions.end())
- return;
-
- _player->SetFactionInactive(&itr->second, inactive);
+ _player->GetReputationMgr().SetInactive(replistid, inactive);
}
void WorldSession::HandleToggleHelmOpcode( WorldPacket & /*recv_data*/ )
@@ -917,11 +978,11 @@ void WorldSession::HandleToggleCloakOpcode( WorldPacket & /*recv_data*/ )
void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
{
+ CHECK_PACKET_SIZE(recv_data, 8+1);
+
uint64 guid;
std::string newname;
- CHECK_PACKET_SIZE(recv_data, 8+1);
-
recv_data >> guid;
recv_data >> newname;
@@ -929,15 +990,15 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
if(!normalizePlayerName(newname))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_NAME_NO_NAME;
+ data << uint8(CHAR_NAME_NO_NAME);
SendPacket( &data );
return;
}
- if(!ObjectMgr::IsValidName(newname,true))
+ if(!ObjectMgr::IsValidName(newname, true))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_NAME_INVALID_CHARACTER;
+ data << uint8(CHAR_NAME_INVALID_CHARACTER);
SendPacket( &data );
return;
}
@@ -946,7 +1007,7 @@ void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_NAME_RESERVED;
+ data << uint8(CHAR_NAME_RESERVED);
SendPacket( &data );
return;
}
@@ -975,7 +1036,7 @@ void WorldSession::HandleChangePlayerNameOpcodeCallBack(QueryResult *result, uin
if (!result)
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_CREATE_ERROR;
+ data << uint8(CHAR_CREATE_ERROR);
session->SendPacket( &data );
return;
}
@@ -989,11 +1050,11 @@ void WorldSession::HandleChangePlayerNameOpcodeCallBack(QueryResult *result, uin
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);
- sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s",session->GetAccountId(), session->GetRemoteAddress().c_str(), oldname.c_str(), guidLow, newname.c_str());
+ sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", session->GetAccountId(), session->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 << guid;
+ WorldPacket data(SMSG_CHAR_RENAME, 1+8+(newname.size()+1));
+ data << uint8(RESPONSE_SUCCESS);
+ data << uint64(guid);
data << newname;
session->SendPacket(&data);
}
@@ -1088,3 +1149,170 @@ void WorldSession::HandleDeclinedPlayerNameOpcode(WorldPacket& recv_data)
SendPacket(&data);
}
+void WorldSession::HandleAlterAppearance( WorldPacket & recv_data )
+{
+ sLog.outDebug("CMSG_ALTER_APPEARANCE");
+
+ CHECK_PACKET_SIZE(recv_data, 4+4+4);
+
+ uint32 Hair, Color, FacialHair;
+ recv_data >> Hair >> Color >> FacialHair;
+
+ BarberShopStyleEntry const* bs_hair = sBarberShopStyleStore.LookupEntry(Hair);
+
+ if(!bs_hair || bs_hair->type != 0 || bs_hair->race != _player->getRace() || bs_hair->gender != _player->getGender())
+ return;
+
+ BarberShopStyleEntry const* bs_facialHair = sBarberShopStyleStore.LookupEntry(FacialHair);
+
+ if(!bs_facialHair || bs_facialHair->type != 2 || bs_facialHair->race != _player->getRace() || bs_facialHair->gender != _player->getGender())
+ return;
+
+ uint32 Cost = _player->GetBarberShopCost(bs_hair->hair_id, Color, bs_facialHair->hair_id);
+
+ // 0 - ok
+ // 1,3 - not enough money
+ // 2 - you have to seat on barber chair
+ if(_player->GetMoney() < Cost)
+ {
+ WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4);
+ data << uint32(1); // no money
+ SendPacket(&data);
+ return;
+ }
+ else
+ {
+ WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4);
+ data << uint32(0); // ok
+ SendPacket(&data);
+ }
+
+ _player->ModifyMoney(-int32(Cost)); // it isn't free
+ _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, Cost);
+
+ _player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id));
+ _player->SetByteValue(PLAYER_BYTES, 3, uint8(Color));
+ _player->SetByteValue(PLAYER_BYTES_2, 0, uint8(bs_facialHair->hair_id));
+
+ _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1);
+
+ _player->SetStandState(0); // stand up
+}
+
+void WorldSession::HandleRemoveGlyph( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ uint32 slot;
+ recv_data >> slot;
+
+ if(slot >= MAX_GLYPH_SLOT_INDEX)
+ {
+ sLog.outDebug("Client sent wrong glyph slot number in opcode CMSG_REMOVE_GLYPH %u", slot);
+ return;
+ }
+
+ if(uint32 glyph = _player->GetGlyph(slot))
+ {
+ if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
+ {
+ _player->RemoveAurasDueToSpell(gp->SpellId);
+ _player->SetGlyph(slot, 0);
+ }
+ }
+}
+
+void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8+1);
+
+ uint64 guid;
+ std::string newname;
+
+ recv_data >> guid;
+ recv_data >> newname;
+
+ CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+1+1+1+1+1+1);
+
+ uint8 gender, skin, face, hairStyle, hairColor, facialHair;
+ recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face;
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid));
+ if (!result)
+ {
+ WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+ data << uint8(CHAR_CREATE_ERROR);
+ SendPacket( &data );
+ return;
+ }
+
+ Field *fields = result->Fetch();
+ uint32 at_loginFlags = fields[0].GetUInt32();
+ delete result;
+
+ if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE))
+ {
+ WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+ data << uint8(CHAR_CREATE_ERROR);
+ SendPacket( &data );
+ return;
+ }
+
+ // prevent character rename to invalid name
+ if(!normalizePlayerName(newname))
+ {
+ WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+ data << uint8(CHAR_NAME_NO_NAME);
+ SendPacket( &data );
+ return;
+ }
+
+ if(!ObjectMgr::IsValidName(newname,true))
+ {
+ WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+ data << uint8(CHAR_NAME_INVALID_CHARACTER);
+ SendPacket( &data );
+ return;
+ }
+
+ // check name limitations
+ if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
+ {
+ WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+ data << uint8(CHAR_NAME_RESERVED);
+ SendPacket( &data );
+ return;
+ }
+
+ // character with this name already exist
+ if(uint64 newguid = objmgr.GetPlayerGUIDByName(newname))
+ {
+ if(newguid != guid)
+ {
+ WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
+ data << uint8(CHAR_CREATE_NAME_IN_USE);
+ SendPacket( &data );
+ return;
+ }
+ }
+
+ CharacterDatabase.escape_string(newname);
+ Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair);
+ CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_CUSTOMIZE), GUID_LOPART(guid));
+ CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid));
+
+ std::string IP_str = GetRemoteAddress();
+ sLog.outChar("Account: %d (IP: %s), Character guid: %u Customized to: %s", GetAccountId(), IP_str.c_str(), GUID_LOPART(guid), newname.c_str());
+
+ WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1+8+(newname.size()+1)+6);
+ data << uint8(RESPONSE_SUCCESS);
+ data << uint64(guid);
+ data << newname;
+ data << uint8(gender);
+ data << uint8(skin);
+ data << uint8(face);
+ data << uint8(hairStyle);
+ data << uint8(hairColor);
+ data << uint8(facialHair);
+ SendPacket(&data);
+}
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index 5d0901b0596..31df4ee6718 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,11 +30,29 @@
#include "Player.h"
#include "UpdateMask.h"
#include "Chat.h"
-#include "MapManager.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
+#include "AccountMgr.h"
#include "TicketMgr.h"
+// Supported shift-links (client generated and server side)
+// |color|Harea:area_id|h[name]|h|r
+// |color|Hcreature:creature_guid|h[name]|h|r
+// |color|Hcreature_entry:creature_id|h[name]|h|r
+// |color|Hgameevent:id|h[name]|h|r
+// |color|Hgameobject:go_guid|h[name]|h|r
+// |color|Hgameobject_entry:go_id|h[name]|h|r
+// |color|Hitem:item_id:perm_ench_id:0:0|h[name]|h|r
+// |color|Hitemset:itemset_id|h[name]|h|r
+// |color|Hplayer:name|h[name]|h|r - client, in some messages, at click copy only name instead link
+// |color|Hquest:quest_id|h[name]|h|r
+// |color|Hskill:skill_id|h[name]|h|r
+// |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click
+// |color|Htalent:talent_id,rank|h[name]|h|r - client, talent icon shift-click
+// |color|Htaxinode:id|h[name]|h|r
+// |color|Htele:id|h[name]|h|r
+// |color|Htrade:spell_id,cur_value,max_value,unk3int,unk3str|h[name]|h|r - client, spellbook profession icon shift-click
+
bool ChatHandler::load_command_table = true;
ChatCommand * ChatHandler::getCommandTable()
@@ -52,168 +70,191 @@ ChatCommand * ChatHandler::getCommandTable()
{ "create", SEC_CONSOLE, true, &ChatHandler::HandleAccountCreateCommand, "", NULL },
{ "delete", SEC_CONSOLE, true, &ChatHandler::HandleAccountDeleteCommand, "", NULL },
{ "onlinelist", SEC_CONSOLE, true, &ChatHandler::HandleAccountOnlineListCommand, "", NULL },
+ { "lock", SEC_PLAYER, false, &ChatHandler::HandleAccountLockCommand, "", NULL },
{ "set", SEC_ADMINISTRATOR, true, NULL, "", accountSetCommandTable },
+ { "password", SEC_PLAYER, false, &ChatHandler::HandleAccountPasswordCommand, "", NULL },
{ "", SEC_PLAYER, false, &ChatHandler::HandleAccountCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand serverSetCommandTable[] =
+ static ChatCommand banCommandTable[] =
{
- { "loglevel", SEC_CONSOLE, true, &ChatHandler::HandleServerSetLogLevelCommand, "", NULL },
- { "difftime", SEC_CONSOLE, true, &ChatHandler::HandleServerSetDiffTimeCommand, "", NULL },
- { "motd", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerSetMotdCommand, "", NULL },
+ { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanAccountCommand, "", NULL },
+ { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanCharacterCommand, "", NULL },
+ { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanIPCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand serverIdleRestartCommandTable[] =
+ static ChatCommand baninfoCommandTable[] =
{
- { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
- { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerIdleRestartCommand, "", NULL },
+ { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoAccountCommand, "", NULL },
+ { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoCharacterCommand, "", NULL },
+ { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoIPCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand serverIdleShutdownCommandTable[] =
+ static ChatCommand banlistCommandTable[] =
{
- { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
- { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerIdleShutDownCommand, "", NULL },
+ { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListAccountCommand, "", NULL },
+ { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListCharacterCommand, "", NULL },
+ { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListIPCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand serverRestartCommandTable[] =
+ static ChatCommand castCommandTable[] =
{
- { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
- { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerRestartCommand, "", NULL },
+ { "back", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastBackCommand, "", NULL },
+ { "dist", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastDistCommand, "", NULL },
+ { "self", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastSelfCommand, "", NULL },
+ { "target", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastTargetCommand, "", NULL },
+ { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand serverShutdownCommandTable[] =
+ static ChatCommand characterCommandTable[] =
{
- { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
- { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCommand, "", NULL },
+ { "customize", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterCustomizeCommand, "", NULL },
+ { "delete", SEC_CONSOLE, true, &ChatHandler::HandleCharacterDeleteCommand, "", NULL },
+ { "level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterLevelCommand, "", NULL },
+ { "rename", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterRenameCommand, "", NULL },
+ { "reputation", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterReputationCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand serverCommandTable[] =
+ static ChatCommand debugPlayCommandTable[] =
{
- { "corpses", SEC_GAMEMASTER, true, &ChatHandler::HandleServerCorpsesCommand, "", NULL },
- { "exit", SEC_CONSOLE, true, &ChatHandler::HandleServerExitCommand, "", NULL },
- { "idlerestart", SEC_ADMINISTRATOR, true, NULL, "", serverIdleRestartCommandTable },
- { "idleshutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable },
- { "info", SEC_PLAYER, true, &ChatHandler::HandleServerInfoCommand, "", NULL },
- { "motd", SEC_PLAYER, true, &ChatHandler::HandleServerMotdCommand, "", NULL },
- { "restart", SEC_ADMINISTRATOR, true, NULL, "", serverRestartCommandTable },
- { "shutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable },
- { "set", SEC_ADMINISTRATOR, true, NULL, "", serverSetCommandTable },
- { NULL, 0, false, NULL, "", NULL }
+ { "cinematic", SEC_MODERATOR, false, &ChatHandler::HandleDebugPlayCinematicCommand, "", NULL },
+ { "movie", SEC_MODERATOR, false, &ChatHandler::HandleDebugPlayMovieCommand, "", NULL },
+ { "sound", SEC_MODERATOR, false, &ChatHandler::HandleDebugPlaySoundCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand modifyCommandTable[] =
+ static ChatCommand debugSendCommandTable[] =
{
- { "hp", SEC_MODERATOR, false, &ChatHandler::HandleModifyHPCommand, "", NULL },
- { "mana", SEC_MODERATOR, false, &ChatHandler::HandleModifyManaCommand, "", NULL },
- { "rage", SEC_MODERATOR, false, &ChatHandler::HandleModifyRageCommand, "", NULL },
- { "energy", SEC_MODERATOR, false, &ChatHandler::HandleModifyEnergyCommand, "", NULL },
- { "money", SEC_MODERATOR, false, &ChatHandler::HandleModifyMoneyCommand, "", NULL },
- { "speed", SEC_MODERATOR, false, &ChatHandler::HandleModifySpeedCommand, "", NULL },
- { "swim", SEC_MODERATOR, false, &ChatHandler::HandleModifySwimCommand, "", NULL },
- { "scale", SEC_MODERATOR, false, &ChatHandler::HandleModifyScaleCommand, "", NULL },
- { "bit", SEC_MODERATOR, false, &ChatHandler::HandleModifyBitCommand, "", NULL },
- { "bwalk", SEC_MODERATOR, false, &ChatHandler::HandleModifyBWalkCommand, "", NULL },
- { "fly", SEC_MODERATOR, false, &ChatHandler::HandleModifyFlyCommand, "", NULL },
- { "aspeed", SEC_MODERATOR, false, &ChatHandler::HandleModifyASpeedCommand, "", NULL },
- { "faction", SEC_MODERATOR, false, &ChatHandler::HandleModifyFactionCommand, "", NULL },
- { "spell", SEC_MODERATOR, false, &ChatHandler::HandleModifySpellCommand, "", NULL },
- { "tp", SEC_MODERATOR, false, &ChatHandler::HandleModifyTalentCommand, "", NULL },
- { "titles", SEC_MODERATOR, false, &ChatHandler::HandleModifyKnownTitlesCommand, "", NULL },
- { "mount", SEC_MODERATOR, false, &ChatHandler::HandleModifyMountCommand, "", NULL },
- { "honor", SEC_MODERATOR, false, &ChatHandler::HandleModifyHonorCommand, "", NULL },
- { "rep", SEC_MODERATOR, false, &ChatHandler::HandleModifyRepCommand, "", NULL },
- { "arena", SEC_MODERATOR, false, &ChatHandler::HandleModifyArenaCommand, "", NULL },
- { "drunk", SEC_MODERATOR, false, &ChatHandler::HandleDrunkCommand, "", NULL },
- { "standstate", SEC_GAMEMASTER, false, &ChatHandler::HandleStandStateCommand, "", NULL },
- { "morph", SEC_GAMEMASTER, false, &ChatHandler::HandleMorphCommand, "", NULL },
- { "gender", SEC_ADMINISTRATOR, false, &ChatHandler::HandleModifyGenderCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
+ { "buyerror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendBuyErrorCommand, "", NULL },
+ { "channelnotify", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendChannelNotifyCommand, "", NULL },
+ { "chatmmessage", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendChatMsgCommand, "", NULL },
+ { "equiperror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendEquipErrorCommand, "", NULL },
+ { "largepacket", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendLargePacketCommand, "", NULL },
+ { "opcode", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendOpcodeCommand, "", NULL },
+ { "poi", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendPoiCommand, "", NULL },
+ { "qpartymsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendQuestPartyMsgCommand, "", NULL },
+ { "qinvalidmsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendQuestInvalidMsgCommand, "", NULL },
+ { "sellerror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendSellErrorCommand, "", NULL },
+ { "setphaseshift", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendSetPhaseShiftCommand, "", NULL },
+ { "spellfail", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendSpellFailCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand wpCommandTable[] =
+ static ChatCommand debugCommandTable[] =
{
- { "show", SEC_GAMEMASTER, false, &ChatHandler::HandleWpShowCommand, "", NULL },
- { "addwp", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL },
- { "load", SEC_GAMEMASTER, false, &ChatHandler::HandleWpLoadPathCommand, "", NULL },
- { "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL },
- { "event", SEC_GAMEMASTER, false, &ChatHandler::HandleWpEventCommand, "", NULL },
- { "unload", SEC_GAMEMASTER, false, &ChatHandler::HandleWpUnLoadPathCommand, "", NULL },
+ { "setbit", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSet32Bit, "", NULL },
+ { "threat", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugThreatList, "", NULL },
+ { "hostil", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugHostilRefList, "", NULL },
+ { "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugAnimCommand, "", NULL },
+ { "arena", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugArenaCommand, "", NULL },
+ { "bg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugBattlegroundCommand, "", NULL },
+ { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemState, "", NULL },
+ { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugGetLootRecipient, "", NULL },
+ { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetValue, "", NULL },
+ { "Mod32Value", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugMod32Value, "", NULL },
+ { "play", SEC_MODERATOR, false, NULL, "", debugPlayCommandTable },
+ { "send", SEC_ADMINISTRATOR, false, NULL, "", debugSendCommandTable },
+ { "setitemflag", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetItemFlagCommand, "", NULL },
+ { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValue, "", NULL },
+ { "spawnvehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSpawnVehicle, "", NULL },
+ { "setvid", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetVehicleId, "", NULL },
+ { "entervehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugEnterVehicle, "", NULL },
+ { "uws", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdateWorldStateCommand, "", NULL },
+ { "update", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdate, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+ static ChatCommand eventCommandTable[] =
+ {
+ { "activelist", SEC_GAMEMASTER, true, &ChatHandler::HandleEventActiveListCommand, "", NULL },
+ { "start", SEC_GAMEMASTER, true, &ChatHandler::HandleEventStartCommand, "", NULL },
+ { "stop", SEC_GAMEMASTER, true, &ChatHandler::HandleEventStopCommand, "", NULL },
+ { "", SEC_GAMEMASTER, true, &ChatHandler::HandleEventInfoCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
-
- static ChatCommand banCommandTable[] =
+ static ChatCommand gmCommandTable[] =
{
- { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanAccountCommand, "", NULL },
- { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanCharacterCommand, "", NULL },
- { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanIPCommand, "", NULL },
+ { "chat", SEC_MODERATOR, false, &ChatHandler::HandleGMChatCommand, "", NULL },
+ { "fly", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGMFlyCommand, "", NULL },
+ { "ingame", SEC_PLAYER, true, &ChatHandler::HandleGMListIngameCommand, "", NULL },
+ { "list", SEC_ADMINISTRATOR, true, &ChatHandler::HandleGMListFullCommand, "", NULL },
+ { "visible", SEC_MODERATOR, false, &ChatHandler::HandleGMVisibleCommand, "", NULL },
+ { "", SEC_MODERATOR, false, &ChatHandler::HandleGMCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand baninfoCommandTable[] =
+ static ChatCommand goCommandTable[] =
{
- { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoAccountCommand, "", NULL },
- { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoCharacterCommand, "", NULL },
- { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoIPCommand, "", NULL },
+ { "creature", SEC_MODERATOR, false, &ChatHandler::HandleGoCreatureCommand, "", NULL },
+ { "graveyard", SEC_MODERATOR, false, &ChatHandler::HandleGoGraveyardCommand, "", NULL },
+ { "grid", SEC_MODERATOR, false, &ChatHandler::HandleGoGridCommand, "", NULL },
+ { "object", SEC_MODERATOR, false, &ChatHandler::HandleGoObjectCommand, "", NULL },
+ { "taxinode", SEC_MODERATOR, false, &ChatHandler::HandleGoTaxinodeCommand, "", NULL },
+ { "trigger", SEC_MODERATOR, false, &ChatHandler::HandleGoTriggerCommand, "", NULL },
+ { "zonexy", SEC_MODERATOR, false, &ChatHandler::HandleGoZoneXYCommand, "", NULL },
+ { "xy", SEC_MODERATOR, false, &ChatHandler::HandleGoXYCommand, "", NULL },
+ { "xyz", SEC_MODERATOR, false, &ChatHandler::HandleGoXYZCommand, "", NULL },
+ { "", SEC_MODERATOR, false, &ChatHandler::HandleGoXYZCommand, "", NULL },
+
+ { "ticket", SEC_MODERATOR, false, &ChatHandler::HandleGoTicketCommand, "", NULL },
+
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand banlistCommandTable[] =
+ static ChatCommand gobjectCommandTable[] =
{
- { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListAccountCommand, "", NULL },
- { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListCharacterCommand, "", NULL },
- { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListIPCommand, "", NULL },
+ { "activate", SEC_GAMEMASTER, false, &ChatHandler::HandleActivateObjectCommand, "", NULL },
+ { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectAddCommand, "", NULL },
+ { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectDeleteCommand, "", NULL },
+ { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectMoveCommand, "", NULL },
+ { "near", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectNearCommand, "", NULL },
+ { "state", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectStateCommand, "", NULL },
+ { "setphase", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectPhaseCommand, "", NULL },
+ { "target", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTargetCommand, "", NULL },
+ { "tempadd", SEC_GAMEMASTER, false, &ChatHandler::HandleTempGameObjectCommand, "", NULL },
+ { "turn", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTurnCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand unbanCommandTable[] =
+ static ChatCommand groupCommandTable[] =
{
- { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanAccountCommand, "", NULL },
- { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanCharacterCommand, "", NULL },
- { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanIPCommand, "", NULL },
+ { "leader", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGroupLeaderCommand, "", NULL },
+ { "disband", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGroupDisbandCommand, "", NULL },
+ { "remove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGroupRemoveCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand guildCommandTable[] =
+ {
+ { "create", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildCreateCommand, "", NULL },
+ { "delete", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildDeleteCommand, "", NULL },
+ { "invite", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildInviteCommand, "", NULL },
+ { "uninvite", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildUninviteCommand, "", NULL },
+ { "rank", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildRankCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand debugCommandTable[] =
+ static ChatCommand honorCommandTable[] =
{
- { "inarc", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugInArcCommand, "", NULL },
- { "spellfail", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSpellFailCommand, "", NULL },
- { "setpoi", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSetPoiCommand, "", NULL },
- { "qpartymsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSendQuestPartyMsgCommand, "", NULL },
- { "qinvalidmsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSendQuestInvalidMsgCommand, "", NULL },
- { "equiperr", SEC_ADMINISTRATOR, false, &ChatHandler::HandleEquipErrorCommand, "", NULL },
- { "sellerr", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSellErrorCommand, "", NULL },
- { "buyerr", SEC_ADMINISTRATOR, false, &ChatHandler::HandleBuyErrorCommand, "", NULL },
- { "sendopcode", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSendOpcodeCommand, "", NULL },
- { "uws", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUpdateWorldStateCommand, "", NULL },
- { "ps", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePlaySound2Command, "", NULL },
- { "scn", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSendChannelNotifyCommand, "", NULL },
- { "scm", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSendChatMsgCommand, "", NULL },
- { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGetItemState, "", NULL },
- { "playsound", SEC_MODERATOR, false, &ChatHandler::HandlePlaySoundCommand, "", NULL },
- { "update", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUpdate, "", NULL },
- { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSetValue, "", NULL },
- { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGetValue, "", NULL },
- { "Mod32Value", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMod32Value, "", NULL },
- { "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleAnimCommand, "", NULL },
- { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleGetLootRecipient, "", NULL },
- { "arena", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugArenaCommand, "", NULL },
+ { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorAddCommand, "", NULL },
+ { "addkill", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorAddKillCommand, "", NULL },
+ { "update", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorUpdateCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand eventCommandTable[] =
+ static ChatCommand instanceCommandTable[] =
{
- { "activelist", SEC_GAMEMASTER, true, &ChatHandler::HandleEventActiveListCommand, "", NULL },
- { "start", SEC_GAMEMASTER, true, &ChatHandler::HandleEventStartCommand, "", NULL },
- { "stop", SEC_GAMEMASTER, true, &ChatHandler::HandleEventStopCommand, "", NULL },
- { "", SEC_GAMEMASTER, true, &ChatHandler::HandleEventInfoCommand, "", NULL },
+ { "listbinds", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceListBindsCommand, "", NULL },
+ { "unbind", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceUnbindCommand, "", NULL },
+ { "stats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleInstanceStatsCommand, "", NULL },
+ { "savedata", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceSaveDataCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
@@ -225,6 +266,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "all_default", SEC_MODERATOR, false, &ChatHandler::HandleLearnAllDefaultCommand, "", NULL },
{ "all_lang", SEC_MODERATOR, false, &ChatHandler::HandleLearnAllLangCommand, "", NULL },
{ "all_myclass", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMyClassCommand, "", NULL },
+ { "all_mypettalents",SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMyPetTalentsCommand,"", NULL },
{ "all_myspells", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMySpellsCommand, "", NULL },
{ "all_mytalents", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMyTalentsCommand, "", NULL },
{ "all_recipes", SEC_GAMEMASTER, false, &ChatHandler::HandleLearnAllRecipesCommand, "", NULL },
@@ -232,31 +274,169 @@ ChatCommand * ChatHandler::getCommandTable()
{ NULL, 0, false, NULL, "", NULL }
};
+ static ChatCommand listCommandTable[] =
+ {
+ { "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListCreatureCommand, "", NULL },
+ { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListItemCommand, "", NULL },
+ { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListObjectCommand, "", NULL },
+ { "auras", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListAurasCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand lookupPlayerCommandTable[] =
+ {
+ { "ip", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerIpCommand, "", NULL },
+ { "account", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerAccountCommand, "", NULL },
+ { "email", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerEmailCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand lookupCommandTable[] =
+ {
+ { "area", SEC_MODERATOR, true, &ChatHandler::HandleLookupAreaCommand, "", NULL },
+ { "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupCreatureCommand, "", NULL },
+ { "event", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupEventCommand, "", NULL },
+ { "faction", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupFactionCommand, "", NULL },
+ { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupItemCommand, "", NULL },
+ { "itemset", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupItemSetCommand, "", NULL },
+ { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupObjectCommand, "", NULL },
+ { "quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupQuestCommand, "", NULL },
+ { "player", SEC_GAMEMASTER, true, NULL, "", lookupPlayerCommandTable },
+ { "skill", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSkillCommand, "", NULL },
+ { "spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSpellCommand, "", NULL },
+ { "taxinode", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupTaxiNodeCommand, "", NULL },
+ { "tele", SEC_MODERATOR, true, &ChatHandler::HandleLookupTeleCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand modifyCommandTable[] =
+ {
+ { "hp", SEC_MODERATOR, false, &ChatHandler::HandleModifyHPCommand, "", NULL },
+ { "mana", SEC_MODERATOR, false, &ChatHandler::HandleModifyManaCommand, "", NULL },
+ { "rage", SEC_MODERATOR, false, &ChatHandler::HandleModifyRageCommand, "", NULL },
+ { "runicpower", SEC_MODERATOR, false, &ChatHandler::HandleModifyRunicPowerCommand, "", NULL },
+ { "energy", SEC_MODERATOR, false, &ChatHandler::HandleModifyEnergyCommand, "", NULL },
+ { "money", SEC_MODERATOR, false, &ChatHandler::HandleModifyMoneyCommand, "", NULL },
+ { "speed", SEC_MODERATOR, false, &ChatHandler::HandleModifySpeedCommand, "", NULL },
+ { "swim", SEC_MODERATOR, false, &ChatHandler::HandleModifySwimCommand, "", NULL },
+ { "scale", SEC_MODERATOR, false, &ChatHandler::HandleModifyScaleCommand, "", NULL },
+ { "bit", SEC_MODERATOR, false, &ChatHandler::HandleModifyBitCommand, "", NULL },
+ { "bwalk", SEC_MODERATOR, false, &ChatHandler::HandleModifyBWalkCommand, "", NULL },
+ { "fly", SEC_MODERATOR, false, &ChatHandler::HandleModifyFlyCommand, "", NULL },
+ { "aspeed", SEC_MODERATOR, false, &ChatHandler::HandleModifyASpeedCommand, "", NULL },
+ { "faction", SEC_MODERATOR, false, &ChatHandler::HandleModifyFactionCommand, "", NULL },
+ { "spell", SEC_MODERATOR, false, &ChatHandler::HandleModifySpellCommand, "", NULL },
+ { "tp", SEC_MODERATOR, false, &ChatHandler::HandleModifyTalentCommand, "", NULL },
+ { "titles", SEC_MODERATOR, false, &ChatHandler::HandleModifyKnownTitlesCommand, "", NULL },
+ { "mount", SEC_MODERATOR, false, &ChatHandler::HandleModifyMountCommand, "", NULL },
+ { "honor", SEC_MODERATOR, false, &ChatHandler::HandleModifyHonorCommand, "", NULL },
+ { "rep", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyRepCommand, "", NULL },
+ { "arena", SEC_MODERATOR, false, &ChatHandler::HandleModifyArenaCommand, "", NULL },
+ { "drunk", SEC_MODERATOR, false, &ChatHandler::HandleModifyDrunkCommand, "", NULL },
+ { "standstate", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyStandStateCommand, "", NULL },
+ { "morph", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyMorphCommand, "", NULL },
+ { "phase", SEC_ADMINISTRATOR, false, &ChatHandler::HandleModifyPhaseCommand, "", NULL },
+ { "gender", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyGenderCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand npcCommandTable[] =
+ {
+ { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddCommand, "", NULL },
+ { "additem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddVendorItemCommand, "", NULL },
+ { "addmove", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddMoveCommand, "", NULL },
+ { "allowmove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAllowMovementCommand, "", NULL },
+ { "changeentry", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcChangeEntryCommand, "", NULL },
+ { "changelevel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcChangeLevelCommand, "", NULL },
+ { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDeleteCommand, "", NULL },
+ { "delitem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDelVendorItemCommand, "", NULL },
+ { "factionid", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFactionIdCommand, "", NULL },
+ { "flag", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFlagCommand, "", NULL },
+ { "follow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFollowCommand, "", NULL },
+ { "info", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcInfoCommand, "", NULL },
+ { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcMoveCommand, "", NULL },
+ { "playemote", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcPlayEmoteCommand, "", NULL },
+ { "setmodel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetModelCommand, "", NULL },
+ { "setmovetype", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetMoveTypeCommand, "", NULL },
+ { "setphase", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetPhaseCommand, "", NULL },
+ { "spawndist", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnDistCommand, "", NULL },
+ { "spawntime", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnTimeCommand, "", NULL },
+ { "say", SEC_MODERATOR, false, &ChatHandler::HandleNpcSayCommand, "", NULL },
+ { "textemote", SEC_MODERATOR, false, &ChatHandler::HandleNpcTextEmoteCommand, "", NULL },
+ { "unfollow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcUnFollowCommand, "", NULL },
+ { "whisper", SEC_MODERATOR, false, &ChatHandler::HandleNpcWhisperCommand, "", NULL },
+ { "yell", SEC_MODERATOR, false, &ChatHandler::HandleNpcYellCommand, "", NULL },
+ { "tempadd", SEC_GAMEMASTER, false, &ChatHandler::HandleTempAddSpwCommand, "", NULL },
+ { "tame", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcTameCommand, "", NULL },
+ { "setdeathstate", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetDeathStateCommand, "", NULL },
+ { "addformation", SEC_MODERATOR, false, &ChatHandler::HandleNpcAddFormationCommand, "", NULL },
+
+ //{ TODO: fix or remove this commands
+ { "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAddWeaponCommand, "", NULL },
+ { "name", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcNameCommand, "", NULL },
+ { "subname", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSubNameCommand, "", NULL },
+ //}
+
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand petCommandTable[] =
+ {
+ { "create", SEC_GAMEMASTER, false, &ChatHandler::HandleCreatePetCommand, "", NULL },
+ { "learn", SEC_GAMEMASTER, false, &ChatHandler::HandlePetLearnCommand, "", NULL },
+ { "unlearn", SEC_GAMEMASTER, false, &ChatHandler::HandlePetUnlearnCommand, "", NULL },
+ { "tp", SEC_GAMEMASTER, false, &ChatHandler::HandlePetTpCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand pdumpCommandTable[] =
+ {
+ { "load", SEC_ADMINISTRATOR, true, &ChatHandler::HandlePDumpLoadCommand, "", NULL },
+ { "write", SEC_ADMINISTRATOR, true, &ChatHandler::HandlePDumpWriteCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand questCommandTable[] =
+ {
+ { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestAdd, "", NULL },
+ { "complete", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestComplete, "", NULL },
+ { "remove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestRemove, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
static ChatCommand reloadCommandTable[] =
{
{ "all", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllCommand, "", NULL },
+ { "all_achievement",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAchievementCommand,"", NULL },
+ { "all_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAreaCommand, "", NULL },
+ { "all_eventai", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllEventAICommand, "", NULL },
+ { "all_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllItemCommand, "", NULL },
+ { "all_locales", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLocalesCommand, "", NULL },
{ "all_loot", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLootCommand, "", NULL },
{ "all_npc", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllNpcCommand, "", NULL },
{ "all_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllQuestCommand, "", NULL },
{ "all_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllScriptsCommand, "", NULL },
{ "all_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllSpellCommand, "", NULL },
- { "all_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllItemCommand, "", NULL },
- { "all_locales", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLocalesCommand, "", NULL },
{ "config", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadConfigCommand, "", NULL },
+ { "achievement_criteria_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAchievementCriteriaDataCommand, "", NULL },
+ { "achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAchievementRewardCommand, "", NULL },
+ { "areatrigger_involvedrelation",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL },
{ "areatrigger_tavern", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL },
{ "areatrigger_teleport", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL },
{ "access_requirement", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAccessRequirementCommand, "", NULL },
- { "areatrigger_involvedrelation",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL },
- { "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL },
{ "command", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommandCommand, "", NULL },
+ { "creature_ai_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAIScriptsCommand, "", NULL },
+ { "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", NULL },
+ { "creature_ai_texts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAITextsCommand, "", NULL },
{ "creature_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand,"",NULL },
{ "creature_linked_respawn", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureLinkedRespawnCommand, "", NULL },
{ "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL },
{ "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL },
//{ "db_script_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDbScriptStringCommand, "", NULL },
{ "disenchant_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL },
+ { "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL },
{ "fishing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesFishingCommand, "", NULL },
{ "game_graveyard_zone", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameGraveyardZoneCommand, "", NULL },
{ "game_tele", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameTeleCommand, "", NULL },
@@ -266,16 +446,27 @@ ChatCommand * ChatHandler::getCommandTable()
{ "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL },
{ "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL },
{ "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL },
- { "trinity_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadTrinityStringCommand, "", NULL },
+ { "locales_achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesAchievementRewardCommand,"", NULL },
+ { "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL },
+ { "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL },
+ { "locales_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesItemCommand, "", NULL },
+ { "locales_npc_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesNpcTextCommand, "", NULL },
+ { "locales_page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPageTextCommand, "", NULL },
+ { "locales_points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPointsOfInterestCommand, "", NULL },
+ { "locales_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesQuestCommand, "", NULL },
+// { "auctions", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAuctionsCommand, "", NULL },
+ { "milling_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesMillingCommand, "", NULL },
{ "npc_gossip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcGossipCommand, "", NULL },
{ "npc_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcOptionCommand, "", NULL },
+ { "npc_spellclick_spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellClickSpellsCommand, "",NULL},
{ "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL },
{ "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL },
{ "page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPageTextsCommand, "", NULL },
{ "pickpocketing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand,"",NULL},
+ { "points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPointsOfInterestCommand, "",NULL},
{ "prospecting_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesProspectingCommand,"", NULL },
- { "quest_mail_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesQuestMailCommand, "", NULL },
{ "quest_end_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestEndScriptsCommand, "", NULL },
+ { "quest_mail_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesQuestMailCommand, "", NULL },
{ "quest_start_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestStartScriptsCommand, "", NULL },
{ "quest_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestTemplateCommand, "", NULL },
{ "reference_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesReferenceCommand, "", NULL },
@@ -286,8 +477,11 @@ ChatCommand * ChatHandler::getCommandTable()
{ "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL },
{ "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL },
{ "spell_required", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellRequiredCommand, "", NULL },
+ { "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL },
+ { "spell_bonus_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellBonusesCommand, "", NULL },
{ "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL },
{ "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL },
+ { "spell_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSpellCommand, "", NULL },
{ "spell_linked_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLinkedSpellCommand, "", NULL },
{ "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL },
{ "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL },
@@ -296,218 +490,115 @@ ChatCommand * ChatHandler::getCommandTable()
{ "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL },
{ "spell_threats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL },
{ "spell_disabled", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellDisabledCommand, "", NULL },
- { "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL },
- { "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL },
- { "locales_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesItemCommand, "", NULL },
- { "locales_npc_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesNpcTextCommand, "", NULL },
- { "locales_page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPageTextCommand, "", NULL },
- { "locales_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesQuestCommand, "", NULL },
+ { "trinity_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadTrinityStringCommand, "", NULL },
{ "auctions", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAuctionsCommand, "", NULL },
{ "waypoint_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadWpScriptsCommand, "", NULL },
{ "gm_tickets", SEC_ADMINISTRATOR, true, &ChatHandler::HandleGMTicketReloadCommand, "", NULL },
- { "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand honorCommandTable[] =
- {
- { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleAddHonorCommand, "", NULL },
- { "addkill", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorAddKillCommand, "", NULL },
- { "update", SEC_GAMEMASTER, false, &ChatHandler::HandleUpdateHonorFieldsCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
- };
-
- static ChatCommand guildCommandTable[] =
- {
- { "create", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildCreateCommand, "", NULL },
- { "delete", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildDeleteCommand, "", NULL },
- { "invite", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildInviteCommand, "", NULL },
- { "uninvite", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildUninviteCommand, "", NULL },
- { "rank", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildRankCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
- };
-
- static ChatCommand petCommandTable[] =
- {
- { "create", SEC_GAMEMASTER, false, &ChatHandler::HandleCreatePetCommand, "", NULL },
- { "learn", SEC_GAMEMASTER, false, &ChatHandler::HandlePetLearnCommand, "", NULL },
- { "unlearn", SEC_GAMEMASTER, false, &ChatHandler::HandlePetUnlearnCommand, "", NULL },
- { "tp", SEC_GAMEMASTER, false, &ChatHandler::HandlePetTpCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
- };
-
-
- static ChatCommand groupCommandTable[] =
- {
- { "leader", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGroupLeaderCommand, "", NULL },
- { "disband", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGroupDisbandCommand, "", NULL },
- { "remove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGroupRemoveCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
- };
-
- static ChatCommand lookupPlayerCommandTable[] =
- {
- { "ip", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerIpCommand, "", NULL },
- { "account", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerAccountCommand, "", NULL },
- { "email", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerEmailCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
- };
-
- static ChatCommand lookupCommandTable[] =
- {
- { "area", SEC_MODERATOR, true, &ChatHandler::HandleLookupAreaCommand, "", NULL },
- { "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupCreatureCommand, "", NULL },
- { "event", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupEventCommand, "", NULL },
- { "faction", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupFactionCommand, "", NULL },
- { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupItemCommand, "", NULL },
- { "itemset", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupItemSetCommand, "", NULL },
- { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupObjectCommand, "", NULL },
- { "quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupQuestCommand, "", NULL },
- { "player", SEC_GAMEMASTER, true, NULL, "", lookupPlayerCommandTable },
- { "skill", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSkillCommand, "", NULL },
- { "spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSpellCommand, "", NULL },
- { "tele", SEC_MODERATOR, true, &ChatHandler::HandleLookupTeleCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
- };
-
static ChatCommand resetCommandTable[] =
{
- { "honor", SEC_ADMINISTRATOR, false, &ChatHandler::HandleResetHonorCommand, "", NULL },
- { "level", SEC_ADMINISTRATOR, false, &ChatHandler::HandleResetLevelCommand, "", NULL },
- { "spells", SEC_ADMINISTRATOR, false, &ChatHandler::HandleResetSpellsCommand, "", NULL },
- { "stats", SEC_ADMINISTRATOR, false, &ChatHandler::HandleResetStatsCommand, "", NULL },
- { "talents", SEC_ADMINISTRATOR, false, &ChatHandler::HandleResetTalentsCommand, "", NULL },
- { "all", SEC_ADMINISTRATOR, false, &ChatHandler::HandleResetAllCommand, "", NULL },
+ { "achievements", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetAchievementsCommand, "", NULL },
+ { "honor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetHonorCommand, "", NULL },
+ { "level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetLevelCommand, "", NULL },
+ { "spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetSpellsCommand, "", NULL },
+ { "stats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetStatsCommand, "", NULL },
+ { "talents", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetTalentsCommand, "", NULL },
+ { "all", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetAllCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand castCommandTable[] =
+ static ChatCommand sendCommandTable[] =
{
- { "back", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastBackCommand, "", NULL },
- { "dist", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastDistCommand, "", NULL },
- { "self", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastSelfCommand, "", NULL },
- { "target", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastTargetCommand, "", NULL },
- { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastCommand, "", NULL },
+ { "items", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendItemsCommand, "", NULL },
+ { "mail", SEC_MODERATOR, true, &ChatHandler::HandleSendMailCommand, "", NULL },
+ { "message", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMessageCommand, "", NULL },
+ { "money", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMoneyCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand pdumpCommandTable[] =
+ static ChatCommand serverIdleRestartCommandTable[] =
{
- { "load", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLoadPDumpCommand, "", NULL },
- { "write", SEC_ADMINISTRATOR, true, &ChatHandler::HandleWritePDumpCommand, "", NULL },
+ { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
+ { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerIdleRestartCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand listCommandTable[] =
+ static ChatCommand serverIdleShutdownCommandTable[] =
{
- { "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListCreatureCommand, "", NULL },
- { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListItemCommand, "", NULL },
- { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListObjectCommand, "", NULL },
- { "auras", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListAurasCommand, "", NULL },
+ { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
+ { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerIdleShutDownCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand teleCommandTable[] =
+ static ChatCommand serverRestartCommandTable[] =
{
- { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddTeleCommand, "", NULL },
- { "del", SEC_ADMINISTRATOR, true, &ChatHandler::HandleDelTeleCommand, "", NULL },
- { "name", SEC_MODERATOR, true, &ChatHandler::HandleNameTeleCommand, "", NULL },
- { "group", SEC_MODERATOR, false, &ChatHandler::HandleGroupTeleCommand, "", NULL },
- { "", SEC_MODERATOR, false, &ChatHandler::HandleTeleCommand, "", NULL },
+ { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
+ { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerRestartCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand npcCommandTable[] =
+ static ChatCommand serverShutdownCommandTable[] =
{
- { "say", SEC_MODERATOR, false, &ChatHandler::HandleNpcSayCommand, "", NULL },
- { "textemote", SEC_MODERATOR, false, &ChatHandler::HandleNpcTextEmoteCommand, "", NULL },
- { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddCommand, "", NULL },
- { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDeleteCommand, "", NULL },
- { "spawndist", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnDistCommand, "", NULL },
- { "spawntime", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnTimeCommand, "", NULL },
- { "factionid", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFactionIdCommand, "", NULL },
- { "addmove", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddMoveCommand, "", NULL },
- { "setmovetype", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetMoveTypeCommand, "", NULL },
- { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcMoveCommand, "", NULL },
- { "changelevel", SEC_GAMEMASTER, false, &ChatHandler::HandleChangeLevelCommand, "", NULL },
- { "setmodel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetModelCommand, "", NULL },
- { "additem", SEC_GAMEMASTER, false, &ChatHandler::HandleAddVendorItemCommand, "", NULL },
- { "delitem", SEC_GAMEMASTER, false, &ChatHandler::HandleDelVendorItemCommand, "", NULL },
- { "flag", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFlagCommand, "", NULL },
- { "changeentry", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcChangeEntryCommand, "", NULL },
- { "info", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcInfoCommand, "", NULL },
- { "playemote", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcPlayEmoteCommand, "", NULL },
- { "follow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFollowCommand, "", NULL },
- { "unfollow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcUnFollowCommand, "", NULL },
- { "whisper", SEC_MODERATOR, false, &ChatHandler::HandleNpcWhisperCommand, "", NULL },
- { "yell", SEC_MODERATOR, false, &ChatHandler::HandleNpcYellCommand, "", NULL },
- { "addtemp", SEC_GAMEMASTER, false, &ChatHandler::HandleTempAddSpwCommand, "", NULL },
- { "addformation", SEC_MODERATOR, false, &ChatHandler::HandleNpcAddFormationCommand, "", NULL },
+ { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
+ { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCommand, "", NULL },
{ "setlink", SEC_MODERATOR, false, &ChatHandler::HandleNpcSetLinkCommand, "", NULL },
-
- //{ TODO: fix or remove this commands
- { "name", SEC_GAMEMASTER, false, &ChatHandler::HandleNameCommand, "", NULL },
- { "subname", SEC_GAMEMASTER, false, &ChatHandler::HandleSubNameCommand, "", NULL },
- { "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddWeaponCommand, "", NULL },
- //}
-
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand goCommandTable[] =
+ static ChatCommand serverSetCommandTable[] =
{
- { "grid", SEC_MODERATOR, false, &ChatHandler::HandleGoGridCommand, "", NULL },
- { "creature", SEC_GAMEMASTER, false, &ChatHandler::HandleGoCreatureCommand, "", NULL },
- { "object", SEC_GAMEMASTER, false, &ChatHandler::HandleGoObjectCommand, "", NULL },
- { "ticket", SEC_MODERATOR, false, &ChatHandler::HandleGoTicketCommand, "", NULL },
- { "trigger", SEC_GAMEMASTER, false, &ChatHandler::HandleGoTriggerCommand, "", NULL },
- { "graveyard", SEC_GAMEMASTER, false, &ChatHandler::HandleGoGraveyardCommand, "", NULL },
- { "zonexy", SEC_MODERATOR, false, &ChatHandler::HandleGoZoneXYCommand, "", NULL },
- { "xy", SEC_MODERATOR, false, &ChatHandler::HandleGoXYCommand, "", NULL },
- { "xyz", SEC_MODERATOR, false, &ChatHandler::HandleGoXYZCommand, "", NULL },
- { "", SEC_MODERATOR, false, &ChatHandler::HandleGoXYZCommand, "", NULL },
+ { "difftime", SEC_CONSOLE, true, &ChatHandler::HandleServerSetDiffTimeCommand, "", NULL },
+ { "loglevel", SEC_CONSOLE, true, &ChatHandler::HandleServerSetLogLevelCommand, "", NULL },
+ { "logfilelevel", SEC_CONSOLE, true, &ChatHandler::HandleServerSetLogFileLevelCommand, "", NULL },
+ { "motd", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerSetMotdCommand, "", NULL },
+ { "closed", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerSetClosedCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand gobjectCommandTable[] =
+ static ChatCommand serverCommandTable[] =
{
- { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectCommand, "", NULL },
- { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleDelObjectCommand, "", NULL },
- { "target", SEC_GAMEMASTER, false, &ChatHandler::HandleTargetObjectCommand, "", NULL },
- { "turn", SEC_GAMEMASTER, false, &ChatHandler::HandleTurnObjectCommand, "", NULL },
- { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleMoveObjectCommand, "", NULL },
- { "near", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNearObjectCommand, "", NULL },
- { "activate", SEC_GAMEMASTER, false, &ChatHandler::HandleActivateObjectCommand, "", NULL },
- { "addtemp", SEC_GAMEMASTER, false, &ChatHandler::HandleTempGameObjectCommand, "", NULL },
+ { "corpses", SEC_GAMEMASTER, true, &ChatHandler::HandleServerCorpsesCommand, "", NULL },
+ { "exit", SEC_CONSOLE, true, &ChatHandler::HandleServerExitCommand, "", NULL },
+ { "idlerestart", SEC_ADMINISTRATOR, true, NULL, "", serverIdleRestartCommandTable },
+ { "idleshutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable },
+ { "info", SEC_PLAYER, true, &ChatHandler::HandleServerInfoCommand, "", NULL },
+ { "motd", SEC_PLAYER, true, &ChatHandler::HandleServerMotdCommand, "", NULL },
+ { "plimit", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerPLimitCommand, "", NULL },
+ { "restart", SEC_ADMINISTRATOR, true, NULL, "", serverRestartCommandTable },
+ { "shutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable },
+ { "set", SEC_ADMINISTRATOR, true, NULL, "", serverSetCommandTable },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand questCommandTable[] =
+ static ChatCommand teleCommandTable[] =
{
- { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddQuest, "", NULL },
- { "complete", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCompleteQuest, "", NULL },
- { "remove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleRemoveQuest, "", NULL },
+ { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleTeleAddCommand, "", NULL },
+ { "del", SEC_ADMINISTRATOR, true, &ChatHandler::HandleTeleDelCommand, "", NULL },
+ { "name", SEC_MODERATOR, true, &ChatHandler::HandleTeleNameCommand, "", NULL },
+ { "group", SEC_MODERATOR, false, &ChatHandler::HandleTeleGroupCommand, "", NULL },
+ { "", SEC_MODERATOR, false, &ChatHandler::HandleTeleCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand gmCommandTable[] =
+ static ChatCommand unbanCommandTable[] =
{
- { "chat", SEC_MODERATOR, false, &ChatHandler::HandleGMChatCommand, "", NULL },
- { "ingame", SEC_PLAYER, true, &ChatHandler::HandleGMListIngameCommand, "", NULL },
- { "list", SEC_ADMINISTRATOR, true, &ChatHandler::HandleGMListFullCommand, "", NULL },
- { "visible", SEC_MODERATOR, false, &ChatHandler::HandleVisibleCommand, "", NULL },
- { "fly", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlyModeCommand, "", NULL },
- { "", SEC_MODERATOR, false, &ChatHandler::HandleGMmodeCommand, "", NULL },
+ { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanAccountCommand, "", NULL },
+ { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanCharacterCommand, "", NULL },
+ { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanIPCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
- static ChatCommand instanceCommandTable[] =
+ static ChatCommand wpCommandTable[] =
{
- { "listbinds", SEC_MODERATOR, false, &ChatHandler::HandleInstanceListBindsCommand, "", NULL },
- { "unbind", SEC_MODERATOR, false, &ChatHandler::HandleInstanceUnbindCommand, "", NULL },
- { "stats", SEC_MODERATOR, true, &ChatHandler::HandleInstanceStatsCommand, "", NULL },
- { "savedata", SEC_MODERATOR, false, &ChatHandler::HandleInstanceSaveDataCommand, "", NULL },
+ { "show", SEC_GAMEMASTER, false, &ChatHandler::HandleWpShowCommand, "", NULL },
+ { "addwp", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL },
+ { "load", SEC_GAMEMASTER, false, &ChatHandler::HandleWpLoadPathCommand, "", NULL },
+ { "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL },
+ { "event", SEC_GAMEMASTER, false, &ChatHandler::HandleWpEventCommand, "", NULL },
+ { "unload", SEC_GAMEMASTER, false, &ChatHandler::HandleWpUnLoadPathCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
@@ -528,34 +619,34 @@ ChatCommand * ChatHandler::getCommandTable()
static ChatCommand commandTable[] =
{
- { "account", SEC_PLAYER, true, NULL, "", accountCommandTable },
- { "gm", SEC_MODERATOR, true, NULL, "", gmCommandTable },
- { "ticket", SEC_MODERATOR, false, NULL, "", ticketCommandTable },
- { "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable },
- { "go", SEC_MODERATOR, false, NULL, "", goCommandTable },
- { "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable },
- { "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable },
- { "debug", SEC_MODERATOR, false, NULL, "", debugCommandTable },
- { "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable },
- { "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable },
- { "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable },
- { "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable },
-
- //wp commands
- { "path", SEC_GAMEMASTER, false, NULL, "", wpCommandTable },
- { "loadpath", SEC_ADMINISTRATOR, false, &ChatHandler::HandleReloadAllPaths, "", NULL },
-
- { "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable },
- { "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable },
- { "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable },
- { "lookup", SEC_ADMINISTRATOR, true, NULL, "", lookupCommandTable },
- { "pdump", SEC_ADMINISTRATOR, true, NULL, "", pdumpCommandTable },
- { "guild", SEC_ADMINISTRATOR, true, NULL, "", guildCommandTable },
- { "cast", SEC_ADMINISTRATOR, false, NULL, "", castCommandTable },
- { "reset", SEC_ADMINISTRATOR, false, NULL, "", resetCommandTable },
+ { "account", SEC_PLAYER, true, NULL, "", accountCommandTable },
+ { "gm", SEC_MODERATOR, true, NULL, "", gmCommandTable },
+ { "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable },
+ { "go", SEC_MODERATOR, false, NULL, "", goCommandTable },
+ { "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable },
+ { "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable },
+ { "debug", SEC_MODERATOR, false, NULL, "", debugCommandTable },
+ { "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable },
+ { "character", SEC_GAMEMASTER, false, NULL, "", characterCommandTable},
+ { "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable },
+ { "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable },
+ { "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable },
+ { "wp", SEC_GAMEMASTER, false, NULL, "", wpCommandTable },
+ { "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable },
+ { "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable },
+ { "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable },
+ { "lookup", SEC_ADMINISTRATOR, true, NULL, "", lookupCommandTable },
+ { "pdump", SEC_ADMINISTRATOR, true, NULL, "", pdumpCommandTable },
+ { "guild", SEC_ADMINISTRATOR, true, NULL, "", guildCommandTable },
+ { "cast", SEC_ADMINISTRATOR, false, NULL, "", castCommandTable },
+ { "reset", SEC_ADMINISTRATOR, true, NULL, "", resetCommandTable },
{ "instance", SEC_ADMINISTRATOR, true, NULL, "", instanceCommandTable },
- { "server", SEC_ADMINISTRATOR, true, NULL, "", serverCommandTable },
+ { "server", SEC_ADMINISTRATOR, true, NULL, "", serverCommandTable },
+
{ "pet", SEC_GAMEMASTER, false, NULL, "", petCommandTable },
+ { "loadpath", SEC_ADMINISTRATOR, false, &ChatHandler::HandleReloadAllPaths, "", NULL },
+ { "ahbotoptions", SEC_GAMEMASTER, false, &ChatHandler::HandleAHBotOptionsCommand, "", NULL },
+ { "ticket", SEC_MODERATOR, false, NULL, "", ticketCommandTable },
{ "aura", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuraCommand, "", NULL },
{ "unaura", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnAuraCommand, "", NULL },
@@ -571,7 +662,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "commands", SEC_PLAYER, true, &ChatHandler::HandleCommandsCommand, "", NULL },
{ "demorph", SEC_GAMEMASTER, false, &ChatHandler::HandleDeMorphCommand, "", NULL },
{ "die", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDieCommand, "", NULL },
- { "revive", SEC_ADMINISTRATOR, false, &ChatHandler::HandleReviveCommand, "", NULL },
+ { "revive", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReviveCommand, "", NULL },
{ "dismount", SEC_PLAYER, false, &ChatHandler::HandleDismountCommand, "", NULL },
{ "gps", SEC_MODERATOR, false, &ChatHandler::HandleGPSCommand, "", NULL },
{ "guid", SEC_GAMEMASTER, false, &ChatHandler::HandleGUIDCommand, "", NULL },
@@ -584,19 +675,16 @@ ChatCommand * ChatHandler::getCommandTable()
{ "save", SEC_PLAYER, false, &ChatHandler::HandleSaveCommand, "", NULL },
{ "saveall", SEC_MODERATOR, true, &ChatHandler::HandleSaveAllCommand, "", NULL },
{ "kick", SEC_GAMEMASTER, true, &ChatHandler::HandleKickPlayerCommand, "", NULL },
- { "ban", SEC_ADMINISTRATOR, true, NULL, "", banCommandTable },
- { "unban", SEC_ADMINISTRATOR, true, NULL, "", unbanCommandTable },
- { "baninfo", SEC_ADMINISTRATOR, false, NULL, "", baninfoCommandTable },
- { "banlist", SEC_ADMINISTRATOR, true, NULL, "", banlistCommandTable },
- { "plimit", SEC_ADMINISTRATOR, true, &ChatHandler::HandlePLimitCommand, "", NULL },
+ { "ban", SEC_ADMINISTRATOR, true, NULL, "", banCommandTable },
+ { "unban", SEC_ADMINISTRATOR, true, NULL, "", unbanCommandTable },
+ { "baninfo", SEC_ADMINISTRATOR, false, NULL, "", baninfoCommandTable },
+ { "banlist", SEC_ADMINISTRATOR, true, NULL, "", banlistCommandTable },
{ "start", SEC_PLAYER, false, &ChatHandler::HandleStartCommand, "", NULL },
{ "taxicheat", SEC_MODERATOR, false, &ChatHandler::HandleTaxiCheatCommand, "", NULL },
- { "allowmove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAllowMovementCommand, "", NULL },
{ "linkgrave", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLinkGraveCommand, "", NULL },
{ "neargrave", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNearGraveCommand, "", NULL },
{ "explorecheat", SEC_ADMINISTRATOR, false, &ChatHandler::HandleExploreCheatCommand, "", NULL },
{ "hover", SEC_ADMINISTRATOR, false, &ChatHandler::HandleHoverCommand, "", NULL },
- { "waterwalk", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWaterwalkCommand, "", NULL },
{ "levelup", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLevelUpCommand, "", NULL },
{ "showarea", SEC_ADMINISTRATOR, false, &ChatHandler::HandleShowAreaCommand, "", NULL },
{ "hidearea", SEC_ADMINISTRATOR, false, &ChatHandler::HandleHideAreaCommand, "", NULL },
@@ -608,34 +696,29 @@ ChatCommand * ChatHandler::getCommandTable()
{ "setskill", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSetSkillCommand, "", NULL },
{ "whispers", SEC_MODERATOR, false, &ChatHandler::HandleWhispersCommand, "", NULL },
{ "pinfo", SEC_GAMEMASTER, true, &ChatHandler::HandlePInfoCommand, "", NULL },
- { "password", SEC_PLAYER, false, &ChatHandler::HandlePasswordCommand, "", NULL },
- { "lockaccount", SEC_PLAYER, false, &ChatHandler::HandleLockAccountCommand, "", NULL },
{ "respawn", SEC_ADMINISTRATOR, false, &ChatHandler::HandleRespawnCommand, "", NULL },
- { "senditems", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendItemsCommand, "", NULL },
- { "sendmail", SEC_MODERATOR, true, &ChatHandler::HandleSendMailCommand, "", NULL },
- { "sendmoney", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMoneyCommand, "", NULL },
- { "rename", SEC_GAMEMASTER, true, &ChatHandler::HandleRenameCommand, "", NULL },
+ { "send", SEC_MODERATOR, true, NULL, "", sendCommandTable },
{ "loadscripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLoadScriptsCommand, "", NULL },
- { "mute", SEC_GAMEMASTER, true, &ChatHandler::HandleMuteCommand, "", NULL },
- { "unmute", SEC_GAMEMASTER, true, &ChatHandler::HandleUnmuteCommand, "", NULL },
+ { "mute", SEC_MODERATOR, true, &ChatHandler::HandleMuteCommand, "", NULL },
+ { "unmute", SEC_MODERATOR, true, &ChatHandler::HandleUnmuteCommand, "", NULL },
{ "movegens", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMovegensCommand, "", NULL },
{ "cometome", SEC_ADMINISTRATOR, false, &ChatHandler::HandleComeToMeCommand, "", NULL },
{ "damage", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDamageCommand, "", NULL },
{ "combatstop", SEC_GAMEMASTER, false, &ChatHandler::HandleCombatStopCommand, "", NULL },
- { "ahbotoptions", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotOptionsCommand, "", NULL },
- { "flusharenapoints", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
- { "chardelete", SEC_CONSOLE, true, &ChatHandler::HandleCharacterDeleteCommand, "", NULL },
- { "sendmessage", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMessageCommand, "", NULL },
- { "playall", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePlayAllCommand, "", NULL },
- { "repairitems", SEC_GAMEMASTER, false, &ChatHandler::HandleRepairitemsCommand, "", NULL },
+ { "flusharenapoints",SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
+ { "repairitems", SEC_GAMEMASTER, true, &ChatHandler::HandleRepairitemsCommand, "", NULL },
+ { "waterwalk", SEC_GAMEMASTER, false, &ChatHandler::HandleWaterwalkCommand, "", NULL },
+
{ "freeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFreezeCommand, "", NULL },
{ "unfreeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnFreezeCommand, "", NULL },
{ "listfreeze", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListFreezeCommand, "", NULL },
{ "flusharenapoints", SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
+
{ "possess", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePossessCommand, "", NULL },
{ "unpossess", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnPossessCommand, "", NULL },
{ "bindsight", SEC_ADMINISTRATOR, false, &ChatHandler::HandleBindSightCommand, "", NULL },
{ "unbindsight", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnbindSightCommand, "", NULL },
+ { "playall", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePlayAllCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
@@ -651,28 +734,9 @@ ChatCommand * ChatHandler::getCommandTable()
{
Field *fields = result->Fetch();
std::string name = fields[0].GetCppString();
- for(uint32 i = 0; commandTable[i].Name != NULL; i++)
- {
- if (name == commandTable[i].Name)
- {
- commandTable[i].SecurityLevel = (uint16)fields[1].GetUInt16();
- commandTable[i].Help = fields[2].GetCppString();
- }
- if(commandTable[i].ChildCommands != NULL)
- {
- ChatCommand *ptable = commandTable[i].ChildCommands;
- for(uint32 j = 0; ptable[j].Name != NULL; j++)
- {
- // first case for "" named subcommand
- if (ptable[j].Name[0]=='\0' && name == commandTable[i].Name ||
- name == fmtstring("%s %s", commandTable[i].Name, ptable[j].Name) )
- {
- ptable[j].SecurityLevel = (uint16)fields[1].GetUInt16();
- ptable[j].Help = fields[2].GetCppString();
- }
- }
- }
- }
+
+ SetDataForCommandInTable(commandTable, name.c_str(), fields[1].GetUInt16(), fields[2].GetCppString(), name);
+
} while(result->NextRow());
delete result;
}
@@ -692,6 +756,55 @@ bool ChatHandler::isAvailable(ChatCommand const& cmd) const
return m_session->GetSecurity() >= cmd.SecurityLevel;
}
+bool ChatHandler::HasLowerSecurity(Player* target, uint64 guid, bool strong)
+{
+ WorldSession* target_session = NULL;
+ uint32 target_account = 0;
+
+ if (target)
+ target_session = target->GetSession();
+ else if (guid)
+ target_account = objmgr.GetPlayerAccountIdByGUID(guid);
+
+ if(!target_session && !target_account)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return true;
+ }
+
+ return HasLowerSecurityAccount(target_session,target_account,strong);
+}
+
+bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_account, bool strong)
+{
+ uint32 target_sec;
+
+ // allow everything from console and RA console
+ if (!m_session)
+ return false;
+
+ // ignore only for non-players for non strong checks (when allow apply command at least to same sec level)
+ if (m_session->GetSecurity() > SEC_PLAYER && !strong && !sWorld.getConfig(CONFIG_GM_LOWER_SECURITY))
+ return false;
+
+ if (target)
+ target_sec = target->GetSecurity();
+ else if (target_account)
+ target_sec = accmgr.GetSecurity(target_account);
+ else
+ return true; // caller must report error for (target==NULL && target_account==0)
+
+ if (m_session->GetSecurity() < target_sec || (strong && m_session->GetSecurity() <= target_sec))
+ {
+ SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
+ SetSentErrorMessage(true);
+ return true;
+ }
+
+ return false;
+}
+
bool ChatHandler::hasStringAbbr(const char* name, const char* part)
{
// non "" command
@@ -778,9 +891,9 @@ void ChatHandler::PSendSysMessage(int32 entry, ...)
{
const char *format = GetTrinityString(entry);
va_list ap;
- char str [1024];
+ char str [2048];
va_start(ap, entry);
- vsnprintf(str,1024,format, ap );
+ vsnprintf(str,2048,format, ap );
va_end(ap);
SendSysMessage(str);
}
@@ -788,9 +901,9 @@ void ChatHandler::PSendSysMessage(int32 entry, ...)
void ChatHandler::PSendSysMessage(const char *format, ...)
{
va_list ap;
- char str [1024];
+ char str [2048];
va_start(ap, format);
- vsnprintf(str,1024,format, ap );
+ vsnprintf(str,2048,format, ap );
va_end(ap);
SendSysMessage(str);
}
@@ -808,7 +921,7 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, co
while (*text == ' ') ++text;
- for(uint32 i = 0; table[i].Name != NULL; i++)
+ for(uint32 i = 0; table[i].Name != NULL; ++i)
{
if( !hasStringAbbr(table[i].Name, cmd.c_str()) )
continue;
@@ -865,6 +978,61 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, co
return false;
}
+bool ChatHandler::SetDataForCommandInTable(ChatCommand *table, const char* text, uint32 security, std::string const& help, std::string const& fullcommand )
+{
+ std::string cmd = "";
+
+ while (*text != ' ' && *text != '\0')
+ {
+ cmd += *text;
+ ++text;
+ }
+
+ while (*text == ' ') ++text;
+
+ for(uint32 i = 0; table[i].Name != NULL; i++)
+ {
+ // for data fill use full explicit command names
+ if( table[i].Name != cmd )
+ continue;
+
+ // select subcommand from child commands list (including "")
+ if(table[i].ChildCommands != NULL)
+ {
+ if(SetDataForCommandInTable(table[i].ChildCommands, text, security, help, fullcommand))
+ return true;
+ else if(*text)
+ return false;
+
+ // fail with "" subcommands, then use normal level up command instead
+ }
+ // expected subcommand by full name DB content
+ else if(*text)
+ {
+ sLog.outErrorDb("Table `command` have unexpected subcommand '%s' in command '%s', skip.",text,fullcommand.c_str());
+ return false;
+ }
+
+ if(table[i].SecurityLevel != security)
+ sLog.outDetail("Table `command` overwrite for command '%s' default security (%u) by %u",fullcommand.c_str(),table[i].SecurityLevel,security);
+
+ table[i].SecurityLevel = security;
+ table[i].Help = help;
+ return true;
+ }
+
+ // in case "" command let process by caller
+ if(!cmd.empty())
+ {
+ if(table==getCommandTable())
+ sLog.outErrorDb("Table `command` have not existed command '%s', skip.",cmd.c_str());
+ else
+ sLog.outErrorDb("Table `command` have not existed subcommand '%s' in command '%s', skip.",cmd.c_str(),fullcommand.c_str());
+ }
+
+ return false;
+}
+
int ChatHandler::ParseCommands(const char* text)
{
ASSERT(text);
@@ -873,28 +1041,28 @@ int ChatHandler::ParseCommands(const char* text)
std::string fullcmd = text;
/// chat case (.command or !command format)
- if(m_session)
+ if (m_session)
{
if(text[0] != '!' && text[0] != '.')
return 0;
}
/// ignore single . and ! in line
- if(strlen(text) < 2)
+ if (strlen(text) < 2)
return 0;
// original `text` can't be used. It content destroyed in command code processing.
/// ignore messages staring from many dots.
- if(text[0] == '.' && text[1] == '.' || text[0] == '!' && text[1] == '!')
+ if ((text[0] == '.' && text[1] == '.') || (text[0] == '!' && text[1] == '!'))
return 0;
/// skip first . or ! (in console allowed use command with . and ! and without its)
- if(text[0] == '!' || text[0] == '.')
+ if (text[0] == '!' || text[0] == '.')
++text;
if(!ExecuteCommandInTable(getCommandTable(), text, fullcmd))
{
- if(m_session && m_session->GetSecurity() == SEC_PLAYER)
+ if(m_session && m_session->GetSecurity() == SEC_PLAYER)
return 0;
SendSysMessage(LANG_NO_CMD);
}
@@ -1101,12 +1269,25 @@ Unit* ChatHandler::getSelectedUnit()
return ObjectAccessor::GetUnit(*m_session->GetPlayer(),guid);
}
+WorldObject *ChatHandler::getSelectedObject()
+{
+ if(!m_session)
+ return NULL;
+
+ uint64 guid = m_session->GetPlayer()->GetSelection();
+
+ if (guid == 0)
+ return GetNearbyGameObject();
+
+ return ObjectAccessor::GetUnit(*m_session->GetPlayer(),guid);
+}
+
Creature* ChatHandler::getSelectedCreature()
{
if(!m_session)
return NULL;
- return ObjectAccessor::GetCreatureOrPet(*m_session->GetPlayer(),m_session->GetPlayer()->GetSelection());
+ return ObjectAccessor::GetCreatureOrPetOrVehicle(*m_session->GetPlayer(),m_session->GetPlayer()->GetSelection());
}
char* ChatHandler::extractKeyFromLink(char* text, char const* linkType, char** something1)
@@ -1153,7 +1334,7 @@ char* ChatHandler::extractKeyFromLink(char* text, char const* linkType, char** s
*something1 = strtok(NULL, ":|"); // extract something
strtok(cKeysTail, "]"); // restart scan tail and skip name with possible spaces
- strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after retturn from function
+ strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after return from function
return cKey;
}
@@ -1177,12 +1358,23 @@ char* ChatHandler::extractKeyFromLink(char* text, char const* const* linkTypes,
// [name] Shift-click form |color|linkType:key|h[name]|h|r
// or
// [name] Shift-click form |color|linkType:key:something1:...:somethingN|h[name]|h|r
+ // or
+ // [name] Shift-click form |linkType:key|h[name]|h|r
- char* check = strtok(text, "|"); // skip color
- if(!check)
- return NULL; // end of data
+ char* tail;
- char* cLinkType = strtok(NULL, ":"); // linktype
+ if(text[1]=='c')
+ {
+ char* check = strtok(text, "|"); // skip color
+ if(!check)
+ return NULL; // end of data
+
+ tail = strtok(NULL, ""); // tail
+ }
+ else
+ tail = text+1; // skip first |
+
+ char* cLinkType = strtok(tail, ":"); // linktype
if(!cLinkType)
return NULL; // end of data
@@ -1242,6 +1434,19 @@ char const *fmtstring( char const *format, ... )
return buf;
}
+GameObject* ChatHandler::GetNearbyGameObject()
+{
+ if(!m_session)
+ return NULL;
+
+ Player* pl = m_session->GetPlayer();
+ GameObject* obj = NULL;
+ Trinity::NearestGameObjectCheck check(*pl);
+ Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectCheck> searcher(pl, obj, check);
+ pl->VisitNearbyGridObject(999, searcher);
+ return obj;
+}
+
GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry)
{
if(!m_session)
@@ -1249,7 +1454,7 @@ GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid
Player* pl = m_session->GetPlayer();
- GameObject* obj = ObjectAccessor::GetGameObject(*pl, MAKE_NEW_GUID(lowguid, entry, HIGHGUID_GAMEOBJECT));
+ GameObject* obj = pl->GetMap()->GetGameObject(MAKE_NEW_GUID(lowguid, entry, HIGHGUID_GAMEOBJECT));
if(!obj && objmgr.GetGOData(lowguid)) // guid is DB guid of object
{
@@ -1258,20 +1463,29 @@ GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
- Trinity::GameObjectWithDbGUIDCheck go_check(*pl,lowguid);
- Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(obj,go_check);
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*pl,lowguid);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(pl,obj,go_check);
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(pl->GetMapId(), pl));
+ cell_lock->Visit(cell_lock, object_checker, *pl->GetMap());
}
return obj;
}
-static char const* const spellTalentKeys[] = {
- "Hspell",
- "Htalent",
+enum SpellLinkType
+{
+ SPELL_LINK_SPELL = 0,
+ SPELL_LINK_TALENT = 1,
+ SPELL_LINK_TRADE = 2
+};
+
+static char const* const spellKeys[] =
+{
+ "Hspell", // normal spell
+ "Htalent", // talent spell
+ "Htrade", // profession/skill spell
0
};
@@ -1279,31 +1493,41 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text)
{
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r
// number or [name] Shift-click form |color|Htalent:talent_id,rank|h[name]|h|r
+ // number or [name] Shift-click form |color|Htrade:spell_id,skill_id,max_value,cur_value|h[name]|h|r
int type = 0;
- char* rankS = NULL;
- char* idS = extractKeyFromLink(text,spellTalentKeys,&type,&rankS);
+ char* param1_str = NULL;
+ char* idS = extractKeyFromLink(text,spellKeys,&type,&param1_str);
if(!idS)
return 0;
uint32 id = (uint32)atol(idS);
- // spell
- if(type==0)
- return id;
+ switch(type)
+ {
+ case SPELL_LINK_SPELL:
+ return id;
+ case SPELL_LINK_TALENT:
+ {
+ // talent
+ TalentEntry const* talentEntry = sTalentStore.LookupEntry(id);
+ if(!talentEntry)
+ return 0;
- // talent
- TalentEntry const* talentEntry = sTalentStore.LookupEntry(id);
- if(!talentEntry)
- return 0;
+ int32 rank = param1_str ? (uint32)atol(param1_str) : 0;
+ if(rank >= MAX_TALENT_RANK)
+ return 0;
- int32 rank = rankS ? (uint32)atol(rankS) : 0;
- if(rank >= 5)
- return 0;
+ if(rank < 0)
+ rank = 0;
- if(rank < 0)
- rank = 0;
+ return talentEntry->RankID[rank];
+ }
+ case SPELL_LINK_TRADE:
+ return id;
+ }
- return talentEntry->RankID[rank];
+ // unknown type?
+ return 0;
}
GameTele const* ChatHandler::extractGameTeleFromLink(char* text)
@@ -1321,9 +1545,155 @@ GameTele const* ChatHandler::extractGameTeleFromLink(char* text)
return objmgr.GetGameTele(cId);
}
-const char *ChatHandler::GetName() const
+enum GuidLinkType
+{
+ SPELL_LINK_PLAYER = 0, // must be first for selection in not link case
+ SPELL_LINK_CREATURE = 1,
+ SPELL_LINK_GAMEOBJECT = 2
+};
+
+static char const* const guidKeys[] =
+{
+ "Hplayer",
+ "Hcreature",
+ "Hgameobject",
+ 0
+};
+
+uint64 ChatHandler::extractGuidFromLink(char* text)
+{
+ int type = 0;
+
+ // |color|Hcreature:creature_guid|h[name]|h|r
+ // |color|Hgameobject:go_guid|h[name]|h|r
+ // |color|Hplayer:name|h[name]|h|r
+ char* idS = extractKeyFromLink(text,guidKeys,&type);
+ if(!idS)
+ return 0;
+
+ switch(type)
+ {
+ case SPELL_LINK_PLAYER:
+ {
+ std::string name = idS;
+ if(!normalizePlayerName(name))
+ return 0;
+
+ if(Player* player = objmgr.GetPlayer(name.c_str()))
+ return player->GetGUID();
+
+ if(uint64 guid = objmgr.GetPlayerGUIDByName(name))
+ return guid;
+
+ return 0;
+ }
+ case SPELL_LINK_CREATURE:
+ {
+ uint32 lowguid = (uint32)atol(idS);
+
+ if(CreatureData const* data = objmgr.GetCreatureData(lowguid) )
+ return MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT);
+ else
+ return 0;
+ }
+ case SPELL_LINK_GAMEOBJECT:
+ {
+ uint32 lowguid = (uint32)atol(idS);
+
+ if(GameObjectData const* data = objmgr.GetGOData(lowguid) )
+ return MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_GAMEOBJECT);
+ else
+ return 0;
+ }
+ }
+
+ // unknown type?
+ return 0;
+}
+
+std::string ChatHandler::extractPlayerNameFromLink(char* text)
+{
+ // |color|Hplayer:name|h[name]|h|r
+ char* name_str = extractKeyFromLink(text,"Hplayer");
+ if(!name_str)
+ return "";
+
+ std::string name = name_str;
+ if(!normalizePlayerName(name))
+ return "";
+
+ return name;
+}
+
+bool ChatHandler::extractPlayerTarget(char* args, Player** player, uint64* player_guid /*=NULL*/,std::string* player_name /*= NULL*/)
{
- return m_session->GetPlayer()->GetName();
+ if (args && *args)
+ {
+ std::string name = extractPlayerNameFromLink(args);
+ if (name.empty())
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Player* pl = objmgr.GetPlayer(name.c_str());
+
+ // if allowed player pointer
+ if(player)
+ *player = pl;
+
+ // if need guid value from DB (in name case for check player existence)
+ uint64 guid = !pl && (player_guid || player_name) ? objmgr.GetPlayerGUIDByName(name) : 0;
+
+ // if allowed player guid (if no then only online players allowed)
+ if(player_guid)
+ *player_guid = pl ? pl->GetGUID() : guid;
+
+ if(player_name)
+ *player_name = pl || guid ? name : "";
+ }
+ else
+ {
+ Player* pl = getSelectedPlayer();
+ // if allowed player pointer
+ if(player)
+ *player = pl;
+ // if allowed player guid (if no then only online players allowed)
+ if(player_guid)
+ *player_guid = pl ? pl->GetGUID() : 0;
+
+ if(player_name)
+ *player_name = pl ? pl->GetName() : "";
+ }
+
+ // some from req. data must be provided (note: name is empty if player not exist)
+ if((!player || !*player) && (!player_guid || !*player_guid) && (!player_name || player_name->empty()))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+}
+
+void ChatHandler::extractOptFirstArg(char* args, char** arg1, char** arg2)
+{
+ char* p1 = strtok(args, " ");
+ char* p2 = strtok(NULL, " ");
+
+ if(!p2)
+ {
+ p2 = p1;
+ p1 = NULL;
+ }
+
+ if(arg1)
+ *arg1 = p1;
+
+ if(arg2)
+ *arg2 = p2;
}
bool ChatHandler::needReportToTarget(Player* chr) const
@@ -1332,7 +1702,17 @@ bool ChatHandler::needReportToTarget(Player* chr) const
return pl != chr && pl->IsVisibleGloballyFor(chr);
}
-const char *CliHandler::GetTrinityString(int32 entry) const
+LocaleConstant ChatHandler::GetSessionDbcLocale() const
+{
+ return m_session->GetSessionDbcLocale();
+}
+
+int ChatHandler::GetSessionDbLocaleIndex() const
+{
+ return m_session->GetSessionDbLocaleIndex();
+}
+
+const char *CliHandler::GetMangosString(int32 entry) const
{
return objmgr.GetTrinityStringForDBCLocale(entry);
}
@@ -1349,7 +1729,7 @@ void CliHandler::SendSysMessage(const char *str)
m_print("\r\n");
}
-const char *CliHandler::GetName() const
+std::string CliHandler::GetNameLink() const
{
return GetTrinityString(LANG_CONSOLE_COMMAND);
}
@@ -1403,3 +1783,12 @@ bool ChatHandler::GetPlayerGroupAndGUIDByName(const char* cname, Player* &plr, G
return true;
}
+LocaleConstant CliHandler::GetSessionDbcLocale() const
+{
+ return sWorld.GetDefaultDbcLocale();
+}
+
+int CliHandler::GetSessionDbLocaleIndex() const
+{
+ return objmgr.GetDBCLocaleIndex();
+}
diff --git a/src/game/Chat.h b/src/game/Chat.h
index a8dbb5b98a5..f7a587ce463 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -62,9 +62,10 @@ class ChatHandler
static char* LineFromMessage(char*& pos) { char* start = strtok(pos,"\n"); pos = NULL; return start; }
- virtual const char *GetTrinityString(int32 entry) const;
-
+ // function with different implementation for chat/console
+ virtual const char *GetMangosString(int32 entry) const;
virtual void SendSysMessage( const char *str);
+
void SendSysMessage( int32 entry);
void PSendSysMessage( const char *format, ...) ATTR_PRINTF(2,3);
void PSendSysMessage( int32 entry, ... );
@@ -72,19 +73,25 @@ class ChatHandler
int ParseCommands(const char* text);
- virtual char const* GetName() const;
-
protected:
explicit ChatHandler() : m_session(NULL) {} // for CLI subclass
bool hasStringAbbr(const char* name, const char* part);
+ // function with different implementation for chat/console
virtual bool isAvailable(ChatCommand const& cmd) const;
+ virtual std::string GetNameLink() const { return GetNameLink(m_session->GetPlayer()); }
virtual bool needReportToTarget(Player* chr) const;
+ virtual LocaleConstant GetSessionDbcLocale() const;
+ virtual int GetSessionDbLocaleIndex() const;
+
+ bool HasLowerSecurity(Player* target, uint64 guid, bool strong = false);
+ bool HasLowerSecurityAccount(WorldSession* target, uint32 account, bool strong = false);
void SendGlobalSysMessage(const char *str);
void SendGlobalGMSysMessage(const char *str);
+ bool SetDataForCommandInTable(ChatCommand *table, const char* text, uint32 security, std::string const& help, std::string const& fullcommand );
bool ExecuteCommandInTable(ChatCommand *table, const char* text, const std::string& fullcommand);
bool ShowHelpForCommand(ChatCommand *table, const char* cmd);
bool ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd);
@@ -94,48 +101,130 @@ class ChatHandler
bool HandleAccountCommand(const char* args);
bool HandleAccountCreateCommand(const char* args);
bool HandleAccountDeleteCommand(const char* args);
+ bool HandleAccountLockCommand(const char* args);
bool HandleAccountOnlineListCommand(const char* args);
+ bool HandleAccountPasswordCommand(const char* args);
bool HandleAccountSetAddonCommand(const char* args);
bool HandleAccountSetGmLevelCommand(const char* args);
bool HandleAccountSetPasswordCommand(const char* args);
- bool HandleHelpCommand(const char* args);
bool HandleAHBotOptionsCommand(const char * args);
- bool HandleCommandsCommand(const char* args);
- bool HandleStartCommand(const char* args);
- bool HandleDismountCommand(const char* args);
- bool HandleSaveCommand(const char* args);
- bool HandleGMListIngameCommand(const char* args);
- bool HandleGMListFullCommand(const char* args);
-
- bool HandleNamegoCommand(const char* args);
- bool HandleGonameCommand(const char* args);
- bool HandleGroupgoCommand(const char* args);
- bool HandleRecallCommand(const char* args);
bool HandleNameAnnounceCommand(const char* args);
bool HandleGMNameAnnounceCommand(const char* args);
- bool HandleAnnounceCommand(const char* args);
bool HandleGMAnnounceCommand(const char* args);
- bool HandleNotifyCommand(const char* args);
bool HandleGMNotifyCommand(const char* args);
- bool HandleGMmodeCommand(const char* args);
- bool HandleGMChatCommand(const char* args);
- bool HandleVisibleCommand(const char* args);
- bool HandleGPSCommand(const char* args);
- bool HandleTaxiCheatCommand(const char* args);
- bool HandleWhispersCommand(const char* args);
- bool HandleNameTeleCommand(const char* args);
- bool HandleGroupTeleCommand(const char* args);
- bool HandleDrunkCommand(const char* args);
- bool HandleSendItemsCommand(const char* args);
- bool HandleSendMailCommand(const char* args);
- bool HandleSendMoneyCommand(const char* args);
+
+ bool HandleBanAccountCommand(const char* args);
+ bool HandleBanCharacterCommand(const char* args);
+ bool HandleBanIPCommand(const char* args);
+ bool HandleBanInfoAccountCommand(const char* args);
+ bool HandleBanInfoCharacterCommand(const char* args);
+ bool HandleBanInfoIPCommand(const char* args);
+ bool HandleBanListAccountCommand(const char* args);
+ bool HandleBanListCharacterCommand(const char* args);
+ bool HandleBanListIPCommand(const char* args);
+
+ bool HandleCastCommand(const char *args);
+ bool HandleCastBackCommand(const char *args);
+ bool HandleCastDistCommand(const char *args);
+ bool HandleCastSelfCommand(const char *args);
+ bool HandleCastTargetCommand(const char *args);
+
+ bool HandleCharacterCustomizeCommand(const char * args);
+ bool HandleCharacterDeleteCommand(const char* args);
+ bool HandleCharacterLevelCommand(const char* args);
+ bool HandleCharacterRenameCommand(const char * args);
+ bool HandleCharacterReputationCommand(const char* args);
+
+ bool HandleDebugAnimCommand(const char* args);
+ bool HandleDebugArenaCommand(const char * args);
+ bool HandleDebugBattlegroundCommand(const char * args);
+ bool HandleDebugGetItemState(const char * args);
+ bool HandleDebugGetLootRecipient(const char * args);
+ bool HandleDebugGetValue(const char* args);
+ bool HandleDebugMod32Value(const char* args);
+ bool HandleDebugSetValue(const char* args);
+ bool HandleDebugSetItemFlagCommand(const char * args);
+ bool HandleDebugSetVehicleId(const char * args);
+ bool HandleDebugSpawnVehicle(const char * args);
+ bool HandleDebugEnterVehicle(const char * args);
+ bool HandleDebugUpdate(const char* args);
+ bool HandleDebugUpdateWorldStateCommand(const char* args);
+
+ bool HandleDebugSet32Bit(const char* args);
+ bool HandleDebugThreatList(const char * args);
+ bool HandleDebugHostilRefList(const char * args);
+ bool HandlePossessCommand(const char* args);
+ bool HandleUnPossessCommand(const char* args);
+ bool HandleBindSightCommand(const char* args);
+ bool HandleUnbindSightCommand(const char* args);
+
+ bool HandleDebugPlayCinematicCommand(const char* args);
+ bool HandleDebugPlayMovieCommand(const char* args);
+ bool HandleDebugPlaySoundCommand(const char* args);
+
+ bool HandleDebugSendBuyErrorCommand(const char* args);
+ bool HandleDebugSendChannelNotifyCommand(const char* args);
+ bool HandleDebugSendChatMsgCommand(const char* args);
+ bool HandleDebugSendEquipErrorCommand(const char* args);
+ bool HandleDebugSendLargePacketCommand(const char * args);
+ bool HandleDebugSendOpcodeCommand(const char* args);
+ bool HandleDebugSendPoiCommand(const char* args);
+ bool HandleDebugSendQuestPartyMsgCommand(const char* args);
+ bool HandleDebugSendQuestInvalidMsgCommand(const char* args);
+ bool HandleDebugSendSellErrorCommand(const char* args);
+ bool HandleDebugSendSetPhaseShiftCommand(const char * args);
+ bool HandleDebugSendSpellFailCommand(const char* args);
bool HandleEventActiveListCommand(const char* args);
bool HandleEventStartCommand(const char* args);
bool HandleEventStopCommand(const char* args);
bool HandleEventInfoCommand(const char* args);
+ bool HandleGameObjectAddCommand(const char* args);
+ bool HandleGameObjectDeleteCommand(const char* args);
+ bool HandleGameObjectMoveCommand(const char* args);
+ bool HandleGameObjectNearCommand(const char* args);
+ bool HandleGameObjectPhaseCommand(const char* args);
+ bool HandleGameObjectStateCommand(const char* args);
+ bool HandleGameObjectTargetCommand(const char* args);
+ bool HandleGameObjectTurnCommand(const char* args);
+
+ bool HandleGMCommand(const char* args);
+ bool HandleGMChatCommand(const char* args);
+ bool HandleGMFlyCommand(const char* args);
+ bool HandleGMListFullCommand(const char* args);
+ bool HandleGMListIngameCommand(const char* args);
+ bool HandleGMVisibleCommand(const char* args);
+
+ bool HandleGoCommand(const char* args);
+ bool HandleGoCreatureCommand(const char* args);
+ bool HandleGoGraveyardCommand(const char* args);
+ bool HandleGoGridCommand(const char* args);
+ bool HandleGoObjectCommand(const char* args);
+ bool HandleGoTaxinodeCommand(const char* args);
+ bool HandleGoTriggerCommand(const char* args);
+ bool HandleGoXYCommand(const char* args);
+ bool HandleGoXYZCommand(const char* args);
+ bool HandleGoZoneXYCommand(const char* args);
+
+ bool HandleGoTicketCommand(const char* args);
+
+ bool HandleGuildCreateCommand(const char* args);
+ bool HandleGuildInviteCommand(const char* args);
+ bool HandleGuildUninviteCommand(const char* args);
+ bool HandleGuildRankCommand(const char* args);
+ bool HandleGuildDeleteCommand(const char* args);
+
+ bool HandleHonorAddCommand(const char* args);
+ bool HandleHonorAddKillCommand(const char* args);
+ bool HandleHonorUpdateCommand(const char* args);
+
+ bool HandleInstanceListBindsCommand(const char* args);
+ bool HandleInstanceUnbindCommand(const char* args);
+ bool HandleInstanceStatsCommand(const char* args);
+ bool HandleInstanceSaveDataCommand(const char * args);
+
bool HandleLearnCommand(const char* args);
bool HandleLearnAllCommand(const char* args);
bool HandleLearnAllGMCommand(const char* args);
@@ -144,9 +233,15 @@ class ChatHandler
bool HandleLearnAllDefaultCommand(const char* args);
bool HandleLearnAllLangCommand(const char* args);
bool HandleLearnAllMyClassCommand(const char* args);
+ bool HandleLearnAllMyPetTalentsCommand(const char* args);
bool HandleLearnAllMySpellsCommand(const char* args);
bool HandleLearnAllMyTalentsCommand(const char* args);
+ bool HandleListAurasCommand(const char * args);
+ bool HandleListCreatureCommand(const char* args);
+ bool HandleListItemCommand(const char* args);
+ bool HandleListObjectCommand(const char* args);
+
bool HandleLookupAreaCommand(const char* args);
bool HandleLookupCreatureCommand(const char* args);
bool HandleLookupEventCommand(const char* args);
@@ -160,12 +255,14 @@ class ChatHandler
bool HandleLookupQuestCommand(const char* args);
bool HandleLookupSkillCommand(const char* args);
bool HandleLookupSpellCommand(const char* args);
+ bool HandleLookupTaxiNodeCommand(const char * args);
bool HandleLookupTeleCommand(const char * args);
bool HandleModifyKnownTitlesCommand(const char* args);
bool HandleModifyHPCommand(const char* args);
bool HandleModifyManaCommand(const char* args);
bool HandleModifyRageCommand(const char* args);
+ bool HandleModifyRunicPowerCommand(const char* args);
bool HandleModifyEnergyCommand(const char* args);
bool HandleModifyMoneyCommand(const char* args);
bool HandleModifyASpeedCommand(const char* args);
@@ -182,12 +279,18 @@ class ChatHandler
bool HandleModifyHonorCommand (const char* args);
bool HandleModifyRepCommand(const char* args);
bool HandleModifyArenaCommand(const char* args);
+ bool HandleModifyPhaseCommand(const char* args);
bool HandleModifyGenderCommand(const char* args);
+ //-----------------------Npc Commands-----------------------
bool HandleNpcAddCommand(const char* args);
bool HandleNpcAddMoveCommand(const char* args);
+ bool HandleNpcAddVendorItemCommand(const char* args);
+ bool HandleNpcAllowMovementCommand(const char* args);
bool HandleNpcChangeEntryCommand(const char *args);
+ bool HandleNpcChangeLevelCommand(const char* args);
bool HandleNpcDeleteCommand(const char* args);
+ bool HandleNpcDelVendorItemCommand(const char* args);
bool HandleNpcFactionIdCommand(const char* args);
bool HandleNpcFlagCommand(const char* args);
bool HandleNpcFollowCommand(const char* args);
@@ -195,8 +298,10 @@ class ChatHandler
bool HandleNpcMoveCommand(const char* args);
bool HandleNpcPlayEmoteCommand(const char* args);
bool HandleNpcSayCommand(const char* args);
+ bool HandleNpcSetDeathStateCommand(const char* args);
bool HandleNpcSetModelCommand(const char* args);
bool HandleNpcSetMoveTypeCommand(const char* args);
+ bool HandleNpcSetPhaseCommand(const char* args);
bool HandleNpcSpawnDistCommand(const char* args);
bool HandleNpcSpawnTimeCommand(const char* args);
bool HandleNpcTameCommand(const char* args);
@@ -207,24 +312,42 @@ class ChatHandler
bool HandleNpcAddFormationCommand(const char* args);
bool HandleNpcSetLinkCommand(const char* args);
- bool HandleReloadCommand(const char* args);
+ //TODO: NpcCommands that needs to be fixed :
+ bool HandleNpcAddWeaponCommand(const char* args);
+ bool HandleNpcNameCommand(const char* args);
+ bool HandleNpcSubNameCommand(const char* args);
+ //----------------------------------------------------------
+
+ bool HandlePDumpLoadCommand(const char *args);
+ bool HandlePDumpWriteCommand(const char *args);
+
+ bool HandleQuestAdd(const char * args);
+ bool HandleQuestRemove(const char * args);
+ bool HandleQuestComplete(const char * args);
+
bool HandleReloadAllCommand(const char* args);
+ bool HandleReloadAllAchievementCommand(const char* args);
bool HandleReloadAllAreaCommand(const char* args);
bool HandleReloadAllItemCommand(const char* args);
bool HandleReloadAllLootCommand(const char* args);
bool HandleReloadAllNpcCommand(const char* args);
bool HandleReloadAllQuestCommand(const char* args);
bool HandleReloadAllScriptsCommand(const char* args);
+ bool HandleReloadAllEventAICommand(const char* args);
bool HandleReloadAllSpellCommand(const char* args);
bool HandleReloadAllLocalesCommand(const char* args);
bool HandleReloadConfigCommand(const char* args);
- bool HandleReloadWpScriptsCommand(const char* args);
+ bool HandleReloadAchievementCriteriaDataCommand(const char* args);
+ bool HandleReloadAchievementRewardCommand(const char* args);
bool HandleReloadAreaTriggerTavernCommand(const char* args);
bool HandleReloadAreaTriggerTeleportCommand(const char* args);
bool HandleReloadAccessRequirementCommand(const char* args);
bool HandleReloadEventScriptsCommand(const char* args);
+ bool HandleReloadEventAITextsCommand(const char* args);
+ bool HandleReloadEventAISummonsCommand(const char* args);
+ bool HandleReloadEventAIScriptsCommand(const char* args);
bool HandleReloadCommandCommand(const char* args);
bool HandleReloadCreatureQuestRelationsCommand(const char* args);
bool HandleReloadCreatureQuestInvRelationsCommand(const char* args);
@@ -235,21 +358,36 @@ class ChatHandler
bool HandleReloadGameTeleCommand(const char* args);
bool HandleReloadGOQuestRelationsCommand(const char* args);
bool HandleReloadGOQuestInvRelationsCommand(const char* args);
+ bool HandleReloadItemEnchantementsCommand(const char* args);
+ bool HandleReloadLocalesAchievementRewardCommand(const char* args);
+ bool HandleReloadLocalesCreatureCommand(const char* args);
+ bool HandleReloadLocalesGameobjectCommand(const char* args);
+ bool HandleReloadLocalesItemCommand(const char* args);
+ bool HandleReloadLocalesNpcTextCommand(const char* args);
+ bool HandleReloadLocalesPageTextCommand(const char* args);
+ bool HandleReloadLocalesPointsOfInterestCommand(const char* args);
+ bool HandleReloadLocalesQuestCommand(const char* args);
+// bool HandleReloadAuctionsCommand(const char* args);
bool HandleReloadLootTemplatesCreatureCommand(const char* args);
bool HandleReloadLootTemplatesDisenchantCommand(const char* args);
bool HandleReloadLootTemplatesFishingCommand(const char* args);
bool HandleReloadLootTemplatesGameobjectCommand(const char* args);
bool HandleReloadLootTemplatesItemCommand(const char* args);
+ bool HandleReloadLootTemplatesMillingCommand(const char* args);
bool HandleReloadLootTemplatesPickpocketingCommand(const char* args);
bool HandleReloadLootTemplatesProspectingCommand(const char* args);
bool HandleReloadLootTemplatesReferenceCommand(const char* args);
bool HandleReloadLootTemplatesQuestMailCommand(const char* args);
bool HandleReloadLootTemplatesSkinningCommand(const char* args);
+ bool HandleReloadLootTemplatesSpellCommand(const char* args);
bool HandleReloadTrinityStringCommand(const char* args);
bool HandleReloadNpcGossipCommand(const char* args);
bool HandleReloadNpcOptionCommand(const char* args);
bool HandleReloadNpcTrainerCommand(const char* args);
bool HandleReloadNpcVendorCommand(const char* args);
+ bool HandleReloadPageTextsCommand(const char* args);
+ bool HandleReloadPointsOfInterestCommand(const char* args);
+ bool HandleReloadSpellClickSpellsCommand(const char* args);
bool HandleReloadQuestAreaTriggersCommand(const char* args);
bool HandleReloadQuestEndScriptsCommand(const char* args);
bool HandleReloadQuestStartScriptsCommand(const char* args);
@@ -260,30 +398,33 @@ class ChatHandler
bool HandleReloadSkillFishingBaseLevelCommand(const char* args);
bool HandleReloadSpellAffectCommand(const char* args);
bool HandleReloadSpellRequiredCommand(const char* args);
+ bool HandleReloadSpellAreaCommand(const char* args);
bool HandleReloadSpellElixirCommand(const char* args);
bool HandleReloadSpellLearnSpellCommand(const char* args);
bool HandleReloadSpellLinkedSpellCommand(const char* args);
bool HandleReloadSpellProcEventCommand(const char* args);
+ bool HandleReloadSpellBonusesCommand(const char* args);
bool HandleReloadSpellScriptTargetCommand(const char* args);
bool HandleReloadSpellScriptsCommand(const char* args);
bool HandleReloadSpellTargetPositionCommand(const char* args);
bool HandleReloadSpellThreatsCommand(const char* args);
bool HandleReloadSpellPetAurasCommand(const char* args);
bool HandleReloadSpellDisabledCommand(const char* args);
- bool HandleReloadPageTextsCommand(const char* args);
- bool HandleReloadItemEnchantementsCommand(const char* args);
- bool HandleReloadLocalesCreatureCommand(const char* args);
- bool HandleReloadLocalesGameobjectCommand(const char* args);
- bool HandleReloadLocalesItemCommand(const char* args);
- bool HandleReloadLocalesNpcTextCommand(const char* args);
- bool HandleReloadLocalesPageTextCommand(const char* args);
- bool HandleReloadLocalesQuestCommand(const char* args);
bool HandleReloadAuctionsCommand(const char* args);
+ bool HandleReloadWpScriptsCommand(const char* args);
- bool HandleInstanceListBindsCommand(const char* args);
- bool HandleInstanceUnbindCommand(const char* args);
- bool HandleInstanceStatsCommand(const char* args);
- bool HandleInstanceSaveDataCommand(const char * args);
+ bool HandleResetAchievementsCommand(const char * args);
+ bool HandleResetAllCommand(const char * args);
+ bool HandleResetHonorCommand(const char * args);
+ bool HandleResetLevelCommand(const char * args);
+ bool HandleResetSpellsCommand(const char * args);
+ bool HandleResetStatsCommand(const char * args);
+ bool HandleResetTalentsCommand(const char * args);
+
+ bool HandleSendItemsCommand(const char* args);
+ bool HandleSendMailCommand(const char* args);
+ bool HandleSendMessageCommand(const char * args);
+ bool HandleSendMoneyCommand(const char* args);
bool HandleServerCorpsesCommand(const char* args);
bool HandleServerExitCommand(const char* args);
@@ -291,46 +432,58 @@ class ChatHandler
bool HandleServerIdleShutDownCommand(const char* args);
bool HandleServerInfoCommand(const char* args);
bool HandleServerMotdCommand(const char* args);
+ bool HandleServerPLimitCommand(const char* args);
bool HandleServerRestartCommand(const char* args);
- bool HandleServerSetMotdCommand(const char* args);
bool HandleServerSetLogLevelCommand(const char* args);
- bool HandleServerSetDiffTimeCommand(const char* args);
+ bool HandleServerSetMotdCommand(const char* args);
bool HandleServerShutDownCommand(const char* args);
bool HandleServerShutDownCancelCommand(const char* args);
+ bool HandleServerSetClosedCommand(const char* args);
- bool HandleAddHonorCommand(const char* args);
- bool HandleHonorAddKillCommand(const char* args);
- bool HandleUpdateHonorFieldsCommand(const char* args);
+ bool HandleServerSetLogFileLevelCommand(const char* args);
+ bool HandleServerSetDiffTimeCommand(const char* args);
- bool HandleLoadScriptsCommand(const char* args);
- bool HandleSendQuestPartyMsgCommand(const char* args);
- bool HandleSendQuestInvalidMsgCommand(const char* args);
+ bool HandleTeleCommand(const char * args);
+ bool HandleTeleAddCommand(const char * args);
+ bool HandleTeleDelCommand(const char * args);
+ bool HandleTeleGroupCommand(const char* args);
+ bool HandleTeleNameCommand(const char* args);
+
+ bool HandleUnBanAccountCommand(const char* args);
+ bool HandleUnBanCharacterCommand(const char* args);
+ bool HandleUnBanIPCommand(const char* args);
+
+ bool HandleWpAddCommand(const char* args);
+ bool HandleWpLoadPathCommand(const char* args);
+ bool HandleWpUnLoadPathCommand(const char* args);
+ bool HandleWpModifyCommand(const char* args);
+ bool HandleWpEventCommand(const char* args);
+ bool HandleWpShowCommand(const char* args);
+ bool HandleReloadAllPaths(const char *args);
+
+ bool HandleHelpCommand(const char* args);
+ bool HandleCommandsCommand(const char* args);
+ bool HandleStartCommand(const char* args);
+ bool HandleDismountCommand(const char* args);
+ bool HandleSaveCommand(const char* args);
- bool HandleDebugInArcCommand(const char* args);
- bool HandleDebugSpellFailCommand(const char* args);
+ bool HandleNamegoCommand(const char* args);
+ bool HandleGonameCommand(const char* args);
+ bool HandleGroupgoCommand(const char* args);
+ bool HandleRecallCommand(const char* args);
+ bool HandleAnnounceCommand(const char* args);
+ bool HandleNotifyCommand(const char* args);
+ bool HandleGPSCommand(const char* args);
+ bool HandleTaxiCheatCommand(const char* args);
+ bool HandleWhispersCommand(const char* args);
+ bool HandleModifyDrunkCommand(const char* args);
+
+ bool HandleLoadScriptsCommand(const char* args);
bool HandleGUIDCommand(const char* args);
- bool HandleNameCommand(const char* args);
- bool HandleSubNameCommand(const char* args);
bool HandleItemMoveCommand(const char* args);
bool HandleDeMorphCommand(const char* args);
- bool HandleAddVendorItemCommand(const char* args);
- bool HandleDelVendorItemCommand(const char* args);
- bool HandleChangeLevelCommand(const char* args);
- bool HandleSetPoiCommand(const char* args);
- bool HandleEquipErrorCommand(const char* args);
- bool HandleGoCreatureCommand(const char* args);
- bool HandleGoObjectCommand(const char* args);
- bool HandleGoTicketCommand(const char* args);
- bool HandleGoTriggerCommand(const char* args);
- bool HandleGoGraveyardCommand(const char* args);
- bool HandleTargetObjectCommand(const char* args);
- bool HandleDelObjectCommand(const char* args);
- bool HandleMoveObjectCommand(const char* args);
- bool HandleTurnObjectCommand(const char* args);
- bool HandleObjectStateCommand(const char* args);
bool HandlePInfoCommand(const char* args);
- bool HandlePLimitCommand(const char* args);
bool HandleMuteCommand(const char* args);
bool HandleUnmuteCommand(const char* args);
bool HandleMovegensCommand(const char* args);
@@ -338,38 +491,14 @@ class ChatHandler
bool HandleUnFreezeCommand(const char *args);
bool HandleListFreezeCommand(const char* args);
- bool HandleCharacterDeleteCommand(const char* args);
- bool HandleBanAccountCommand(const char* args);
- bool HandleBanCharacterCommand(const char* args);
- bool HandleBanIPCommand(const char* args);
- bool HandleUnBanAccountCommand(const char* args);
- bool HandleUnBanCharacterCommand(const char* args);
- bool HandleUnBanIPCommand(const char* args);
- bool HandleBanInfoAccountCommand(const char* args);
- bool HandleBanInfoCharacterCommand(const char* args);
- bool HandleBanInfoIPCommand(const char* args);
- bool HandleBanListAccountCommand(const char* args);
- bool HandleBanListCharacterCommand(const char* args);
- bool HandleBanListIPCommand(const char* args);
- bool HandleGoXYCommand(const char* args);
- bool HandleGoXYZCommand(const char* args);
- bool HandleGoZoneXYCommand(const char* args);
- bool HandleGoGridCommand(const char* args);
- bool HandleAddWeaponCommand(const char* args);
- bool HandleAllowMovementCommand(const char* args);
- bool HandleGoCommand(const char* args);
-
bool HandleCooldownCommand(const char* args);
bool HandleUnLearnCommand(const char* args);
bool HandleGetDistanceCommand(const char* args);
- bool HandleGameObjectCommand(const char* args);
- bool HandleAnimCommand(const char* args);
- bool HandlePlaySoundCommand(const char* args);
- bool HandleStandStateCommand(const char* args);
+ bool HandleModifyStandStateCommand(const char* args);
bool HandleDieCommand(const char* args);
bool HandleDamageCommand(const char *args);
bool HandleReviveCommand(const char* args);
- bool HandleMorphCommand(const char* args);
+ bool HandleModifyMorphCommand(const char* args);
bool HandleAuraCommand(const char* args);
bool HandleUnAuraCommand(const char* args);
bool HandleLinkGraveCommand(const char* args);
@@ -393,29 +522,9 @@ class ChatHandler
bool HandleGroupDisbandCommand(const char* args);
bool HandleGroupRemoveCommand(const char* args);
- bool HandleGuildCreateCommand(const char* args);
- bool HandleGuildInviteCommand(const char* args);
- bool HandleGuildUninviteCommand(const char* args);
- bool HandleGuildRankCommand(const char* args);
- bool HandleGuildDeleteCommand(const char* args);
- bool HandleUpdate(const char* args);
bool HandleBankCommand(const char* args);
bool HandleChangeWeather(const char* args);
bool HandleKickPlayerCommand(const char * args);
- bool HandleTeleCommand(const char * args);
- bool HandleAddTeleCommand(const char * args);
- bool HandleDelTeleCommand(const char * args);
- bool HandleListAurasCommand(const char * args);
-
- bool HandleResetHonorCommand(const char * args);
- bool HandleResetLevelCommand(const char * args);
- bool HandleResetSpellsCommand(const char * args);
-
- bool HandleResetStatsCommand(const char * args);
- bool HandleResetTalentsCommand(const char * args);
-
- bool HandleResetAllCommand(const char * args);
-
// GM ticket command handlers
bool HandleGMTicketListCommand(const char* args);
@@ -432,43 +541,13 @@ class ChatHandler
bool HandleMaxSkillCommand(const char* args);
bool HandleSetSkillCommand(const char* args);
- bool HandleListCreatureCommand(const char* args);
- bool HandleListItemCommand(const char* args);
- bool HandleListObjectCommand(const char* args);
- bool HandleNearObjectCommand(const char* args);
- bool HandlePasswordCommand(const char* args);
- bool HandleLockAccountCommand(const char* args);
bool HandleRespawnCommand(const char* args);
-
- //New Wp Commands
- bool HandleWpAddCommand(const char* args);
- bool HandleWpLoadPathCommand(const char* args);
- bool HandleWpUnLoadPathCommand(const char* args);
- bool HandleWpModifyCommand(const char* args);
- bool HandleWpEventCommand(const char* args);
- bool HandleWpShowCommand(const char* args);
- bool HandleReloadAllPaths(const char *args);
-
- bool HandleFlyModeCommand(const char* args);
- bool HandleSendOpcodeCommand(const char* args);
- bool HandleSellErrorCommand(const char* args);
- bool HandleBuyErrorCommand(const char* args);
- bool HandleUpdateWorldStateCommand(const char* args);
- bool HandlePlaySound2Command(const char* args);
- bool HandleSendChannelNotifyCommand(const char* args);
- bool HandleSendChatMsgCommand(const char* args);
- bool HandleRenameCommand(const char * args);
- bool HandleLoadPDumpCommand(const char *args);
- bool HandleWritePDumpCommand(const char *args);
- bool HandleCastCommand(const char *args);
- bool HandleCastBackCommand(const char *args);
- bool HandleCastDistCommand(const char *args);
- bool HandleCastSelfCommand(const char *args);
- bool HandleCastTargetCommand(const char *args);
bool HandleComeToMeCommand(const char *args);
bool HandleCombatStopCommand(const char *args);
- bool HandleCharDeleteCommand(const char *args);
- bool HandleSendMessageCommand(const char * args);
+
+ /*bool HandleCharDeleteCommand(const char *args);
+ bool HandleSendMessageCommand(const char * args);*/
+
bool HandleFlushArenaPointsCommand(const char *args);
bool HandlePlayAllCommand(const char* args);
bool HandleRepairitemsCommand(const char* args);
@@ -477,33 +556,37 @@ class ChatHandler
bool HandleTempAddSpwCommand(const char* args);
//! Development Commands
- bool HandleSetValue(const char* args);
- bool HandleGetValue(const char* args);
+
+ /*bool HandleQuestAdd(const char * args);
+ bool HandleQuestRemove(const char * args);
+ bool HandleQuestComplete(const char * args);*/
+
bool HandleSet32Bit(const char* args);
- bool HandleMod32Value(const char* args);
- bool HandleAddQuest(const char * args);
- bool HandleRemoveQuest(const char * args);
- bool HandleCompleteQuest(const char * args);
bool HandleSaveAllCommand(const char* args);
- bool HandleGetItemState(const char * args);
- bool HandleGetLootRecipient(const char * args);
- bool HandleDebugArenaCommand(const char * args);
- bool HandleDebugThreatList(const char * args);
- bool HandleDebugHostilRefList(const char * args);
- bool HandlePossessCommand(const char* args);
- bool HandleUnPossessCommand(const char* args);
- bool HandleBindSightCommand(const char* args);
- bool HandleUnbindSightCommand(const char* args);
Player* getSelectedPlayer();
Creature* getSelectedCreature();
Unit* getSelectedUnit();
+ WorldObject* getSelectedObject();
+
char* extractKeyFromLink(char* text, char const* linkType, char** something1 = NULL);
char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL);
+
+ // if args have single value then it return in arg2 and arg1 == NULL
+ void extractOptFirstArg(char* args, char** arg1, char** arg2);
+
uint32 extractSpellIdFromLink(char* text);
+ uint64 extractGuidFromLink(char* text);
GameTele const* extractGameTeleFromLink(char* text);
bool GetPlayerGroupAndGUIDByName(const char* cname, Player* &plr, Group* &group, uint64 &guid, bool offline = false);
+ std::string extractPlayerNameFromLink(char* text);
+ // select by arg (name/link) or in-game selection online/offline player
+ bool extractPlayerTarget(char* args, Player** player, uint64* player_guid = NULL, std::string* player_name = NULL);
+
+ std::string playerLink(std::string const& name) const { return m_session ? "|cffffffff|Hplayer:"+name+"|h["+name+"]|h|r" : name; }
+ std::string GetNameLink(Player* chr) const { return playerLink(chr->GetName()); }
+ GameObject* GetNearbyGameObject();
GameObject* GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry);
// Utility methods for commands
@@ -512,6 +595,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 SetSentErrorMessage(bool val){ sentErrorMessage = val;};
private:
@@ -532,8 +616,10 @@ class CliHandler : public ChatHandler
const char *GetTrinityString(int32 entry) const;
bool isAvailable(ChatCommand const& cmd) const;
void SendSysMessage(const char *str);
- char const* GetName() const;
+ std::string GetNameLink() const;
bool needReportToTarget(Player* chr) const;
+ LocaleConstant GetSessionDbcLocale() const;
+ int GetSessionDbLocaleIndex() const;
private:
Print* m_print;
diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp
index 22b58cccdf3..142de50b059 100644
--- a/src/game/ChatHandler.cpp
+++ b/src/game/ChatHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,13 +30,14 @@
#include "ChannelMgr.h"
#include "Group.h"
#include "Guild.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "ScriptCalls.h"
#include "Player.h"
#include "SpellAuras.h"
#include "Language.h"
#include "Util.h"
+#include "GridNotifiersImpl.h"
+#include "CellImpl.h"
void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
{
@@ -66,11 +67,11 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(langDesc->skill_id != 0 && !_player->HasSkill(langDesc->skill_id))
{
// also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
- Unit::AuraList const& langAuras = _player->GetAurasByType(SPELL_AURA_COMPREHEND_LANGUAGE);
+ Unit::AuraEffectList const& langAuras = _player->GetAurasByType(SPELL_AURA_COMPREHEND_LANGUAGE);
bool foundAura = false;
- for(Unit::AuraList::const_iterator i = langAuras.begin();i != langAuras.end(); ++i)
+ for(Unit::AuraEffectList::const_iterator i = langAuras.begin();i != langAuras.end(); ++i)
{
- if((*i)->GetModifier()->m_miscvalue == lang)
+ if((*i)->GetMiscValue() == int32(lang))
{
foundAura = true;
break;
@@ -85,6 +86,21 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(lang == LANG_ADDON)
{
+ if(sWorld.getConfig(CONFIG_CHATLOG_ADDON))
+ {
+ std::string msg = "";
+ recv_data >> msg;
+
+ if(msg.empty())
+ {
+ sLog.outDebug("Player %s send empty addon msg", GetPlayer()->GetName());
+ return;
+ }
+
+ sLog.outChat("[ADDON] Player %s sends: %s",
+ GetPlayer()->GetName(), msg.c_str());
+ }
+
// Disabled addon channel?
if(!sWorld.getConfig(CONFIG_ADDON_CHANNEL))
return;
@@ -122,9 +138,9 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
}
// but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
- Unit::AuraList const& ModLangAuras = _player->GetAurasByType(SPELL_AURA_MOD_LANGUAGE);
+ Unit::AuraEffectList const& ModLangAuras = _player->GetAurasByType(SPELL_AURA_MOD_LANGUAGE);
if(!ModLangAuras.empty())
- lang = ModLangAuras.front()->GetModifier()->m_miscvalue;
+ lang = ModLangAuras.front()->GetMiscValue();
}
if (!_player->CanSpeak())
@@ -192,8 +208,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
Player *player = objmgr.GetPlayer(to.c_str());
uint32 tSecurity = GetSecurity();
- uint32 pSecurity = player ? player->GetSession()->GetSecurity() : 0;
- if(!player || tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers())
+ uint32 pSecurity = player ? player->GetSession()->GetSecurity() : SEC_PLAYER;
+ if (!player || (tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers()))
{
WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
data<<to;
@@ -235,13 +251,19 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
- Group *group = GetPlayer()->GetGroup();
- if(!group)
+ // if player is in battleground, he cannot say to battleground members by /p
+ Group *group = GetPlayer()->GetOriginalGroup();
+ // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid, then return
+ if( !group && (!(group = GetPlayer()->GetGroup()) || group->isBGGroup()) )
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID()));
+ group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID()));
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_PARTY))
+ sLog.outChat("[PARTY] Player %s tells group with leader %s: %s",
+ GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str());
}
break;
case CHAT_MSG_GUILD:
@@ -267,6 +289,17 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
if (guild)
guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
+
+ if(lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHATLOG_GUILD))
+ {
+ sLog.outChat("[GUILD] Player %s tells guild %s: %s",
+ GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str());
+ }
+ else if (lang == LANG_ADDON && sWorld.getConfig(CONFIG_CHATLOG_ADDON))
+ {
+ sLog.outChat("[ADDON] Player %s sends to guild %s: %s",
+ GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str());
+ }
}
break;
@@ -294,6 +327,10 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
if (guild)
guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_GUILD))
+ sLog.outChat("[OFFICER] Player %s tells guild %s officers: %s",
+ GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str());
}
break;
}
@@ -315,13 +352,19 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
- Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup() || group->isBGGroup())
+ // if player is in battleground, he cannot say to battleground members by /ra
+ Group *group = GetPlayer()->GetOriginalGroup();
+ // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid or his group isn't raid, then return
+ if ((!group && !(group = GetPlayer()->GetGroup())) || group->isBGGroup() || !group->isRaidGroup())
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
+ group->BroadcastPacket(&data, false);
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_RAID))
+ sLog.outChat("[RAID] Player %s tells raid with leader %s: %s",
+ GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str());
} break;
case CHAT_MSG_RAID_LEADER:
{
@@ -341,13 +384,18 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
- Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()) || group->isBGGroup())
+ // if player is in battleground, he cannot say to battleground members by /ra
+ Group *group = GetPlayer()->GetOriginalGroup();
+ if( !group && !(group = GetPlayer()->GetGroup()) || group->isBGGroup() || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
+ group->BroadcastPacket(&data, false);
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_RAID))
+ sLog.outChat("[RAID] Leader player %s tells raid: %s",
+ GetPlayer()->GetName(), msg.c_str());
} break;
case CHAT_MSG_RAID_WARNING:
{
@@ -366,8 +414,13 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
return;
WorldPacket data;
+ //in battleground, raid warning is sent only to players in battleground - code is ok
ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
+ group->BroadcastPacket(&data, false);
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_RAID))
+ sLog.outChat("[RAID] Leader player %s warns raid with: %s",
+ GetPlayer()->GetName(), msg.c_str());
} break;
case CHAT_MSG_BATTLEGROUND:
@@ -382,13 +435,18 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
+ //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup() || !group->isBGGroup())
+ if(!group || !group->isBGGroup())
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
+ group->BroadcastPacket(&data, false);
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_BGROUND))
+ sLog.outChat("[BATTLEGROUND] Player %s tells battleground with leader %s: %s",
+ GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str());
} break;
case CHAT_MSG_BATTLEGROUND_LEADER:
@@ -403,13 +461,18 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(msg.empty())
break;
+ //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()) || !group->isBGGroup())
+ if(!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
return;
WorldPacket data;
ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
+ group->BroadcastPacket(&data, false);
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_BGROUND))
+ sLog.outChat("[RAID] Leader player %s tells battleground: %s",
+ GetPlayer()->GetName(), msg.c_str());
} break;
case CHAT_MSG_CHANNEL:
@@ -431,8 +494,22 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
{
- if(Channel *chn = cMgr->GetChannel(channel,_player))
+ Channel *chn = cMgr->GetChannel(channel,_player);
+ if(chn)
+ {
chn->Say(_player->GetGUID(),msg.c_str(),lang);
+
+ if((chn->HasFlag(CHANNEL_FLAG_TRADE) ||
+ chn->HasFlag(CHANNEL_FLAG_GENERAL) ||
+ chn->HasFlag(CHANNEL_FLAG_CITY) ||
+ chn->HasFlag(CHANNEL_FLAG_LFG)) &&
+ sWorld.getConfig(CONFIG_CHATLOG_SYSCHAN))
+ sLog.outChat("[SYSCHAN] Player %s tells channel %s: %s",
+ GetPlayer()->GetName(), chn->GetName().c_str(), msg.c_str());
+ else if(sWorld.getConfig(CONFIG_CHATLOG_CHANNEL))
+ sLog.outChat("[CHANNEL] Player %s tells channel %s: %s",
+ GetPlayer()->GetName(), chn->GetName().c_str(), msg.c_str());
+ }
}
} break;
@@ -491,6 +568,38 @@ void WorldSession::HandleEmoteOpcode( WorldPacket & recv_data )
GetPlayer()->HandleEmoteCommand(emote);
}
+namespace MaNGOS
+{
+ class EmoteChatBuilder
+ {
+ public:
+ EmoteChatBuilder(Player const& pl, uint32 text_emote, uint32 emote_num, Unit const* target)
+ : i_player(pl), i_text_emote(text_emote), i_emote_num(emote_num), i_target(target) {}
+
+ void operator()(WorldPacket& data, int32 loc_idx)
+ {
+ char const* nam = i_target ? i_target->GetNameForLocaleIdx(loc_idx) : NULL;
+ uint32 namlen = (nam ? strlen(nam) : 0) + 1;
+
+ data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
+ data << i_player.GetGUID();
+ data << (uint32)i_text_emote;
+ data << i_emote_num;
+ data << (uint32)namlen;
+ if( namlen > 1 )
+ data.append(nam, namlen);
+ else
+ data << (uint8)0x00;
+ }
+
+ private:
+ Player const& i_player;
+ uint32 i_text_emote;
+ uint32 i_emote_num;
+ Unit const* i_target;
+ };
+} // namespace MaNGOS
+
void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
{
if(!GetPlayer()->isAlive())
@@ -512,56 +621,44 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
recv_data >> emoteNum;
recv_data >> guid;
- const char *nam = 0;
- uint32 namlen = 1;
+ EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote);
+ if (!em)
+ return;
- Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
- Creature *pCreature = dynamic_cast<Creature *>(unit);
- if(unit)
+ uint32 emote_anim = em->textid;
+
+ switch(emote_anim)
{
- nam = unit->GetName();
- namlen = (nam ? strlen(nam) : 0) + 1;
+ case EMOTE_STATE_SLEEP:
+ case EMOTE_STATE_SIT:
+ case EMOTE_STATE_KNEEL:
+ case EMOTE_ONESHOT_NONE:
+ break;
+ default:
+ GetPlayer()->HandleEmoteCommand(emote_anim);
+ break;
}
- EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote);
- if (em)
- {
- uint32 emote_anim = em->textid;
+ Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
- WorldPacket data;
+ CellPair p = MaNGOS::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
- switch(emote_anim)
- {
- case EMOTE_STATE_SLEEP:
- case EMOTE_STATE_SIT:
- case EMOTE_STATE_KNEEL:
- case EMOTE_ONESHOT_NONE:
- break;
- default:
- GetPlayer()->HandleEmoteCommand(emote_anim);
- break;
- }
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
- data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
- data << GetPlayer()->GetGUID();
- data << (uint32)text_emote;
- data << emoteNum;
- data << (uint32)namlen;
- if( namlen > 1 )
- {
- data.append(nam, namlen);
- }
- else
- {
- data << (uint8)0x00;
- }
+ MaNGOS::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit);
+ MaNGOS::LocalizedPacketDo<MaNGOS::EmoteChatBuilder > emote_do(emote_builder);
+ MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::EmoteChatBuilder > > emote_worker(GetPlayer(),sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),emote_do);
+ TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::EmoteChatBuilder > >, WorldTypeMapContainer > message(emote_worker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, message, *GetPlayer()->GetMap());
- GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
+ GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit);
- //Send scripted event call
- if (pCreature && Script)
- Script->ReceiveEmote(GetPlayer(),pCreature,text_emote);
- }
+ //Send scripted event call
+ if (unit && unit->GetTypeId()==TYPEID_UNIT && ((Creature*)unit)->AI())
+ ((Creature*)unit)->AI()->ReceiveEmote(GetPlayer(),text_emote);
}
void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data )
diff --git a/src/game/CombatHandler.cpp b/src/game/CombatHandler.cpp
index f9fb4fd7ee0..f732f128fd0 100644
--- a/src/game/CombatHandler.cpp
+++ b/src/game/CombatHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
#include "Log.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "World.h"
#include "ObjectAccessor.h"
#include "CreatureAI.h"
#include "ObjectDefines.h"
diff --git a/src/game/ConfusedMovementGenerator.cpp b/src/game/ConfusedMovementGenerator.cpp
index 2a81facc126..da383cc8a07 100644
--- a/src/game/ConfusedMovementGenerator.cpp
+++ b/src/game/ConfusedMovementGenerator.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -56,11 +56,12 @@ ConfusedMovementGenerator<T>::Initialize(T &unit)
bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
// if generated wrong path just ignore
- if( is_water && !is_water_ok || !is_water && !is_land_ok )
+ if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
{
i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
}
+
unit.UpdateGroundPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z);
i_waypoints[idx][2] = z;
}
diff --git a/src/game/ConfusedMovementGenerator.h b/src/game/ConfusedMovementGenerator.h
index 4940c4bcaea..ad47b13cb39 100644
--- a/src/game/ConfusedMovementGenerator.h
+++ b/src/game/ConfusedMovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Corpse.cpp b/src/game/Corpse.cpp
index fe4794dea41..3df7838cf60 100644
--- a/src/game/Corpse.cpp
+++ b/src/game/Corpse.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,12 +22,9 @@
#include "Corpse.h"
#include "Player.h"
#include "UpdateMask.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Database/DatabaseEnv.h"
#include "Opcodes.h"
-#include "WorldSession.h"
-#include "WorldPacket.h"
#include "GossipDef.h"
#include "World.h"
@@ -36,7 +33,7 @@ Corpse::Corpse(CorpseType type) : WorldObject()
m_objectType |= TYPEMASK_CORPSE;
m_objectTypeId = TYPEID_CORPSE;
// 2.3.2 - 0x58
- m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION);
+ m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION);
m_valuesCount = CORPSE_END;
@@ -71,26 +68,26 @@ bool Corpse::Create( uint32 guidlow )
return true;
}
-bool Corpse::Create( uint32 guidlow, Player *owner, uint32 mapid, float x, float y, float z, float ang )
+bool Corpse::Create( uint32 guidlow, Player *owner)
{
SetInstanceId(owner->GetInstanceId());
- WorldObject::_Create(guidlow, HIGHGUID_CORPSE, mapid);
+ WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetMapId(), owner->GetPhaseMask());
- Relocate(x,y,z,ang);
+ Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation());
if(!IsPositionValid())
{
- sLog.outError("ERROR: Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
- guidlow,owner->GetName(),x,y);
+ sLog.outError("Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
+ guidlow,owner->GetName(),owner->GetPositionX(), owner->GetPositionY());
return false;
}
SetFloatValue( OBJECT_FIELD_SCALE_X, 1 );
- SetFloatValue( CORPSE_FIELD_POS_X, x );
- SetFloatValue( CORPSE_FIELD_POS_Y, y );
- SetFloatValue( CORPSE_FIELD_POS_Z, z );
- SetFloatValue( CORPSE_FIELD_FACING, ang );
+ SetFloatValue( CORPSE_FIELD_POS_X, GetPositionX() );
+ SetFloatValue( CORPSE_FIELD_POS_Y, GetPositionY() );
+ SetFloatValue( CORPSE_FIELD_POS_Z, GetPositionZ() );
+ SetFloatValue( CORPSE_FIELD_FACING, GetOrientation() );
SetUInt64Value( CORPSE_FIELD_OWNER, owner->GetGUID() );
m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY());
@@ -100,17 +97,27 @@ bool Corpse::Create( uint32 guidlow, Player *owner, uint32 mapid, float x, float
void Corpse::SaveToDB()
{
- // prevent DB data inconsistance problems and duplicates
+ // prevent DB data inconsistence problems and duplicates
CharacterDatabase.BeginTransaction();
DeleteFromDB();
std::ostringstream ss;
- ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance) VALUES ("
- << GetGUIDLow() << ", " << GUID_LOPART(GetOwnerGUID()) << ", " << GetPositionX() << ", " << GetPositionY() << ", " << GetPositionZ() << ", "
- << GetOrientation() << ", " << GetZoneId() << ", " << GetMapId() << ", '";
- for(uint16 i = 0; i < m_valuesCount; i++ )
+ ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance,phaseMask) VALUES ("
+ << GetGUIDLow() << ", "
+ << GUID_LOPART(GetOwnerGUID()) << ", "
+ << GetPositionX() << ", "
+ << GetPositionY() << ", "
+ << GetPositionZ() << ", "
+ << GetOrientation() << ", "
+ << GetZoneId() << ", "
+ << GetMapId() << ", '";
+ for(uint16 i = 0; i < m_valuesCount; ++i )
ss << GetUInt32Value(i) << " ";
- ss << "'," << uint64(m_time) <<", " << uint32(GetType()) << ", " << int(GetInstanceId()) << ")";
+ ss << "',"
+ << uint64(m_time) <<", "
+ << uint32(GetType()) << ", "
+ << int(GetInstanceId()) << ", "
+ << uint16(GetPhaseMask()) << ")"; // prevent out of range error
CharacterDatabase.Execute( ss.str().c_str() );
CharacterDatabase.CommitTransaction();
}
@@ -143,12 +150,12 @@ bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId)
{
bool external = (result != NULL);
if (!external)
- // 0 1 2 3 4 5 6 7 8
- result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance FROM corpse WHERE guid = '%u'",guid);
+ // 0 1 2 3 4 5 6 7 8 9
+ result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance,phaseMask FROM corpse WHERE guid = '%u'",guid);
if( ! result )
{
- sLog.outError("ERROR: Corpse (GUID: %u) not found in table `corpse`, can't load. ",guid);
+ sLog.outError("Corpse (GUID: %u) not found in table `corpse`, can't load. ",guid);
return false;
}
@@ -166,8 +173,8 @@ bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId)
bool Corpse::LoadFromDB(uint32 guid, Field *fields)
{
- // 0 1 2 3 4 5 6 7 8
- //result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance FROM corpse WHERE guid = '%u'",guid);
+ // 0 1 2 3 4 5 6 7 8 9
+ //result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance,phaseMask FROM corpse WHERE guid = '%u'",guid);
float positionX = fields[0].GetFloat();
float positionY = fields[1].GetFloat();
float positionZ = fields[2].GetFloat();
@@ -176,7 +183,7 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
if(!LoadValues( fields[5].GetString() ))
{
- sLog.outError("ERROR: Corpse #%d have broken data in `data` field. Can't be loaded.",guid);
+ sLog.outError("Corpse #%d have broken data in `data` field. Can't be loaded.",guid);
return false;
}
@@ -184,10 +191,11 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
m_type = CorpseType(fields[7].GetUInt32());
if(m_type >= MAX_CORPSE_TYPE)
{
- sLog.outError("ERROR: Corpse (guidlow %d, owner %d) have wrong corpse type, not load.",GetGUIDLow(),GUID_LOPART(GetOwnerGUID()));
+ sLog.outError("Corpse (guidlow %d, owner %d) have wrong corpse type, not load.",GetGUIDLow(),GUID_LOPART(GetOwnerGUID()));
return false;
}
uint32 instanceid = fields[8].GetUInt32();
+ uint32 phaseMask = fields[9].GetUInt32();
// overwrite possible wrong/corrupted guid
SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE));
@@ -195,11 +203,12 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
// place
SetInstanceId(instanceid);
SetMapId(mapid);
+ SetPhaseMask(phaseMask,false);
Relocate(positionX,positionY,positionZ,ort);
if(!IsPositionValid())
{
- sLog.outError("ERROR: Corpse (guidlow %d, owner %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
+ sLog.outError("Corpse (guidlow %d, owner %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
GetGUIDLow(),GUID_LOPART(GetOwnerGUID()),GetPositionX(),GetPositionY());
return false;
}
@@ -211,6 +220,6 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const
{
- return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
+ return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
}
diff --git a/src/game/Corpse.h b/src/game/Corpse.h
index 91131c1cb85..da3511abfbb 100644
--- a/src/game/Corpse.h
+++ b/src/game/Corpse.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,7 +58,7 @@ class Corpse : public WorldObject
void RemoveFromWorld();
bool Create( uint32 guidlow );
- bool Create( uint32 guidlow, Player *owner, uint32 mapid, float x, float y, float z, float ang );
+ bool Create( uint32 guidlow, Player *owner );
void SaveToDB();
bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId);
@@ -82,14 +82,11 @@ class Corpse : public WorldObject
Player* lootRecipient;
bool lootForBody;
- void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); }
- void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); }
- void TextEmote(const char* text, uint64 TargetGuid) { MonsterTextEmote(text,TargetGuid); }
- void Whisper(const char* text, uint64 receiver) { MonsterWhisper(text,receiver); }
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
+ void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
GridReference<Corpse> &GetGridRef() { return m_gridRef; }
private:
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp
index fc79caf7260..3c90f4b3b62 100644
--- a/src/game/Creature.cpp
+++ b/src/game/Creature.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "WorldPacket.h"
-#include "WorldSession.h"
#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
@@ -29,6 +28,7 @@
#include "QuestDef.h"
#include "GossipDef.h"
#include "Player.h"
+#include "PoolHandler.h"
#include "Opcodes.h"
#include "Log.h"
#include "LootMgr.h"
@@ -36,32 +36,24 @@
#include "CreatureAI.h"
#include "CreatureAISelector.h"
#include "Formulas.h"
-#include "SpellAuras.h"
#include "WaypointMovementGenerator.h"
#include "InstanceData.h"
-#include "BattleGround.h"
+#include "BattleGroundMgr.h"
#include "Util.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "OutdoorPvPMgr.h"
-#include "GameEvent.h"
+#include "GameEventMgr.h"
#include "CreatureGroups.h"
// apply implementation of the singletons
#include "Policies/SingletonImp.h"
-void TrainerSpellData::Clear()
-{
- for (TrainerSpellList::iterator itr = spellList.begin(); itr != spellList.end(); ++itr)
- delete (*itr);
- spellList.empty();
-}
-
TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
{
- for(TrainerSpellList::const_iterator itr = spellList.begin(); itr != spellList.end(); ++itr)
- if((*itr)->spell == spell_id)
- return *itr;
+ TrainerSpellMap::const_iterator itr = spellList.find(spell_id);
+ if (itr != spellList.end())
+ return &itr->second;
return NULL;
}
@@ -119,8 +111,7 @@ uint32 CreatureInfo::GetFirstValidModelId() const
bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
- Unit* victim = Unit::GetUnit(m_owner, m_victim);
- if (victim)
+ if(Unit* victim = Unit::GetUnit(m_owner, m_victim))
{
while (!m_assistants.empty())
{
@@ -144,14 +135,16 @@ Unit(),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0),
m_lootMoney(0), m_lootRecipient(0),
m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f),
-m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isTotem(false), m_reactState(REACT_AGGRESSIVE),
-m_regenTimer(2000), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0),
-m_AlreadyCallAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false),
-m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),m_creatureInfo(NULL), m_DBTableGuid(0), m_formation(NULL)
+m_gossipOptionLoaded(false),
+m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
+m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
+m_creatureInfo(NULL), m_reactState(REACT_AGGRESSIVE), m_formation(NULL), m_summonMask(SUMMON_MASK_NONE)
+, m_AlreadySearchedAssistance(false)
{
+ m_regenTimer = 200;
m_valuesCount = UNIT_END;
- for(int i =0; i<4; ++i)
+ for(int i =0; i<CREATURE_MAX_SPELLS; ++i)
m_spells[i] = 0;
m_CreatureSpellCooldowns.clear();
@@ -172,8 +165,8 @@ Creature::~Creature()
i_AI = NULL;
}
- if(m_uint32Values)
- sLog.outDetail("Deconstruct Creature Entry = %u", GetEntry());
+ //if(m_uint32Values)
+ // sLog.outDetail("Deconstruct Creature Entry = %u", GetEntry());
}
void Creature::AddToWorld()
@@ -183,38 +176,56 @@ void Creature::AddToWorld()
{
ObjectAccessor::Instance().AddObject(this);
Unit::AddToWorld();
- SearchFormation();
+ SearchFormationAndPath();
+ AIM_Initialize();
}
}
void Creature::RemoveFromWorld()
{
- ///- Remove the creature from the accessor
if(IsInWorld())
{
if(Map *map = FindMap())
if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
- ((InstanceMap*)map)->GetInstanceData()->OnCreatureRemove(this);
+ ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this, false);
if(m_formation)
formation_mgr.RemoveCreatureFromGroup(m_formation, this);
- ObjectAccessor::Instance().RemoveObject(this);
Unit::RemoveFromWorld();
+ ObjectAccessor::Instance().RemoveObject(this);
}
}
-void Creature::SearchFormation()
+void Creature::SearchFormationAndPath()
{
- if(isPet())
+ if(isSummon())
return;
uint32 lowguid = GetDBTableGUIDLow();
if(!lowguid)
- return;
+ return;
+ bool usePath = (GetDefaultMovementType() == WAYPOINT_MOTION_TYPE);
CreatureGroupInfoType::iterator frmdata = CreatureGroupMap.find(lowguid);
if(frmdata != CreatureGroupMap.end())
+ {
+ if(usePath && lowguid != frmdata->second->leaderGUID)
+ {
+ SetDefaultMovementType(IDLE_MOTION_TYPE);
+ usePath = false;
+ }
formation_mgr.AddCreatureToGroup(frmdata->second->leaderGUID, this);
+ }
+ if(usePath)
+ {
+ if(WaypointMgr.GetPath(lowguid * 10))
+ SetWaypointPathId(lowguid * 10);
+ else
+ {
+ sLog.outErrorDb("Creature DBGUID %u has waypoint motion type, but it does not have a waypoint path!", lowguid);
+ SetDefaultMovementType(IDLE_MOTION_TYPE);
+ }
+ }
}
void Creature::RemoveCorpse()
@@ -315,10 +326,8 @@ bool Creature::InitEntry(uint32 Entry, uint32 team, const CreatureData *data )
if(!m_respawnradius && m_defaultMovementType==RANDOM_MOTION_TYPE)
m_defaultMovementType = IDLE_MOTION_TYPE;
- m_spells[0] = GetCreatureInfo()->spell1;
- m_spells[1] = GetCreatureInfo()->spell2;
- m_spells[2] = GetCreatureInfo()->spell3;
- m_spells[3] = GetCreatureInfo()->spell4;
+ for(int i=0; i < CREATURE_MAX_SPELLS; ++i)
+ m_spells[i] = GetCreatureInfo()->spells[i];
return true;
}
@@ -332,7 +341,6 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data )
// creatures always have melee weapon ready if any
SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE );
- SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_AURAS );
SelectLevel(GetCreatureInfo());
if (team == HORDE)
@@ -448,6 +456,9 @@ void Creature::Update(uint32 diff)
}
else
{
+ // for delayed spells
+ m_Events.Update( diff );
+
m_deathTimer -= diff;
if (m_groupLootTimer && lootingGroupLeaderGUID)
{
@@ -601,6 +612,41 @@ void Creature::RegenerateHealth()
ModifyHealth(addvalue);
}
+void Creature::DoFleeToGetAssistance()
+{
+ if (!getVictim())
+ return;
+
+ if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
+ return;
+
+ float radius = sWorld.getConfig(CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS);
+ if (radius >0)
+ {
+ Creature* pCreature = NULL;
+
+ CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+ MaNGOS::NearestAssistCreatureInCreatureRangeCheck u_check(this, getVictim(), radius);
+ MaNGOS::CreatureLastSearcher<MaNGOS::NearestAssistCreatureInCreatureRangeCheck> searcher(this, pCreature, u_check);
+
+ TypeContainerVisitor<MaNGOS::CreatureLastSearcher<MaNGOS::NearestAssistCreatureInCreatureRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap());
+
+ SetNoSearchAssistance(true);
+ if(!pCreature)
+ //SetFeared(true, getVictim()->GetGUID(), 0 ,sWorld.getConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY));
+ //TODO: use 31365
+ SetControlled(true, UNIT_STAT_FLEEING);
+ else
+ GetMotionMaster()->MoveSeekAssistance(pCreature->GetPositionX(), pCreature->GetPositionY(), pCreature->GetPositionZ());
+ }
+}
+
bool Creature::AIM_Initialize(CreatureAI* ai)
{
// make sure nothing can change the AI during AI update
@@ -610,19 +656,37 @@ bool Creature::AIM_Initialize(CreatureAI* ai)
return false;
}
- if(i_AI) delete i_AI;
- i_motionMaster.Initialize();
+ UnitAI *oldAI = i_AI;
+
+ Motion_Initialize();
+
i_AI = ai ? ai : FactorySelector::selectAI(this);
+ if(oldAI) delete oldAI;
IsAIEnabled = true;
i_AI->InitializeAI();
return true;
}
-bool Creature::Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, const CreatureData *data)
+void Creature::Motion_Initialize()
+{
+ if(!m_formation)
+ i_motionMaster.Initialize();
+ else if(m_formation->getLeader() == this)
+ {
+ m_formation->FormationReset(false);
+ i_motionMaster.Initialize();
+ }
+ else if(m_formation->isFormed())
+ i_motionMaster.MoveIdle(MOTION_SLOT_IDLE); //wait the order of leader
+ else
+ i_motionMaster.Initialize();
+}
+
+bool Creature::Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 team, const CreatureData *data)
{
SetMapId(map->GetId());
SetInstanceId(map->GetInstanceId());
- //m_DBTableGuid = guidlow;
+ SetPhaseMask(phaseMask,false);
//oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0;
const bool bResult = CreateFromProto(guidlow, Entry, team, data);
@@ -743,7 +807,7 @@ bool Creature::isCanInteractWithBattleMaster(Player* pPlayer, bool msg) const
if(!isBattleMaster())
return false;
- uint32 bgTypeId = objmgr.GetBattleMasterBG(GetEntry());
+ BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(GetEntry());
if(!msg)
return pPlayer->GetBGAccessByLevel(bgTypeId);
@@ -759,8 +823,11 @@ bool Creature::isCanInteractWithBattleMaster(Player* pPlayer, bool msg) const
case BATTLEGROUND_NA:
case BATTLEGROUND_BE:
case BATTLEGROUND_AA:
- case BATTLEGROUND_RL: pPlayer->PlayerTalkClass->SendGossipMenu(10024,GetGUID()); break;
- break;
+ case BATTLEGROUND_RL:
+ case BATTLEGROUND_SA:
+ case BATTLEGROUND_DS:
+ case BATTLEGROUND_RV: pPlayer->PlayerTalkClass->SendGossipMenu(10024,GetGUID()); break;
+ default: break;
}
return false;
}
@@ -796,7 +863,7 @@ void Creature::prepareGossipMenu( Player *pPlayer,uint32 gossipid )
if(gso->Id==1)
{
uint32 textid=GetNpcTextId();
- GossipText * gossiptext=objmgr.GetGossipText(textid);
+ GossipText const* gossiptext=objmgr.GetGossipText(textid);
if(!gossiptext)
cantalking=false;
}
@@ -907,13 +974,11 @@ void Creature::sendPreparedGossip(Player* player)
if(!player)
return;
- GossipMenu& gossipmenu = player->PlayerTalkClass->GetGossipMenu();
-
if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT) // if world event npc then
gameeventmgr.HandleWorldEventGossip(player, this); // update world state with progress
- // in case empty gossip menu open quest menu if any
- if (gossipmenu.Empty() && GetNpcTextId() == 0)
+ // in case no gossip flag and quest menu not empty, open quest menu (client expect gossip menu with this flag)
+ if (!HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_GOSSIP) && !player->PlayerTalkClass->GetQuestMenu().Empty())
{
player->SendPreparedQuest(GetGUID());
return;
@@ -1014,7 +1079,7 @@ void Creature::OnGossipSelect(Player* player, uint32 option)
break;
case GOSSIP_OPTION_BATTLEFIELD:
{
- uint32 bgTypeId = objmgr.GetBattleMasterBG(GetEntry());
+ BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(GetEntry());
player->GetSession()->SendBattlegGroundList( GetGUID(), bgTypeId );
break;
}
@@ -1029,12 +1094,12 @@ void Creature::OnPoiSelect(Player* player, GossipOption const *gossip)
{
if(gossip->GossipId==GOSSIP_GUARD_SPELLTRAINER || gossip->GossipId==GOSSIP_GUARD_SKILLTRAINER)
{
- Poi_Icon icon = ICON_POI_0;
+ Poi_Icon icon = ICON_POI_BLANK;
//need add more case.
switch(gossip->Action)
{
case GOSSIP_GUARD_BANK:
- icon=ICON_POI_HOUSE;
+ icon=ICON_POI_SMALL_HOUSE;
break;
case GOSSIP_GUARD_RIDE:
icon=ICON_POI_RWHORSE;
@@ -1043,7 +1108,7 @@ void Creature::OnPoiSelect(Player* player, GossipOption const *gossip)
icon=ICON_POI_BLUETOWER;
break;
default:
- icon=ICON_POI_TOWER;
+ icon=ICON_POI_GREYTOWER;
break;
}
uint32 textid = GetGossipTextId( gossip->Action, GetZoneId() );
@@ -1177,10 +1242,10 @@ void Creature::SaveToDB()
return;
}
- SaveToDB(GetMapId(), data->spawnMask);
+ SaveToDB(GetMapId(), data->spawnMask,GetPhaseMask());
}
-void Creature::SaveToDB(uint32 mapid, uint8 spawnMask)
+void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
{
// update in loaded data
if (!m_DBTableGuid)
@@ -1200,6 +1265,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask)
// data->guid = guid don't must be update at save
data.id = GetEntry();
data.mapid = mapid;
+ data.phaseMask = phaseMask;
data.displayid = displayId;
data.equipmentId = GetEquipmentId();
data.posX = GetPositionX();
@@ -1228,7 +1294,8 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask)
<< m_DBTableGuid << ","
<< GetEntry() << ","
<< mapid <<","
- << (uint32)spawnMask << ","
+ << uint32(spawnMask) << "," // cast to prevent save as symbol
+ << uint16(GetPhaseMask()) << "," // prevent out of range error
<< displayId <<","
<< GetEquipmentId() <<","
<< GetPositionX() << ","
@@ -1362,12 +1429,15 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 team, const
CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(Entry);
if(!cinfo)
{
- sLog.outErrorDb("Error: creature entry %u does not exist.", Entry);
+ sLog.outErrorDb("Creature entry %u does not exist.", Entry);
return false;
}
m_originalEntry = Entry;
- Object::_Create(guidlow, Entry, HIGHGUID_UNIT);
+ if(isVehicle())
+ Object::_Create(guidlow, Entry, HIGHGUID_VEHICLE);
+ else
+ Object::_Create(guidlow, Entry, HIGHGUID_UNIT);
if(!UpdateEntry(Entry, team, data))
return false;
@@ -1378,7 +1448,7 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 team, const
Map *map = FindMap();
if(map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
{
- ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this, Entry);
+ ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this, true);
}
return true;
@@ -1394,18 +1464,22 @@ bool Creature::LoadFromDB(uint32 guid, Map *map)
return false;
}
+ if(const CreatureInfo *cInfo = objmgr.GetCreatureTemplate(data->id))
+ if(cInfo->VehicleId)
+ return false;
+
m_DBTableGuid = guid;
if (map->GetInstanceId() != 0) guid = objmgr.GenerateLowGuid(HIGHGUID_UNIT);
uint16 team = 0;
- if(!Create(guid,map,data->id,team,data))
+ if(!Create(guid,map,data->phaseMask,data->id,team,data))
return false;
Relocate(data->posX,data->posY,data->posZ,data->orientation);
if(!IsPositionValid())
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",GetGUIDLow(),GetEntry(),GetPositionX(),GetPositionY());
+ sLog.outError("Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",GetGUIDLow(),GetEntry(),GetPositionX(),GetPositionY());
return false;
}
//We should set first home position, because then AI calls home movement
@@ -1443,7 +1517,6 @@ bool Creature::LoadFromDB(uint32 guid, Map *map)
// checked at creature_template loading
m_defaultMovementType = MovementGeneratorType(data->movementType);
- AIM_Initialize();
return true;
}
@@ -1453,12 +1526,8 @@ void Creature::LoadEquipment(uint32 equip_entry, bool force)
{
if (force)
{
- for (uint8 i = 0; i < 3; i++)
- {
- SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + i, 0);
- SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2), 0);
- SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2) + 1, 0);
- }
+ for (uint8 i = 0; i < 3; ++i)
+ SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0);
m_equipmentId = 0;
}
return;
@@ -1469,12 +1538,8 @@ void Creature::LoadEquipment(uint32 equip_entry, bool force)
return;
m_equipmentId = equip_entry;
- for (uint8 i = 0; i < 3; i++)
- {
- SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + i, einfo->equipmodel[i]);
- SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2), einfo->equipinfo[i]);
- SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2) + 1, einfo->equipslot[i]);
- }
+ for (uint8 i = 0; i < 3; ++i)
+ SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->equipentry[i]);
}
bool Creature::hasQuest(uint32 quest_id) const
@@ -1532,6 +1597,10 @@ bool Creature::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList, bo
if (u == this)
return true;
+ // phased visibility (both must phased in same way)
+ if(!InSamePhase(u))
+ return false;
+
// always seen by owner
if(GetGUID() == u->GetCharmerOrOwnerGUID())
return true;
@@ -1567,7 +1636,7 @@ bool Creature::IsWithinSightDist(Unit const* u) const
bool Creature::canStartAttack(Unit const* who) const
{
- if(isCivilian()
+ if(isCivilian() || IsNeutralToAll()
|| !who->isInAccessiblePlaceFor(this)
|| !canFly() && GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE
|| !IsWithinDistInMap(who, GetAttackDistance(who)))
@@ -1621,7 +1690,7 @@ void Creature::setDeathState(DeathState s)
{
if((s == JUST_DIED && !m_isDeadByDefault)||(s == JUST_ALIVED && m_isDeadByDefault))
{
- m_deathTimer = m_corpseDelay*1000;
+ m_deathTimer = m_corpseDelay*IN_MILISECONDS;
// always save boss respawn time at death to prevent crash cheating
if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY) || isWorldBoss())
@@ -1646,7 +1715,12 @@ void Creature::setDeathState(DeathState s)
if (canFly() && FallGround())
return;
+ SetNoSearchAssistance(false);
Unit::setDeathState(CORPSE);
+
+ //Dismiss group if is leader
+ if(m_formation && m_formation->getLeader() == this)
+ m_formation->FormationReset(true);
}
if(s == JUST_ALIVED)
{
@@ -1661,9 +1735,9 @@ void Creature::setDeathState(DeathState s)
AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag);
clearUnitState(UNIT_STAT_ALL_STATE);
- i_motionMaster.Initialize();
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
LoadCreaturesAddon(true);
+ Motion_Initialize();
}
}
@@ -1726,11 +1800,17 @@ void Creature::Respawn()
//Call AI respawn virtual function
AI()->JustRespawned();
+ uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), GetTypeId());
+ if (poolid)
+ poolhandler.UpdatePool(poolid, GetGUIDLow(), GetTypeId());
+
//GetMap()->Add(this);
+
+
}
}
-bool Creature::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
+bool Creature::IsImmunedToSpell(SpellEntry const* spellInfo)
{
if (!spellInfo)
return false;
@@ -1738,15 +1818,15 @@ bool Creature::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))
return true;
- return Unit::IsImmunedToSpell(spellInfo, useCharges);
+ return Unit::IsImmunedToSpell(spellInfo);
}
-bool Creature::IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const
+bool Creature::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
{
- if (GetCreatureInfo()->MechanicImmuneMask & (1 << (mechanic-1)))
+ if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->EffectMechanic[index] - 1)))
return true;
- return Unit::IsImmunedToSpellEffect(effect, mechanic);
+ return Unit::IsImmunedToSpellEffect(spellInfo, index);
}
SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim)
@@ -1754,14 +1834,14 @@ SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim)
if(!pVictim)
return NULL;
- for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++)
+ for(uint32 i=0; i < CREATURE_MAX_SPELLS; ++i)
{
if(!m_spells[i])
continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] );
if(!spellInfo)
{
- sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]);
+ sLog.outError("WORLD: unknown spell id %i", m_spells[i]);
continue;
}
@@ -1783,14 +1863,16 @@ SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim)
if(spellInfo->manaCost > GetPower(POWER_MANA))
continue;
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
- float range = GetSpellMaxRange(srange);
- float minrange = GetSpellMinRange(srange);
+ float range = GetSpellMaxRangeForHostile(srange);
+ float minrange = GetSpellMinRangeForHostile(srange);
float dist = GetDistance(pVictim);
//if(!isInFront( pVictim, range ) && spellInfo->AttributesEx )
// continue;
if( dist > range || dist < minrange )
continue;
- if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
+ if(spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
+ continue;
+ if(spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
continue;
return spellInfo;
}
@@ -1802,14 +1884,14 @@ SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim)
if(!pVictim)
return NULL;
- for(uint32 i=0; i < CREATURE_MAX_SPELLS; i++)
+ for(uint32 i=0; i < CREATURE_MAX_SPELLS; ++i)
{
if(!m_spells[i])
continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] );
if(!spellInfo)
{
- sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]);
+ sLog.outError("WORLD: unknown spell id %i", m_spells[i]);
continue;
}
@@ -1827,14 +1909,16 @@ SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim)
if(spellInfo->manaCost > GetPower(POWER_MANA))
continue;
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
- float range = GetSpellMaxRange(srange);
- float minrange = GetSpellMinRange(srange);
+ float range = GetSpellMaxRangeForFriend(srange);
+ float minrange = GetSpellMinRangeForFriend( srange);
float dist = GetDistance(pVictim);
//if(!isInFront( pVictim, range ) && spellInfo->AttributesEx )
// continue;
if( dist > range || dist < minrange )
continue;
- if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
+ if(spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
+ continue;
+ if(spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
continue;
return spellInfo;
}
@@ -1875,22 +1959,6 @@ bool Creature::IsVisibleInGridForPlayer(Player const* pl) const
return false;
}
-void Creature::DoFleeToGetAssistance(float radius) // Optional parameter
-{
- if (!getVictim())
- return;
-
- Creature* pCreature = NULL;
- Trinity::NearestAssistCreatureInCreatureRangeCheck u_check(this,getVictim(),radius);
- Trinity::CreatureLastSearcher<Trinity::NearestAssistCreatureInCreatureRangeCheck> searcher(pCreature, u_check);
- VisitNearbyGridObject(radius, searcher);
-
- if(!pCreature)
- SetControlled(true, UNIT_STAT_FLEEING);
- else
- GetMotionMaster()->MovePoint(0,pCreature->GetPositionX(),pCreature->GetPositionY(),pCreature->GetPositionZ());
-}
-
Unit* Creature::SelectNearestTarget(float dist) const
{
CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
@@ -1902,7 +1970,7 @@ Unit* Creature::SelectNearestTarget(float dist) const
{
Trinity::NearestHostileUnitInAttackDistanceCheck u_check(this, dist);
- Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck> searcher(target, u_check);
+ Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck> searcher(this, target, u_check);
TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
@@ -1922,6 +1990,7 @@ void Creature::CallAssistance()
SetNoCallAssistance(true);
float radius = sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS);
+
if(radius > 0)
{
std::list<Creature*> assistList;
@@ -1932,8 +2001,8 @@ void Creature::CallAssistance()
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
- Trinity::AnyAssistCreatureInRangeCheck u_check(this, getVictim(), radius);
- Trinity::CreatureListSearcher<Trinity::AnyAssistCreatureInRangeCheck> searcher(assistList, u_check);
+ MaNGOS::AnyAssistCreatureInRangeCheck u_check(this, getVictim(), radius);
+ MaNGOS::CreatureListSearcher<MaNGOS::AnyAssistCreatureInRangeCheck> searcher(this, assistList, u_check);
TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyAssistCreatureInRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
@@ -1956,30 +2025,38 @@ void Creature::CallAssistance()
}
}
-bool Creature::CanAssistTo(const Unit* u, const Unit* enemy) const
+bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /*= true*/) const
{
// is it true?
if(!HasReactState(REACT_AGGRESSIVE))
return false;
// we don't need help from zombies :)
- if( !isAlive() )
+ if (!isAlive())
return false;
// skip fighting creature
- if( isInCombat() )
- return false;
-
- // only from same creature faction
- if(getFaction() != u->getFaction() )
+ if (isInCombat())
return false;
// only free creature
- if( GetCharmerOrOwnerGUID() )
+ if (GetCharmerOrOwnerGUID())
return false;
+ // only from same creature faction
+ if (checkfaction)
+ {
+ if (getFaction() != u->getFaction())
+ return false;
+ }
+ else
+ {
+ if (!IsFriendlyTo(u))
+ return false;
+ }
+
// skip non hostile to caster enemy creatures
- if( !IsHostileTo(enemy) )
+ if (!IsHostileTo(enemy))
return false;
return true;
@@ -1993,7 +2070,7 @@ void Creature::SaveRespawnTime()
if(m_respawnTime > time(NULL)) // dead (no corpse)
objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime);
else if(m_deathTimer > 0) // dead (corpse)
- objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),time(NULL)+m_respawnDelay+m_deathTimer/1000);
+ objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),time(NULL)+m_respawnDelay+m_deathTimer/IN_MILISECONDS);
}
bool Creature::IsOutOfThreatArea(Unit* pVictim) const
@@ -2013,12 +2090,12 @@ bool Creature::IsOutOfThreatArea(Unit* pVictim) const
if(sMapStore.LookupEntry(GetMapId())->IsDungeon())
return false;
- float length = pVictim->GetDistance(mHome_X, mHome_Y, mHome_Z);
float AttackDist = GetAttackDistance(pVictim);
uint32 ThreatRadius = sWorld.getConfig(CONFIG_THREAT_RADIUS);
//Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick.
- return ( length > (ThreatRadius > AttackDist ? ThreatRadius : AttackDist));
+ return !pVictim->IsWithinDist3d(mHome_X,mHome_Y,mHome_Z,
+ ThreatRadius > AttackDist ? ThreatRadius : AttackDist);
}
CreatureDataAddon const* Creature::GetCreatureAddon() const
@@ -2058,10 +2135,6 @@ bool Creature::LoadCreaturesAddon(bool reload)
if (cainfo->move_flags != 0)
SetUnitMovementFlags(cainfo->move_flags);
- //Load Path
- if (cainfo->path_id != 0)
- m_path_id = cainfo->path_id;
-
if(cainfo->auras)
{
for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura)
@@ -2074,7 +2147,7 @@ bool Creature::LoadCreaturesAddon(bool reload)
}
// skip already applied aura
- if(HasAura(cAura->spell_id,cAura->effect_idx))
+ if(HasAuraEffect(cAura->spell_id,cAura->effect_idx))
{
if(!reload)
sLog.outErrorDb("Creature (GUIDLow: %u Entry: %u ) has duplicate aura (spell %u effect %u) in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id,cAura->effect_idx);
@@ -2082,9 +2155,8 @@ bool Creature::LoadCreaturesAddon(bool reload)
continue;
}
- Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, cAura->effect_idx, NULL, this, this, 0);
- AddAura(AdditionalAura);
- sLog.outDebug("Spell: %u with Aura %u added to creature (GUIDLow: %u Entry: %u )", cAura->spell_id, AdditionalSpellInfo->EffectApplyAuraName[0],GetGUIDLow(),GetEntry());
+ AddAuraEffect(AdditionalSpellInfo, cAura->effect_idx, this);
+ sLog.outDebug("Spell: %u with Aura %u added to creature (GUIDLow: %u Entry: %u )", cAura->spell_id, AdditionalSpellInfo->EffectApplyAuraName[cAura->effect_idx],GetGUIDLow(),GetEntry());
}
}
return true;
@@ -2118,7 +2190,7 @@ void Creature::AddCreatureSpellCooldown(uint32 spellid)
uint32 cooldown = GetSpellRecoveryTime(spellInfo);
if(cooldown)
- _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/1000);
+ _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILISECONDS);
if(spellInfo->Category)
_AddCreatureCategoryCooldown(spellInfo->Category, time(NULL));
@@ -2137,7 +2209,7 @@ bool Creature::HasCategoryCooldown(uint32 spell_id) const
return true;
CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category);
- return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / 1000)) > time(NULL));
+ return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILISECONDS)) > time(NULL));
}
bool Creature::HasSpellCooldown(uint32 spell_id) const
@@ -2166,7 +2238,7 @@ time_t Creature::GetRespawnTimeEx() const
if(m_respawnTime > now) // dead (no corpse)
return m_respawnTime;
else if(m_deathTimer > 0) // dead (corpse)
- return now+m_respawnDelay+m_deathTimer/1000;
+ return now+m_respawnDelay+m_deathTimer/IN_MILISECONDS;
else
return now;
}
@@ -2208,7 +2280,7 @@ void Creature::AllLootRemovedFromCorpse()
// corpse was not skinnable -> apply corpse looted timer
if (!cinfo || !cinfo->SkinLootId)
- nDeathTimer = (uint32)((m_corpseDelay * 1000) * sWorld.getRate(RATE_CORPSE_DECAY_LOOTED));
+ nDeathTimer = (uint32)((m_corpseDelay * IN_MILISECONDS) * sWorld.getRate(RATE_CORPSE_DECAY_LOOTED));
// corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
else
nDeathTimer = 0;
@@ -2232,12 +2304,17 @@ uint32 Creature::getLevelForTarget( Unit const* target ) const
return level;
}
-std::string Creature::GetScriptName()
+std::string Creature::GetAIName() const
+{
+ return ObjectMgr::GetCreatureTemplate(GetEntry())->AIName;
+}
+
+std::string Creature::GetScriptName() const
{
return objmgr.GetScriptName(GetScriptId());
}
-uint32 Creature::GetScriptId()
+uint32 Creature::GetScriptId() const
{
return ObjectMgr::GetCreatureTemplate(GetEntry())->ScriptID;
}
@@ -2372,4 +2449,4 @@ time_t Creature::GetLinkedCreatureRespawnTime() const
}
return 0;
-}
+} \ No newline at end of file
diff --git a/src/game/Creature.h b/src/game/Creature.h
index b25893b5ba9..2f583e25be0 100644
--- a/src/game/Creature.h
+++ b/src/game/Creature.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +28,6 @@
#include "LootMgr.h"
#include "Database/DatabaseEnv.h"
#include "Cell.h"
-#include "CreatureGroups.h"
#include <list>
@@ -109,6 +108,21 @@ enum Gossip_Guard_Skill
GOSSIP_GUARD_SKILL_ENGINERING = 91
};
+enum GossipOptionIcon
+{
+ GOSSIP_ICON_CHAT = 0, //white chat bubble
+ GOSSIP_ICON_VENDOR = 1, //brown bag
+ GOSSIP_ICON_TAXI = 2, //flight
+ GOSSIP_ICON_TRAINER = 3, //book
+ GOSSIP_ICON_INTERACT_1 = 4, //interaction wheel
+ GOSSIP_ICON_INTERACT_2 = 5, //interaction wheel
+ GOSSIP_ICON_MONEY_BAG = 6, //brown bag with yellow dot
+ GOSSIP_ICON_TALK = 7, //white chat bubble with black dots
+ GOSSIP_ICON_TABARD = 8, //tabard
+ GOSSIP_ICON_BATTLE = 9, //two swords
+ GOSSIP_ICON_DOT = 10 //yellow dot
+};
+
struct GossipOption
{
uint32 Id;
@@ -132,12 +146,23 @@ enum CreatureFlagsExtra
CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
+ CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
//CREATURE_FLAG_EXTRA_CHARM_AI = 0x00008000, // use ai when charmed
- CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00010000, // cannot be taunted
CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
};
+enum SummonMask
+{
+ SUMMON_MASK_NONE = 0x00000000,
+ SUMMON_MASK_SUMMON = 0x00000001,
+ SUMMON_MASK_MINION = 0x00000002,
+ SUMMON_MASK_GUARDIAN = 0x00000004,
+ SUMMON_MASK_TOTEM = 0x00000008,
+ SUMMON_MASK_PET = 0x00000010,
+ SUMMON_MASK_VEHICLE = 0x00000020,
+};
+
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
#if defined( __GNUC__ )
#pragma pack(1)
@@ -178,7 +203,7 @@ struct CreatureInfo
uint32 rangeattacktime;
uint32 unit_flags; // enum UnitFlags mask values
uint32 dynamicflags;
- uint32 family; // enum CreatureFamily values for type==CREATURE_TYPE_BEAST, or 0 in another cases
+ uint32 family; // enum CreatureFamily values (optional)
uint32 trainer_type;
uint32 trainer_spell;
uint32 classNum;
@@ -197,16 +222,16 @@ struct CreatureInfo
int32 resistance4;
int32 resistance5;
int32 resistance6;
- uint32 spell1;
- uint32 spell2;
- uint32 spell3;
- uint32 spell4;
+ uint32 spells[CREATURE_MAX_SPELLS];
uint32 PetSpellDataId;
+ uint32 VehicleId;
uint32 mingold;
uint32 maxgold;
char const* AIName;
uint32 MovementType;
uint32 InhabitType;
+ float unk16;
+ float unk17;
bool RacialLeader;
bool RegenHealth;
uint32 equipmentId;
@@ -223,6 +248,8 @@ struct CreatureInfo
return SKILL_HERBALISM;
else if(type_flags & CREATURE_TYPEFLAGS_MININGLOOT)
return SKILL_MINING;
+ else if(type_flags & CREATURE_TYPEFLAGS_ENGINEERLOOT)
+ return SKILL_ENGINERING;
else
return SKILL_SKINNING; // normal case
}
@@ -245,12 +272,15 @@ struct NpcOptionLocale
std::vector<std::string> BoxText;
};
+struct PointOfInterestLocale
+{
+ std::vector<std::string> IconName;
+};
+
struct EquipmentInfo
{
uint32 entry;
- uint32 equipmodel[3];
- uint32 equipinfo[3];
- uint32 equipslot[3];
+ uint32 equipentry[3];
};
// from `creature` table
@@ -258,6 +288,7 @@ struct CreatureData
{
uint32 id; // entry in creature_template
uint16 mapid;
+ uint16 phaseMask;
uint32 displayid;
int32 equipmentId;
float posX;
@@ -284,7 +315,6 @@ struct CreatureDataAddonAura
struct CreatureDataAddon
{
uint32 guidOrEntry;
- uint32 path_id;
uint32 mount;
uint32 bytes0;
uint32 bytes1;
@@ -311,6 +341,31 @@ enum InhabitTypeValues
INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR
};
+// Enums used by StringTextData::Type (CreatureEventAI)
+enum ChatType
+{
+ CHAT_TYPE_SAY = 0,
+ CHAT_TYPE_YELL = 1,
+ CHAT_TYPE_TEXT_EMOTE = 2,
+ CHAT_TYPE_BOSS_EMOTE = 3,
+ CHAT_TYPE_WHISPER = 4,
+ CHAT_TYPE_BOSS_WHISPER = 5,
+ CHAT_TYPE_ZONE_YELL = 6
+};
+
+//Selection method used by SelectTarget (CreatureEventAI)
+enum AttackingTarget
+{
+ ATTACKING_TARGET_RANDOM = 0, //Just selects a random target
+ ATTACKING_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom
+ ATTACKING_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top
+ /* not implemented
+ ATTACKING_TARGET_RANDOM_PLAYER, //Just selects a random target (player only)
+ ATTACKING_TARGET_TOPAGGRO_PLAYER, //Selects targes from top aggro to bottom (player only)
+ ATTACKING_TARGET_BOTTOMAGGRO_PLAYER, //Selects targets from bottom aggro to top (player only)
+ */
+};
+
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
#if defined( __GNUC__ )
#pragma pack()
@@ -352,8 +407,9 @@ struct VendorItemData
void Clear()
{
- for (VendorItemList::iterator itr = m_items.begin(); itr != m_items.end(); ++itr)
+ for (VendorItemList::const_iterator itr = m_items.begin(); itr != m_items.end(); ++itr)
delete (*itr);
+ m_items.clear();
}
};
@@ -371,25 +427,34 @@ typedef std::list<VendorItemCount> VendorItemCounts;
struct TrainerSpell
{
+ TrainerSpell() : spell(0), spellCost(0), reqSkill(0), reqSkillValue(0), reqLevel(0), learnedSpell(0) {}
+
+ TrainerSpell(uint32 _spell, uint32 _spellCost, uint32 _reqSkill, uint32 _reqSkillValue, uint32 _reqLevel, uint32 _learnedspell)
+ : spell(_spell), spellCost(_spellCost), reqSkill(_reqSkill), reqSkillValue(_reqSkillValue), reqLevel(_reqLevel), learnedSpell(_learnedspell)
+ {}
+
uint32 spell;
- uint32 spellcost;
- uint32 reqskill;
- uint32 reqskillvalue;
- uint32 reqlevel;
+ uint32 spellCost;
+ uint32 reqSkill;
+ uint32 reqSkillValue;
+ uint32 reqLevel;
+ uint32 learnedSpell;
+
+ // helpers
+ bool IsCastable() const { return learnedSpell != spell; }
};
-typedef std::vector<TrainerSpell*> TrainerSpellList;
+typedef UNORDERED_MAP<uint32 /*spellid*/, TrainerSpell> TrainerSpellMap;
struct TrainerSpellData
{
TrainerSpellData() : trainerType(0) {}
- TrainerSpellList spellList;
+ TrainerSpellMap spellList;
uint32 trainerType; // trainer type based at trainer spells, can be different from creature_template value.
// req. for correct show non-prof. trainers like weaponmaster, allowed values 0 and 2.
-
- void Clear();
TrainerSpell const* Find(uint32 spell_id) const;
+ void Clear() { spellList.clear(); }
};
typedef std::list<GossipOption> GossipOptionList;
@@ -411,7 +476,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
void AddToWorld();
void RemoveFromWorld();
- bool Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, const CreatureData *data = NULL);
+ bool Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 team, const CreatureData *data = NULL);
bool LoadCreaturesAddon(bool reload = false);
void SelectLevel(const CreatureInfo *cinfo);
void LoadEquipment(uint32 equip_entry, bool force=false);
@@ -423,9 +488,13 @@ class TRINITY_DLL_SPEC Creature : public Unit
void GetRespawnCoord(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
uint32 GetEquipmentId() const { return m_equipmentId; }
- bool isPet() const { return m_isPet; }
+ uint32 HasSummonMask(uint32 mask) const { return mask & m_summonMask; }
+ bool isSummon() const { return m_summonMask & SUMMON_MASK_SUMMON; }
+ bool isPet() const { return m_summonMask & SUMMON_MASK_PET; }
+ bool isVehicle() const { return m_summonMask & SUMMON_MASK_VEHICLE; }
+ bool isWorldCreature() const { return m_summonMask & SUMMON_MASK_PET; }
+ bool isTotem() const { return m_summonMask & SUMMON_MASK_TOTEM; }
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
- bool isTotem() const { return m_isTotem; }
bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
bool isTrigger() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER; }
@@ -440,9 +509,9 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool isCanInteractWithBattleMaster(Player* player, bool msg) const;
bool isCanTrainingAndResetTalentsOf(Player* pPlayer) const;
bool IsOutOfThreatArea(Unit* pVictim) const;
- bool IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges = false);
+ bool IsImmunedToSpell(SpellEntry const* spellInfo);
// redefine Unit::IsImmunedToSpell
- bool IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const;
+ bool IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const;
// redefine Unit::IsImmunedToSpellEffect
bool isElite() const
{
@@ -466,6 +535,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool IsInEvadeMode() const;
bool AIM_Initialize(CreatureAI* ai = NULL);
+ void Motion_Initialize();
void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
CreatureAI* AI() { return (CreatureAI*)i_AI; }
@@ -507,8 +577,9 @@ class TRINITY_DLL_SPEC Creature : public Unit
CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; }
CreatureDataAddon const* GetCreatureAddon() const;
- std::string GetScriptName();
- uint32 GetScriptId();
+ std::string GetAIName() const;
+ std::string GetScriptName() const;
+ uint32 GetScriptId() const;
void prepareGossipMenu( Player *pPlayer, uint32 gossipid = 0 );
void sendPreparedGossip( Player* player );
@@ -522,15 +593,11 @@ class TRINITY_DLL_SPEC Creature : public Unit
GossipOption const* GetGossipOption( uint32 id ) const;
void addGossipOption(GossipOption const& gso) { m_goptions.push_back(gso); }
- void setEmoteState(uint8 emote) { m_emoteState = emote; };
- void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); }
- void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); }
- void TextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(text,TargetGuid,IsBossEmote); }
- void Whisper(const char* text, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(text,receiver,IsBossWhisper); }
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
void TextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(textId,TargetGuid,IsBossEmote); }
void Whisper(int32 textId, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(textId,receiver,IsBossWhisper); }
+ void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
// overwrite WorldObject function for proper name localization
const char* GetNameForLocaleIdx(int32 locale_idx) const;
@@ -541,7 +608,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool LoadFromDB(uint32 guid, Map *map);
void SaveToDB();
// overwrited in Pet
- virtual void SaveToDB(uint32 mapid, uint8 spawnMask);
+ virtual void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
virtual void DeleteFromDB(); // overwrited in Pet
Loot loot;
@@ -567,10 +634,12 @@ class TRINITY_DLL_SPEC Creature : public Unit
float GetAttackDistance(Unit const* pl) const;
Unit* SelectNearestTarget(float dist = 0) const;
+ void DoFleeToGetAssistance();
void CallAssistance();
void SetNoCallAssistance(bool val) { m_AlreadyCallAssistance = val; }
- bool CanAssistTo(const Unit* u, const Unit* enemy) const;
- void DoFleeToGetAssistance(float radius = 50);
+ void SetNoSearchAssistance(bool val) { m_AlreadySearchedAssistance = val; }
+ bool HasSearchedAssistance() { return m_AlreadySearchedAssistance; }
+ bool CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction = true) const;
MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
@@ -582,6 +651,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool IsVisibleInGridForPlayer(Player const* pl) const;
void RemoveCorpse();
+ bool isDeadByDefault() const { return m_isDeadByDefault; };
time_t const& GetRespawnTime() const { return m_respawnTime; }
time_t GetRespawnTimeEx() const;
@@ -623,17 +693,18 @@ class TRINITY_DLL_SPEC Creature : public Unit
uint32 GetGlobalCooldown() const { return m_GlobalCooldown; }
- uint32 GetWaypointPath(){return m_path_id;}
- void LoadPath(uint32 pathid) { m_path_id = pathid; }
+ uint32 GetWaypointPathId() const { return m_pathId; }
+ void SetWaypointPathId(uint32 pathid) { m_pathId = pathid; }
uint32 GetCurrentWaypointID(){return m_waypointID;}
void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;}
- void SearchFormation();
- CreatureGroup *GetFormation(){return m_formation;}
+ void SearchFormationAndPath();
+ CreatureGroup *GetFormation() {return m_formation;}
void SetFormation(CreatureGroup *formation) {m_formation = formation;}
Unit *SelectVictim();
+ void SetDeadByDefault (bool death_state) {m_isDeadByDefault = death_state;}
void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; }
bool IsReputationGainDisabled() { return DisableReputationGain; }
@@ -667,19 +738,17 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool m_gossipOptionLoaded;
GossipOptionList m_goptions;
- uint8 m_emoteState;
- bool m_isPet; // set only in Pet::Pet
- bool m_isTotem; // set only in Totem::Totem
+ uint32 m_summonMask;
ReactStates m_reactState; // for AI, not charmInfo
void RegenerateMana();
void RegenerateHealth();
- uint32 m_regenTimer;
MovementGeneratorType m_defaultMovementType;
Cell m_currentCell; // store current cell where creature listed
uint32 m_DBTableGuid; ///< For new or temporary creatures is 0 for saved it is lowguid
uint32 m_equipmentId;
bool m_AlreadyCallAssistance;
+ bool m_AlreadySearchedAssistance;
bool m_regenHealth;
bool m_AI_locked;
bool m_isDeadByDefault;
@@ -697,7 +766,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
private:
//WaypointMovementGenerator vars
uint32 m_waypointID;
- uint32 m_path_id;
+ uint32 m_pathId;
//Formation var
CreatureGroup *m_formation;
diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp
index 3a7cb896e88..e9970071f23 100644
--- a/src/game/CreatureAI.cpp
+++ b/src/game/CreatureAI.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,58 +19,72 @@
*/
#include "CreatureAI.h"
+#include "CreatureAIImpl.h"
#include "Creature.h"
-#include "Player.h"
-#include "Pet.h"
-#include "SpellAuras.h"
#include "World.h"
+#include "SpellMgr.h"
-void UnitAI::AttackStart(Unit *victim)
+//Disable CreatureAI when charmed
+void CreatureAI::OnCharmed(bool apply)
+{
+ //me->IsAIEnabled = !apply;*/
+ me->NeedChangeAI = true;
+ me->IsAIEnabled = false;
+}
+
+AISpellInfoType * UnitAI::AISpellInfo;
+TRINITY_DLL_SPEC AISpellInfoType * GetAISpellInfo(uint32 i) { return &CreatureAI::AISpellInfo[i]; }
+
+void CreatureAI::DoZoneInCombat(Creature* creature)
{
- if(!victim)
+ if (!creature)
+ creature = me;
+
+ if(!creature->CanHaveThreatList())
return;
- if(me->Attack(victim, true))
+ Map *map = creature->GetMap();
+ if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
{
- //DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", me->GetName(), victim->GetGUIDLow());
- me->GetMotionMaster()->MoveChase(victim);
+ sLog.outError("DoZoneInCombat call for map that isn't an instance (creature entry = %d)", creature->GetTypeId() == TYPEID_UNIT ? ((Creature*)creature)->GetEntry() : 0);
+ return;
}
-}
-void UnitAI::DoMeleeAttackIfReady()
-{
- //Make sure our attack is ready and we aren't currently casting before checking distance
- if (me->isAttackReady() && !me->hasUnitState(UNIT_STAT_CASTING))
+ if(!creature->HasReactState(REACT_PASSIVE) && !creature->getVictim())
{
- //If we are within range melee the target
- if (me->IsWithinMeleeRange(me->getVictim()))
+ if(Unit *target = creature->SelectNearestTarget(50))
+ creature->AI()->AttackStart(target);
+ else if(creature->isSummon())
{
- me->AttackerStateUpdate(me->getVictim());
- me->resetAttackTimer();
+ if(Unit *summoner = ((TempSummon*)creature)->GetSummoner())
+ {
+ Unit *target = summoner->getAttackerForHelper();
+ if(!target && summoner->CanHaveThreatList() && !summoner->getThreatManager().isThreatListEmpty())
+ target = summoner->getThreatManager().getHostilTarget();
+ if(target && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(target)))
+ creature->AI()->AttackStart(target);
+ }
}
}
- if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK) && !me->hasUnitState(UNIT_STAT_CASTING))
+
+ if(!creature->HasReactState(REACT_PASSIVE) && !creature->getVictim())
{
- //If we are within range melee the target
- if (me->IsWithinMeleeRange(me->getVictim()))
+ sLog.outError("DoZoneInCombat called for creature that has empty threat list (creature entry = %u)", creature->GetEntry());
+ return;
+ }
+
+ Map::PlayerList const &PlayerList = map->GetPlayers();
+ for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
+ {
+ if (i->getSource()->isAlive())
{
- me->AttackerStateUpdate(me->getVictim(), OFF_ATTACK);
- me->resetAttackTimer(OFF_ATTACK);
+ creature->SetInCombatWith(i->getSource());
+ i->getSource()->SetInCombatWith(creature);
+ creature->AddThreat(i->getSource(), 0.0f);
}
}
}
-//Enable PlayerAI when charmed
-void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; }
-
-//Disable CreatureAI when charmed
-void CreatureAI::OnCharmed(bool apply)
-{
- //me->IsAIEnabled = !apply;*/
- me->NeedChangeAI = true;
- me->IsAIEnabled = false;
-}
-
void CreatureAI::MoveInLineOfSight(Unit *who)
{
if(me->getVictim())
@@ -84,49 +98,92 @@ void CreatureAI::MoveInLineOfSight(Unit *who)
AttackStart(who->getVictim());
}
-bool CreatureAI::UpdateVictim()
+void CreatureAI::SelectNearestTarget(Unit *who)
+{
+ if(me->getVictim() && me->GetDistanceOrder(who, me->getVictim()) && me->canAttack(who))
+ {
+ me->getThreatManager().modifyThreatPercent(me->getVictim(), -100);
+ me->AddThreat(who, 1000000.0f);
+ }
+}
+
+void CreatureAI::SetGazeOn(Unit *target)
+{
+ if(me->canAttack(target))
+ {
+ AttackStart(target);
+ me->SetReactState(REACT_PASSIVE);
+ }
+}
+
+bool CreatureAI::UpdateVictimWithGaze()
{
if(!me->isInCombat())
return false;
+
+ if(me->HasReactState(REACT_PASSIVE))
+ {
+ if(me->getVictim())
+ return true;
+ else
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+
if(Unit *victim = me->SelectVictim())
AttackStart(victim);
return me->getVictim();
}
-void CreatureAI::EnterEvadeMode()
+bool CreatureAI::UpdateVictim()
{
+ if(!me->isInCombat())
+ return false;
+
+ if(!me->HasReactState(REACT_PASSIVE))
+ {
+ if(Unit *victim = me->SelectVictim())
+ AttackStart(victim);
+ return me->getVictim();
+ }
+ else if(me->getThreatManager().isThreatListEmpty())
+ {
+ EnterEvadeMode();
+ return false;
+ }
+
+ return true;
+}
+
+bool CreatureAI::_EnterEvadeMode()
+{
+ if(me->IsInEvadeMode() || !me->isAlive())
+ return false;
+
me->RemoveAllAuras();
me->DeleteThreatList();
- me->CombatStop();
+ me->CombatStop(true);
me->LoadCreaturesAddon();
me->SetLootRecipient(NULL);
me->ResetDamageByPlayers();
- if(me->isAlive())
- me->GetMotionMaster()->MoveTargetedHome();
+ return true;
}
-void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
+void CreatureAI::EnterEvadeMode()
{
- Creature *charmer = (Creature*)me->GetCharmer();
-
- //kill self if charm aura has infinite duration
- if(charmer->IsInEvadeMode())
- {
- Unit::AuraList const& auras = me->GetAurasByType(SPELL_AURA_MOD_CHARM);
- for(Unit::AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
- if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->IsPermanent())
- {
- charmer->Kill(me);
- return;
- }
- }
+ if(!_EnterEvadeMode())
+ return;
- if(!charmer->isInCombat())
- me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ if(Unit *owner = me->GetCharmerOrOwner())
+ me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE);
+ else
+ me->GetMotionMaster()->MoveTargetedHome();
- Unit *target = me->getVictim();
- if(!target || !charmer->canAttack(target))
- AttackStart(charmer->SelectNearestTarget());
+ Reset();
}
+/*void CreatureAI::AttackedBy( Unit* attacker )
+{
+ if(!m_creature->getVictim())
+ AttackStart(attacker);
+}*/
diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h
index b7a584fd36e..d9d437c936c 100644
--- a/src/game/CreatureAI.h
+++ b/src/game/CreatureAI.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,12 +21,10 @@
#ifndef TRINITY_CREATUREAI_H
#define TRINITY_CREATUREAI_H
+#include "UnitAI.h"
#include "Common.h"
-#include "Platform/Define.h"
-#include "Policies/Singleton.h"
-#include "Dynamic/ObjectRegistry.h"
-#include "Dynamic/FactoryHolder.h"
+class WorldObject;
class Unit;
class Creature;
class Player;
@@ -36,7 +34,7 @@ struct SpellEntry;
#define VISIBILITY_RANGE 10000
//Spell targets used by SelectSpell
-enum SelectTarget
+enum SelectTargetType
{
SELECT_TARGET_DONTCARE = 0, //All target types allowed
@@ -60,73 +58,41 @@ enum SelectEffect
SELECT_EFFECT_AURA, //Spell applies an aura
};
-//Selection method used by SelectTarget
-enum SelectAggroTarget
+enum SCEquip
{
- SELECT_TARGET_RANDOM = 0, //Just selects a random target
- SELECT_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom
- SELECT_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top
- SELECT_TARGET_NEAREST,
- SELECT_TARGET_FARTHEST,
-};
-
-class TRINITY_DLL_SPEC UnitAI
-{
- protected:
- Unit *me;
- public:
- UnitAI(Unit *u) : me(u) {}
- virtual void AttackStart(Unit *);
- virtual void UpdateAI(const uint32 diff) = 0;
-
- virtual void InitializeAI() { Reset(); }
-
- virtual void Reset() {};
-
- // Called when unit is charmed
- virtual void OnCharmed(bool apply) = 0;
-
- // Pass parameters between AI
- virtual void DoAction(const int32 param) {}
-
- //Do melee swing of current victim if in rnage and ready and not casting
- void DoMeleeAttackIfReady();
-};
-
-class TRINITY_DLL_SPEC PlayerAI : public UnitAI
-{
- protected:
- Player *me;
- public:
- PlayerAI(Player *p) : UnitAI((Unit*)p), me(p) {}
-
- void OnCharmed(bool apply);
-};
-
-class TRINITY_DLL_SPEC SimpleCharmedAI : public PlayerAI
-{
- public:
- void UpdateAI(const uint32 diff);
+ EQUIP_NO_CHANGE = -1,
+ EQUIP_UNEQUIP = 0
};
class TRINITY_DLL_SPEC CreatureAI : public UnitAI
{
protected:
- Creature *me;
+ Creature * const me;
+ Creature * const m_creature;
bool UpdateVictim();
+ bool UpdateVictimWithGaze();
+
+ void SelectNearestTarget(Unit *who);
public:
- CreatureAI(Creature *c) : UnitAI((Unit*)c), me(c) {}
+ explicit CreatureAI(Creature *c) : UnitAI((Unit*)c), me(c), m_creature(c) {}
virtual ~CreatureAI() {}
- // Called if IsVisible(Unit *who) is true at each *who move
+ ///== Reactions At =================================
+
+ // Called if IsVisible(Unit *who) is true at each *who move, reaction at visibility zone enter
virtual void MoveInLineOfSight(Unit *);
- // Called at stopping attack by any attacker
+ // Called for reaction at stopping attack at no attackers or targets
virtual void EnterEvadeMode();
+ // Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
+ virtual void EnterCombat(Unit* /*enemy*/) {}
+
// Called at any Damage from any attacker (before damage apply)
+ // Note: it for recalculation damage or special reaction at damage
+ // for attack reaction use AttackedBy called for not DOT damage in Unit::DealDamage also
virtual void DamageTaken(Unit *done_by, uint32 & /*damage*/) {}
// Called when the creature is killed
@@ -146,32 +112,53 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI
// Called when spell hits a target
virtual void SpellHitTarget(Unit* target, const SpellEntry*) {}
- // Called when vitim entered water and creature can not enter water
- virtual bool canReachByRangeAttack(Unit*) { return false; }
+ // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
+ //virtual void AttackedBy(Unit* attacker);
// Called when creature is spawned or respawned (for reseting variables)
- virtual void JustRespawned() {}
+ virtual void JustRespawned() { Reset(); }
// Called at waypoint reached or point movement finished
virtual void MovementInform(uint32 /*MovementType*/, uint32 /*Data*/) {}
void OnCharmed(bool apply);
-};
-struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
-{
+ //virtual void SpellClick(Player *player) {}
- SelectableAI(const char *id) : FactoryHolder<CreatureAI>(id) {}
-};
+ // Called at reaching home after evade
+ virtual void JustReachedHome() {}
-template<class REAL_AI>
-struct CreatureAIFactory : public SelectableAI
-{
- CreatureAIFactory(const char *name) : SelectableAI(name) {}
+ void DoZoneInCombat(Creature* pUnit = NULL);
+
+ // Called at text emote receive from player
+ virtual void ReceiveEmote(Player* pPlayer, uint32 text_emote) {}
+
+ ///== Triggered Actions Requested ==================
- CreatureAI* Create(void *) const;
+ // Called when creature attack expected (if creature can and no have current victim)
+ // Note: for reaction at hostile action must be called AttackedBy function.
+ //virtual void AttackStart(Unit *) {}
- int Permit(const Creature *c) const { return REAL_AI::Permissible(c); }
+ // Called at World update tick
+ //virtual void UpdateAI(const uint32 diff ) {}
+
+ ///== State checks =================================
+
+ // Is unit visible for MoveInLineOfSight
+ //virtual bool IsVisible(Unit *) const { return false; }
+
+ // Called when victim entered water and creature can not enter water
+ virtual bool canReachByRangeAttack(Unit*) { return false; }
+
+ ///== Fields =======================================
+
+ // Pointer to controlled by AI creature
+ //Creature* const m_creature;
+
+ void SetGazeOn(Unit *target);
+
+ protected:
+ bool _EnterEvadeMode();
};
enum Permitions
@@ -184,8 +171,4 @@ enum Permitions
PERMIT_BASE_SPECIAL = 800
};
-typedef FactoryHolder<CreatureAI> CreatureAICreator;
-typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry;
-typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository;
#endif
-
diff --git a/src/game/CreatureAIFactory.h b/src/game/CreatureAIFactory.h
new file mode 100644
index 00000000000..d546c2b1720
--- /dev/null
+++ b/src/game/CreatureAIFactory.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef TRINITY_CREATUREAIFACTORY_H
+#define TRINITY_CREATUREAIFACTORY_H
+
+//#include "Policies/Singleton.h"
+#include "Dynamic/ObjectRegistry.h"
+#include "Dynamic/FactoryHolder.h"
+
+struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
+{
+ SelectableAI(const char *id) : FactoryHolder<CreatureAI>(id) {}
+};
+
+template<class REAL_AI>
+struct CreatureAIFactory : public SelectableAI
+{
+ CreatureAIFactory(const char *name) : SelectableAI(name) {}
+
+ CreatureAI* Create(void *) const;
+
+ int Permit(const Creature *c) const { return REAL_AI::Permissible(c); }
+};
+
+template<class REAL_AI>
+inline CreatureAI*
+CreatureAIFactory<REAL_AI>::Create(void *data) const
+{
+ Creature* creature = reinterpret_cast<Creature *>(data);
+ return (new REAL_AI(creature));
+}
+
+typedef FactoryHolder<CreatureAI> CreatureAICreator;
+typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry;
+typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository;
+#endif
diff --git a/src/game/CreatureAIImpl.h b/src/game/CreatureAIImpl.h
index 2f82522f426..95a16d0ac5b 100644
--- a/src/game/CreatureAIImpl.h
+++ b/src/game/CreatureAIImpl.h
@@ -1,7 +1,5 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,14 +18,160 @@
#ifndef CREATUREAIIMPL_H
#define CREATUREAIIMPL_H
-#include "CreatureAI.h"
+#include "Common.h"
+#include "Platform/Define.h"
+
+#define HEROIC(n,h) (HeroicMode ? h : n)
+
+template<class T>
+inline
+const T& RAND(const T& v1, const T& v2)
+{
+ return rand()%2 ? v1 : v2;
+}
+
+template<class T>
+inline
+const T& RAND(const T& v1, const T& v2, const T& v3)
+{
+ switch(rand()%3)
+ {
+ default:
+ case 0: return v1;
+ case 1: return v2;
+ case 2: return v3;
+ }
+}
-template<class REAL_AI>
-inline CreatureAI*
-CreatureAIFactory<REAL_AI>::Create(void *data) const
+template<class T>
+inline
+const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4)
{
- Creature* creature = reinterpret_cast<Creature *>(data);
- return (new REAL_AI(creature));
+ switch(rand()%4)
+ {
+ default:
+ case 0: return v1;
+ case 1: return v2;
+ case 2: return v3;
+ case 3: return v4;
+ }
}
+
+template<class T>
+inline
+const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5)
+{
+ switch(rand()%4)
+ {
+ default:
+ case 0: return v1;
+ case 1: return v2;
+ case 2: return v3;
+ case 3: return v4;
+ case 4: return v5;
+ }
+}
+
+class EventMap : private std::map<uint32, uint32>
+{
+ private:
+ uint32 m_time, m_phase;
+ public:
+ explicit EventMap() : m_phase(0), m_time(0) {}
+
+ uint32 GetTimer() const { return m_time; }
+
+ void Reset() { clear(); m_time = 0; m_phase = 0; }
+
+ void Update(uint32 time) { m_time += time; }
+
+ void SetPhase(uint32 phase)
+ {
+ if(phase && phase < 9)
+ m_phase = (1 << (phase + 24));
+ }
+
+ void ScheduleEvent(uint32 eventId, uint32 time, uint32 gcd = 0, uint32 phase = 0)
+ {
+ time += m_time;
+ if(gcd && gcd < 9)
+ eventId |= (1 << (gcd + 16));
+ if(phase && phase < 9)
+ eventId |= (1 << (phase + 24));
+ iterator itr = find(time);
+ while(itr != end())
+ {
+ ++time;
+ itr = find(time);
+ }
+ insert(std::make_pair(time, eventId));
+ }
+
+ uint32 ExecuteEvent()
+ {
+ while(!empty())
+ {
+ if(begin()->first > m_time)
+ return 0;
+ else if(m_phase && (begin()->second & 0xFF000000) && !(begin()->second & m_phase))
+ erase(begin());
+ else
+ {
+ uint32 eventId = (begin()->second & 0x0000FFFF);
+ erase(begin());
+ return eventId;
+ }
+ }
+ return 0;
+ }
+
+ void DelayEvents(uint32 time, uint32 gcd)
+ {
+ time += m_time;
+ gcd = (1 << (gcd + 16));
+ for(iterator itr = begin(); itr != end();)
+ {
+ if(itr->first >= time)
+ break;
+ if(itr->second & gcd)
+ {
+ ScheduleEvent(time, itr->second);
+ erase(itr++);
+ }
+ else
+ ++itr;
+ }
+ }
+};
+
+enum AITarget
+{
+ AITARGET_SELF,
+ AITARGET_VICTIM,
+ AITARGET_ENEMY,
+ AITARGET_ALLY,
+ AITARGET_BUFF,
+ AITARGET_DEBUFF,
+};
+
+enum AICondition
+{
+ AICOND_AGGRO,
+ AICOND_COMBAT,
+ AICOND_DIE,
+};
+
+#define AI_DEFAULT_COOLDOWN 5000
+
+struct AISpellInfoType
+{
+ AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT), cooldown(AI_DEFAULT_COOLDOWN) {}
+ AITarget target;
+ AICondition condition;
+ uint32 cooldown;
+};
+
+TRINITY_DLL_SPEC AISpellInfoType * GetAISpellInfo(uint32 i);
+
#endif
diff --git a/src/game/CreatureAIRegistry.cpp b/src/game/CreatureAIRegistry.cpp
index 2ac73da702b..162ebd9b47c 100644
--- a/src/game/CreatureAIRegistry.cpp
+++ b/src/game/CreatureAIRegistry.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,22 +18,21 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "CreatureAIRegistry.h"
#include "NullCreatureAI.h"
#include "ReactorAI.h"
#include "AggressorAI.h"
#include "GuardAI.h"
#include "PetAI.h"
-#include "PossessedAI.h"
#include "TotemAI.h"
#include "OutdoorPvPObjectiveAI.h"
+#include "CreatureEventAI.h"
#include "RandomMovementGenerator.h"
-#include "CreatureAIImpl.h"
#include "MovementGeneratorImpl.h"
-#include "MapManager.h"
#include "CreatureAIRegistry.h"
#include "WaypointMovementGenerator.h"
+#include "CreatureAIFactory.h"
+#include "CreatureAIImpl.h"
namespace AIRegistry
{
void Initialize()
@@ -47,7 +46,8 @@ namespace AIRegistry
(new CreatureAIFactory<PetAI>("PetAI"))->RegisterSelf();
(new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf();
(new CreatureAIFactory<OutdoorPvPObjectiveAI>("OutdoorPvPObjectiveAI"))->RegisterSelf();
- (new CreatureAIFactory<PossessedAI>("PossessedAI"))->RegisterSelf();
+ (new CreatureAIFactory<SpellAI>("SpellAI"))->RegisterSelf();
+ (new CreatureAIFactory<CreatureEventAI>("EventAI"))->RegisterSelf();
(new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf();
(new MovementGeneratorFactory<WaypointMovementGenerator<Creature> >(WAYPOINT_MOTION_TYPE))->RegisterSelf();
diff --git a/src/game/CreatureAIRegistry.h b/src/game/CreatureAIRegistry.h
index b4155403e9b..2b92a096731 100644
--- a/src/game/CreatureAIRegistry.h
+++ b/src/game/CreatureAIRegistry.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp
index a2f3d39fcc7..f950e9f508c 100644
--- a/src/game/CreatureAISelector.cpp
+++ b/src/game/CreatureAISelector.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,13 +19,14 @@
*/
#include "Creature.h"
-#include "CreatureAIImpl.h"
#include "CreatureAISelector.h"
#include "NullCreatureAI.h"
#include "Policies/SingletonImp.h"
#include "MovementGenerator.h"
#include "ScriptCalls.h"
#include "Pet.h"
+#include "TemporarySummon.h"
+#include "CreatureAIFactory.h"
INSTANTIATE_SINGLETON_1(CreatureAIRegistry);
INSTANTIATE_SINGLETON_1(MovementGeneratorRegistry);
@@ -34,32 +35,31 @@ namespace FactorySelector
{
CreatureAI* selectAI(Creature *creature)
{
- //if(creature->isPossessed())
- // creature->InitPossessedAI();
-
- // Allow scripting AI for normal creatures and not controlled pets (guardians and mini-pets)
- if((!creature->isPet() || !((Pet*)creature)->isControlled()) && !creature->isCharmed())
- if(CreatureAI* scriptedAI = Script->GetAI(creature))
- return scriptedAI;
-
+ const CreatureAICreator *ai_factory = NULL;
CreatureAIRegistry &ai_registry(CreatureAIRepository::Instance());
- assert( creature->GetCreatureInfo() != NULL );
- CreatureInfo const *cinfo=creature->GetCreatureInfo();
- const CreatureAICreator *ai_factory = NULL;
+ //player-controlled guardians with pet bar
+ if(creature->HasSummonMask(SUMMON_MASK_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER)
+ ai_factory = ai_registry.GetRegistryItem("PetAI");
- std::string ainame=cinfo->AIName;
+ //scriptname in db
+ if(!ai_factory)
+ if(CreatureAI* scriptedAI = Script->GetAI(creature))
+ return scriptedAI;
- // select by script name
- if( !ainame.empty())
+ // AIname in db
+ std::string ainame=creature->GetAIName();
+ if(!ai_factory && !ainame.empty())
ai_factory = ai_registry.GetRegistryItem( ainame.c_str() );
// select by NPC flags
if(!ai_factory)
{
- if( creature->isGuard() )
+ if(creature->isVehicle() || creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK))
+ ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
+ else if(creature->isGuard())
ai_factory = ai_registry.GetRegistryItem("GuardAI");
- else if(creature->isPet() || (creature->isCharmed() && !creature->isPossessed()))
+ else if(creature->HasSummonMask(SUMMON_MASK_GUARDIAN))
ai_factory = ai_registry.GetRegistryItem("PetAI");
else if(creature->isTotem())
ai_factory = ai_registry.GetRegistryItem("TotemAI");
@@ -69,6 +69,18 @@ namespace FactorySelector
ai_factory = ai_registry.GetRegistryItem("CritterAI");
}
+ if(!ai_factory)
+ {
+ for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
+ {
+ if(creature->m_spells[i])
+ {
+ ai_factory = ai_registry.GetRegistryItem("SpellAI");
+ break;
+ }
+ }
+ }
+
// select by permit check
if(!ai_factory)
{
diff --git a/src/game/CreatureAISelector.h b/src/game/CreatureAISelector.h
index c7b4e541f3c..436233b5b21 100644
--- a/src/game/CreatureAISelector.h
+++ b/src/game/CreatureAISelector.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp
new file mode 100644
index 00000000000..c2ae915c9a4
--- /dev/null
+++ b/src/game/CreatureEventAI.cpp
@@ -0,0 +1,1365 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Common.h"
+#include "CreatureEventAI.h"
+#include "CreatureEventAIMgr.h"
+#include "ObjectMgr.h"
+#include "Spell.h"
+#include "World.h"
+#include "Cell.h"
+#include "CellImpl.h"
+#include "GameEventMgr.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
+#include "WorldPacket.h"
+#include "InstanceData.h"
+
+namespace MaNGOS
+{
+ class CallOfHelpCreatureInRangeDo // do attack at call of help to friendly crearture
+ {
+ public:
+ CallOfHelpCreatureInRangeDo(Unit* funit, Unit* enemy, float range)
+ : i_funit(funit), i_enemy(enemy), i_range(range)
+ {}
+ void operator()(Creature* u)
+ {
+ if (u == i_funit)
+ return;
+
+ if (!u->CanAssistTo(i_funit, i_enemy, false))
+ return;
+
+ // too far
+ if( !i_funit->IsWithinDistInMap(u, i_range) )
+ return;
+
+ // only if see assisted creature
+ if( !i_funit->IsWithinLOSInMap(u) )
+ return;
+
+ if(u->AI())
+ u->AI()->AttackStart(i_enemy);
+ }
+ private:
+ Unit* const i_funit;
+ Unit* const i_enemy;
+ float i_range;
+ };
+}
+
+bool CreatureEventAIHolder::UpdateRepeatTimer( Creature* creature, uint32 repeatMin, uint32 repeatMax )
+{
+ if (repeatMin == repeatMax)
+ Time = repeatMin;
+ else if (repeatMax > repeatMin)
+ Time = urand(repeatMin, repeatMax);
+ else
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", creature->GetEntry(), Event.event_id, Event.event_type);
+ Enabled = false;
+ return false;
+ }
+
+ return true;
+}
+
+int CreatureEventAI::Permissible(const Creature *creature)
+{
+ if( creature->GetAIName() == "EventAI" )
+ return PERMIT_BASE_SPECIAL;
+ return PERMIT_BASE_NO;
+}
+
+CreatureEventAI::CreatureEventAI(Creature *c ) : CreatureAI(c)
+{
+ // Need make copy for filter unneeded steps and safe in case table reload
+ CreatureEventAI_Event_Map::const_iterator CreatureEvents = CreatureEAI_Mgr.GetCreatureEventAIMap().find(m_creature->GetEntry());
+ if (CreatureEvents != CreatureEAI_Mgr.GetCreatureEventAIMap().end())
+ {
+ std::vector<CreatureEventAI_Event>::const_iterator i;
+ for (i = (*CreatureEvents).second.begin(); i != (*CreatureEvents).second.end(); ++i)
+ {
+
+ //Debug check
+ #ifndef TRINITY_DEBUG
+ if ((*i).event_flags & EFLAG_DEBUG_ONLY)
+ continue;
+ #endif
+ if(((*i).event_flags & (EFLAG_HEROIC | EFLAG_NORMAL)) && m_creature->GetMap()->IsDungeon() )
+ {
+ if( (m_creature->GetMap()->IsHeroic() && (*i).event_flags & EFLAG_HEROIC) ||
+ (!m_creature->GetMap()->IsHeroic() && (*i).event_flags & EFLAG_NORMAL))
+ {
+ //event flagged for instance mode
+ CreatureEventAIList.push_back(CreatureEventAIHolder(*i));
+ }
+ continue;
+ }
+ CreatureEventAIList.push_back(CreatureEventAIHolder(*i));
+ }
+ //EventMap had events but they were not added because they must be for instance
+ if (CreatureEventAIList.empty())
+ sLog.outError("CreatureEventAI: Creature %u has events but no events added to list because of instance flags.", m_creature->GetEntry());
+ }
+ else
+ sLog.outError("CreatureEventAI: EventMap for Creature %u is empty but creature is using CreatureEventAI.", m_creature->GetEntry());
+
+ bEmptyList = CreatureEventAIList.empty();
+ Phase = 0;
+ CombatMovementEnabled = true;
+ MeleeEnabled = true;
+ AttackDistance = 0;
+ AttackAngle = 0.0f;
+
+ //Handle Spawned Events
+ if (!bEmptyList)
+ {
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ if (SpawnedEventConditionsCheck((*i).Event))
+ ProcessEvent(*i);
+ }
+}
+
+bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker)
+{
+ if (!pHolder.Enabled || pHolder.Time)
+ return false;
+
+ //Check the inverse phase mask (event doesn't trigger if current phase bit is set in mask)
+ if (pHolder.Event.event_inverse_phase_mask & (1 << Phase))
+ return false;
+
+ //Store random here so that all random actions match up
+ uint32 rnd = rand();
+
+ //Return if chance for event is not met
+ if (pHolder.Event.event_chance <= rnd % 100)
+ return false;
+
+ CreatureEventAI_Event const& event = pHolder.Event;
+
+ //Check event conditions based on the event type, also reset events
+ switch (event.event_type)
+ {
+ case EVENT_T_TIMER:
+ if (!m_creature->isInCombat())
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.timer.repeatMin,event.timer.repeatMax);
+ break;
+ case EVENT_T_TIMER_OOC:
+ if (m_creature->isInCombat())
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.timer.repeatMin,event.timer.repeatMax);
+ break;
+ case EVENT_T_HP:
+ {
+ if (!m_creature->isInCombat() || !m_creature->GetMaxHealth())
+ return false;
+
+ uint32 perc = (m_creature->GetHealth()*100) / m_creature->GetMaxHealth();
+
+ if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.percent_range.repeatMin,event.percent_range.repeatMax);
+ break;
+ }
+ case EVENT_T_MANA:
+ {
+ if (!m_creature->isInCombat() || !m_creature->GetMaxPower(POWER_MANA))
+ return false;
+
+ uint32 perc = (m_creature->GetPower(POWER_MANA)*100) / m_creature->GetMaxPower(POWER_MANA);
+
+ if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.percent_range.repeatMin,event.percent_range.repeatMax);
+ break;
+ }
+ case EVENT_T_AGGRO:
+ break;
+ case EVENT_T_KILL:
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.kill.repeatMin,event.kill.repeatMax);
+ break;
+ case EVENT_T_DEATH:
+ case EVENT_T_EVADE:
+ break;
+ case EVENT_T_SPELLHIT:
+ //Spell hit is special case, param1 and param2 handled within CreatureEventAI::SpellHit
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.spell_hit.repeatMin,event.spell_hit.repeatMax);
+ break;
+ case EVENT_T_RANGE:
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.range.repeatMin,event.range.repeatMax);
+ break;
+ case EVENT_T_OOC_LOS:
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.ooc_los.repeatMin,event.ooc_los.repeatMax);
+ break;
+ case EVENT_T_SPAWNED:
+ break;
+ case EVENT_T_TARGET_HP:
+ {
+ if (!m_creature->isInCombat() || !m_creature->getVictim() || !m_creature->getVictim()->GetMaxHealth())
+ return false;
+
+ uint32 perc = (m_creature->getVictim()->GetHealth()*100) / m_creature->getVictim()->GetMaxHealth();
+
+ if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.percent_range.repeatMin,event.percent_range.repeatMax);
+ break;
+ }
+ case EVENT_T_TARGET_CASTING:
+ if (!m_creature->isInCombat() || !m_creature->getVictim() || !m_creature->getVictim()->IsNonMeleeSpellCasted(false, false, true))
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.target_casting.repeatMin,event.target_casting.repeatMax);
+ break;
+ case EVENT_T_FRIENDLY_HP:
+ {
+ if (!m_creature->isInCombat())
+ return false;
+
+ Unit* pUnit = DoSelectLowestHpFriendly(event.friendly_hp.radius, event.friendly_hp.hpDeficit);
+ if (!pUnit)
+ return false;
+
+ pActionInvoker = pUnit;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.friendly_hp.repeatMin,event.friendly_hp.repeatMax);
+ break;
+ }
+ case EVENT_T_FRIENDLY_IS_CC:
+ {
+ if (!m_creature->isInCombat())
+ return false;
+
+ std::list<Creature*> pList;
+ DoFindFriendlyCC(pList, event.friendly_is_cc.radius);
+
+ //List is empty
+ if (pList.empty())
+ return false;
+
+ //We don't really care about the whole list, just return first available
+ pActionInvoker = *(pList.begin());
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.friendly_is_cc.repeatMin,event.friendly_is_cc.repeatMax);
+ break;
+ }
+ case EVENT_T_FRIENDLY_MISSING_BUFF:
+ {
+ std::list<Creature*> pList;
+ DoFindFriendlyMissingBuff(pList, event.friendly_buff.radius, event.friendly_buff.spellId);
+
+ //List is empty
+ if (pList.empty())
+ return false;
+
+ //We don't really care about the whole list, just return first available
+ pActionInvoker = *(pList.begin());
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.friendly_buff.repeatMin,event.friendly_buff.repeatMax);
+ break;
+ }
+ case EVENT_T_SUMMONED_UNIT:
+ {
+ //Prevent event from occuring on no unit or non creatures
+ if (!pActionInvoker || pActionInvoker->GetTypeId()!=TYPEID_UNIT)
+ return false;
+
+ //Creature id doesn't match up
+ if (((Creature*)pActionInvoker)->GetEntry() != event.summon_unit.creatureId)
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.summon_unit.repeatMin,event.summon_unit.repeatMax);
+ }
+ break;
+ case EVENT_T_TARGET_MANA:
+ {
+ if (!m_creature->isInCombat() || !m_creature->getVictim() || !m_creature->getVictim()->GetMaxPower(POWER_MANA))
+ return false;
+
+ uint32 perc = (m_creature->getVictim()->GetPower(POWER_MANA)*100) / m_creature->getVictim()->GetMaxPower(POWER_MANA);
+
+ if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.percent_range.repeatMin,event.percent_range.repeatMax);
+ break;
+ }
+ case EVENT_T_REACHED_HOME:
+ case EVENT_T_RECEIVE_EMOTE:
+ break;
+ default:
+ sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type);
+ break;
+ }
+
+ //Disable non-repeatable events
+ if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE))
+ pHolder.Enabled = false;
+
+ //Process actions
+ for (uint32 j = 0; j < MAX_ACTIONS; j++)
+ ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker);
+
+ return true;
+}
+
+void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker)
+{
+ switch (action.type)
+ {
+ case ACTION_T_TEXT:
+ {
+ if (!action.text.TextId1)
+ return;
+
+ int32 temp = 0;
+
+ if (action.text.TextId2 && action.text.TextId3)
+ {
+ switch( rand()%3 )
+ {
+ case 0: temp = action.text.TextId1; break;
+ case 1: temp = action.text.TextId2; break;
+ case 2: temp = action.text.TextId3; break;
+ }
+ }
+ else if (action.text.TextId2 && urand(0,1))
+ temp = action.text.TextId2;
+ else
+ temp = action.text.TextId1;
+
+ if (temp)
+ {
+ Unit* target = NULL;
+
+ if (pActionInvoker)
+ {
+ if (pActionInvoker->GetTypeId() == TYPEID_PLAYER)
+ target = pActionInvoker;
+ else if (Unit* owner = pActionInvoker->GetOwner())
+ {
+ if (owner->GetTypeId() == TYPEID_PLAYER)
+ target = owner;
+ }
+ }
+ else if (target = m_creature->getVictim())
+ {
+ if (target->GetTypeId() != TYPEID_PLAYER)
+ if (Unit* owner = target->GetOwner())
+ if (owner->GetTypeId() == TYPEID_PLAYER)
+ target = owner;
+ }
+
+ DoScriptText(temp, m_creature, target);
+ }
+ break;
+ }
+ case ACTION_T_SET_FACTION:
+ {
+ if (action.set_faction.factionId)
+ m_creature->setFaction(action.set_faction.factionId);
+ else
+ {
+ if (CreatureInfo const* ci = GetCreatureTemplateStore(m_creature->GetEntry()))
+ {
+ //if no id provided, assume reset and then use default
+ if (m_creature->getFaction() != ci->faction_A)
+ m_creature->setFaction(ci->faction_A);
+ }
+ }
+ break;
+ }
+ case ACTION_T_MORPH_TO_ENTRY_OR_MODEL:
+ {
+ if (action.morph.creatireId || action.morph.modelId)
+ {
+ //set model based on entry from creature_template
+ if (action.morph.creatireId)
+ {
+ if (CreatureInfo const* ci = GetCreatureTemplateStore(action.morph.creatireId))
+ {
+ //use default display
+ if (ci->Modelid_A1)
+ m_creature->SetDisplayId(ci->Modelid_A1);
+ }
+ }
+ //if no param1, then use value from param2 (modelId)
+ else
+ m_creature->SetDisplayId(action.morph.modelId);
+ }
+ else
+ m_creature->DeMorph();
+ break;
+ }
+ case ACTION_T_SOUND:
+ m_creature->PlayDirectSound(action.sound.soundId);
+ break;
+ case ACTION_T_EMOTE:
+ m_creature->HandleEmoteCommand(action.emote.emoteId);
+ break;
+ case ACTION_T_RANDOM_SOUND:
+ {
+ int32 temp = GetRandActionParam(rnd, action.random_sound.soundId1, action.random_sound.soundId2, action.random_sound.soundId3);
+ if (temp >= 0)
+ m_creature->PlayDirectSound(temp);
+ break;
+ }
+ case ACTION_T_RANDOM_EMOTE:
+ {
+ int32 temp = GetRandActionParam(rnd, action.random_emote.emoteId1, action.random_emote.emoteId2, action.random_emote.emoteId3);
+ if (temp >= 0)
+ m_creature->HandleEmoteCommand(temp);
+ break;
+ }
+ case ACTION_T_CAST:
+ {
+ Unit* target = GetTargetByType(action.cast.target, pActionInvoker);
+ Unit* caster = m_creature;
+
+ if (!target)
+ return;
+
+ if (action.cast.castFlags & CAST_FORCE_TARGET_SELF)
+ caster = target;
+
+ //Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered
+ bool canCast = !caster->IsNonMeleeSpellCasted(false) || (action.cast.castFlags & (CAST_TRIGGERED | CAST_INTURRUPT_PREVIOUS));
+
+ // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them
+ if(action.cast.castFlags & CAST_AURA_NOT_PRESENT)
+ {
+ if(target->HasAura(action.cast.spellId))
+ return;
+ }
+
+ if (canCast)
+ {
+ const SpellEntry* tSpell = GetSpellStore()->LookupEntry(action.cast.spellId);
+
+ //Verify that spell exists
+ if (tSpell)
+ {
+ //Check if cannot cast spell
+ if (!(action.cast.castFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST)) &&
+ !CanCast(target, tSpell, (action.cast.castFlags & CAST_TRIGGERED)))
+ {
+ //Melee current victim if flag not set
+ if (!(action.cast.castFlags & CAST_NO_MELEE_IF_OOM))
+ {
+ if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
+ {
+ AttackDistance = 0;
+ AttackAngle = 0;
+
+ m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle);
+ }
+ }
+
+ }
+ else
+ {
+ //Interrupt any previous spell
+ if (caster->IsNonMeleeSpellCasted(false) && action.cast.castFlags & CAST_INTURRUPT_PREVIOUS)
+ caster->InterruptNonMeleeSpells(false);
+
+ caster->CastSpell(target, action.cast.spellId, (action.cast.castFlags & CAST_TRIGGERED));
+ }
+
+ }
+ else
+ sLog.outErrorDb("CreatureEventAI: event %d creature %d attempt to cast spell that doesn't exist %d", EventId, m_creature->GetEntry(), action.cast.spellId);
+ }
+ break;
+ }
+ case ACTION_T_SUMMON:
+ {
+ Unit* target = GetTargetByType(action.summon.target, pActionInvoker);
+
+ Creature* pCreature = NULL;
+
+ if (action.summon.duration)
+ pCreature = m_creature->SummonCreature(action.summon.creatured, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, action.summon.duration);
+ else
+ pCreature = m_creature->SummonCreature(action.summon.creatured, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+
+ if (!pCreature)
+ sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. Spawn event %d is on creature %d", action.summon.creatured, EventId, m_creature->GetEntry());
+ else if (action.summon.target != TARGET_T_SELF && target)
+ pCreature->AI()->AttackStart(target);
+ break;
+ }
+ case ACTION_T_THREAT_SINGLE_PCT:
+ if (Unit* target = GetTargetByType(action.threat_single_pct.target, pActionInvoker))
+ m_creature->getThreatManager().modifyThreatPercent(target, action.threat_single_pct.percent);
+ break;
+ case ACTION_T_THREAT_ALL_PCT:
+ {
+ std::list<HostilReference*>& threatList = m_creature->getThreatManager().getThreatList();
+ for (std::list<HostilReference*>::iterator i = threatList.begin(); i != threatList.end(); ++i)
+ if(Unit* Temp = Unit::GetUnit(*m_creature,(*i)->getUnitGuid()))
+ m_creature->getThreatManager().modifyThreatPercent(Temp, action.threat_all_pct.percent);
+ break;
+ }
+ case ACTION_T_QUEST_EVENT:
+ if (Unit* target = GetTargetByType(action.quest_event.target, pActionInvoker))
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)target)->AreaExploredOrEventHappens(action.quest_event.questId);
+ break;
+ case ACTION_T_CAST_EVENT:
+ if (Unit* target = GetTargetByType(action.cast_event.target, pActionInvoker))
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)target)->CastedCreatureOrGO(action.cast_event.creatureId, m_creature->GetGUID(), action.cast_event.spellId);
+ break;
+ case ACTION_T_SET_UNIT_FIELD:
+ {
+ Unit* target = GetTargetByType(action.set_unit_field.target, pActionInvoker);
+
+ // not allow modify important for integrity object fields
+ if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END)
+ return;
+
+ if (target)
+ target->SetUInt32Value(action.set_unit_field.field, action.set_unit_field.value);
+
+ break;
+ }
+ case ACTION_T_SET_UNIT_FLAG:
+ if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker))
+ target->SetFlag(UNIT_FIELD_FLAGS, action.unit_flag.value);
+ break;
+ case ACTION_T_REMOVE_UNIT_FLAG:
+ if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker))
+ target->RemoveFlag(UNIT_FIELD_FLAGS, action.unit_flag.value);
+ break;
+ case ACTION_T_AUTO_ATTACK:
+ MeleeEnabled = action.auto_attack.state != 0;
+ break;
+ case ACTION_T_COMBAT_MOVEMENT:
+ CombatMovementEnabled = action.combat_movement.state != 0;
+
+ //Allow movement (create new targeted movement gen only if idle)
+ if (CombatMovementEnabled)
+ {
+ m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle);
+ }
+ else
+ {
+ m_creature->GetMotionMaster()->MoveIdle();
+ }
+ break;
+ case ACTION_T_SET_PHASE:
+ Phase = action.set_phase.phase;
+ break;
+ case ACTION_T_INC_PHASE:
+ {
+ int32 new_phase = int32(Phase)+action.set_inc_phase.step;
+ if (new_phase < 0)
+ {
+ sLog.outErrorDb( "CreatureEventAI: Event %d decrease Phase under 0. CreatureEntry = %d", EventId, m_creature->GetEntry());
+ Phase = 0;
+ }
+ else if (new_phase >= MAX_PHASE)
+ {
+ sLog.outErrorDb( "CreatureEventAI: Event %d incremented Phase above %u. Phase mask cannot be used with phases past %u. CreatureEntry = %d", EventId, MAX_PHASE-1, MAX_PHASE-1, m_creature->GetEntry());
+ Phase = MAX_PHASE-1;
+ }
+ else
+ Phase = new_phase;
+
+ break;
+ }
+ case ACTION_T_EVADE:
+ EnterEvadeMode();
+ break;
+ case ACTION_T_FLEE_FOR_ASSIST:
+ m_creature->DoFleeToGetAssistance();
+ break;
+ case ACTION_T_QUEST_EVENT_ALL:
+ if (pActionInvoker && pActionInvoker->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (Unit* Temp = Unit::GetUnit(*m_creature,pActionInvoker->GetGUID()))
+ if (Temp->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)Temp)->GroupEventHappens(action.quest_event_all.questId,m_creature);
+ }
+ break;
+ case ACTION_T_CAST_EVENT_ALL:
+ {
+ std::list<HostilReference*>& threatList = m_creature->getThreatManager().getThreatList();
+ for (std::list<HostilReference*>::iterator i = threatList.begin(); i != threatList.end(); ++i)
+ if (Unit* Temp = Unit::GetUnit(*m_creature,(*i)->getUnitGuid()))
+ if (Temp->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)Temp)->CastedCreatureOrGO(action.cast_event_all.creatureId, m_creature->GetGUID(), action.cast_event_all.spellId);
+ break;
+ }
+ case ACTION_T_REMOVEAURASFROMSPELL:
+ if (Unit* target = GetTargetByType(action.remove_aura.target, pActionInvoker))
+ target->RemoveAurasDueToSpell(action.remove_aura.spellId);
+ break;
+ case ACTION_T_RANGED_MOVEMENT:
+ AttackDistance = action.ranged_movement.distance;
+ AttackAngle = ((float)action.ranged_movement.angle/180)*M_PI;
+
+ if (CombatMovementEnabled)
+ {
+ m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle);
+ }
+ break;
+ case ACTION_T_RANDOM_PHASE:
+ Phase = GetRandActionParam(rnd, action.random_phase.phase1, action.random_phase.phase2, action.random_phase.phase3);
+ break;
+ case ACTION_T_RANDOM_PHASE_RANGE:
+ if (action.random_phase_range.phaseMax > action.random_phase_range.phaseMin)
+ Phase = action.random_phase_range.phaseMin + (rnd % (action.random_phase_range.phaseMax - action.random_phase_range.phaseMin));
+ else
+ sLog.outErrorDb( "CreatureEventAI: ACTION_T_RANDOM_PHASE_RANGE cannot have Param2 <= Param1. Divide by Zero. Event = %d. CreatureEntry = %d", EventId, m_creature->GetEntry());
+ break;
+ case ACTION_T_SUMMON_ID:
+ {
+ Unit* target = GetTargetByType(action.summon_id.target, pActionInvoker);
+
+ CreatureEventAI_Summon_Map::const_iterator i = CreatureEAI_Mgr.GetCreatureEventAISummonMap().find(action.summon_id.spawnId);
+ if (i == CreatureEAI_Mgr.GetCreatureEventAISummonMap().end())
+ {
+ sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", action.summon_id.creatureId, action.summon_id.spawnId, EventId, m_creature->GetEntry());
+ return;
+ }
+
+ Creature* pCreature = NULL;
+ if ((*i).second.SpawnTimeSecs)
+ pCreature = m_creature->SummonCreature(action.summon_id.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs);
+ else
+ pCreature = m_creature->SummonCreature(action.summon_id.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+
+ if (!pCreature)
+ sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. EventId %d.Creature %d", action.summon_id.creatureId, EventId, m_creature->GetEntry());
+ else if (action.summon_id.target != TARGET_T_SELF && target)
+ pCreature->AI()->AttackStart(target);
+
+ break;
+ }
+ case ACTION_T_KILLED_MONSTER:
+ //first attempt player who tapped creature
+ if (Player* pPlayer = m_creature->GetLootRecipient())
+ pPlayer->RewardPlayerAndGroupAtEvent(action.killed_monster.creatureId, m_creature);
+ else
+ {
+ //if not available, use pActionInvoker
+ if (Unit* pTarget = GetTargetByType(action.killed_monster.target, pActionInvoker))
+ if (Player* pPlayer2 = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself())
+ pPlayer2->RewardPlayerAndGroupAtEvent(action.killed_monster.creatureId, m_creature);
+ }
+ break;
+ case ACTION_T_SET_INST_DATA:
+ {
+ InstanceData* pInst = (InstanceData*)m_creature->GetInstanceData();
+ if (!pInst)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data without instance script. Creature %d", EventId, m_creature->GetEntry());
+ return;
+ }
+
+ pInst->SetData(action.set_inst_data.field, action.set_inst_data.value);
+ break;
+ }
+ case ACTION_T_SET_INST_DATA64:
+ {
+ Unit* target = GetTargetByType(action.set_inst_data64.target, pActionInvoker);
+ if (!target)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, m_creature->GetEntry());
+ return;
+ }
+
+ InstanceData* pInst = (InstanceData*)m_creature->GetInstanceData();
+ if (!pInst)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data64 without instance script. Creature %d", EventId, m_creature->GetEntry());
+ return;
+ }
+
+ pInst->SetData64(action.set_inst_data64.field, target->GetGUID());
+ break;
+ }
+ case ACTION_T_UPDATE_TEMPLATE:
+ if (m_creature->GetEntry() == action.update_template.creatureId)
+ {
+
+ sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_UPDATE_TEMPLATE call with param1 == current entry. Creature %d", EventId, m_creature->GetEntry());
+ return;
+ }
+
+ m_creature->UpdateEntry(action.update_template.creatureId, action.update_template.team ? HORDE : ALLIANCE);
+ break;
+ case ACTION_T_DIE:
+ if (m_creature->isDead())
+ {
+
+ sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_DIE on dead creature. Creature %d", EventId, m_creature->GetEntry());
+ return;
+ }
+ m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ break;
+ case ACTION_T_ZONE_COMBAT_PULSE:
+ if (!m_creature->isInCombat() || !m_creature->GetMap()->IsDungeon())
+ {
+
+ sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_ZONE_COMBAT_PULSE on creature out of combat or in non-dungeon map. Creature %d", EventId, m_creature->GetEntry());
+ return;
+ }
+
+ DoZoneInCombat(m_creature);
+ break;
+ case ACTION_T_CALL_FOR_HELP:
+ {
+ if (!m_creature->getVictim())
+ return;
+
+ CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::CallOfHelpCreatureInRangeDo u_do(m_creature, m_creature->getVictim(), action.call_for_help.radius);
+ MaNGOS::CreatureWorker<MaNGOS::CallOfHelpCreatureInRangeDo> worker(m_creature, u_do);
+
+ TypeContainerVisitor<MaNGOS::CreatureWorker<MaNGOS::CallOfHelpCreatureInRangeDo>, GridTypeMapContainer > grid_creature_searcher(worker);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap());
+ break;
+ }
+ break;
+
+ // TRINITY ONLY
+ case ACTION_T_SET_ACTIVE:
+ me->setActive(action.raw.param1 ? true : false);
+ break;
+ case ACTION_T_SET_AGGRESSIVE:
+ me->SetReactState(ReactStates(action.raw.param1));
+ break;
+ case ACTION_T_ATTACK_START_PULSE:
+ AttackStart(me->SelectNearestTarget((float)action.raw.param1));
+ break;
+ case ACTION_T_SUMMON_GO:
+ {
+ GameObject* pObject = NULL;
+
+ float x,y,z;
+ m_creature->GetPosition(x,y,z);
+ pObject = m_creature->SummonGameObject(action.raw.param1, x, y, z, 0, 0, 0, 0, 0, action.raw.param2);
+ if (!pObject)
+ {
+ sLog.outErrorDb("TSCR: EventAI failed to spawn object %u. Spawn event %d is on creature %d", action.raw.param1, EventId, m_creature->GetEntry());
+ }
+ break;
+ }
+ }
+}
+
+void CreatureEventAI::JustRespawned()
+{
+ Reset();
+
+ if (bEmptyList)
+ return;
+
+ //Handle Spawned Events
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ if (SpawnedEventConditionsCheck((*i).Event))
+ ProcessEvent(*i);
+}
+
+void CreatureEventAI::Reset()
+{
+ EventUpdateTime = EVENT_UPDATE_TIME;
+ EventDiff = 0;
+
+ if (bEmptyList)
+ return;
+
+ //Reset all events to enabled
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ {
+ CreatureEventAI_Event const& event = (*i).Event;
+ switch (event.event_type)
+ {
+ //Reset all out of combat timers
+ case EVENT_T_TIMER_OOC:
+ {
+ if ((*i).UpdateRepeatTimer(m_creature,event.timer.initialMin,event.timer.initialMax))
+ (*i).Enabled = true;
+ break;
+ }
+ //default:
+ //TODO: enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void EnterCombat()
+ //(*i).Enabled = true;
+ //(*i).Time = 0;
+ //break;
+ }
+ }
+}
+
+void CreatureEventAI::JustReachedHome()
+{
+ m_creature->LoadCreaturesAddon();
+
+ if (!bEmptyList)
+ {
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ {
+ if ((*i).Event.event_type == EVENT_T_REACHED_HOME)
+ ProcessEvent(*i);
+ }
+ }
+
+ Reset();
+}
+
+void CreatureEventAI::EnterEvadeMode()
+{
+ CreatureAI::EnterEvadeMode();
+
+ if (bEmptyList)
+ return;
+
+ //Handle Evade events
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ {
+ if ((*i).Event.event_type == EVENT_T_EVADE)
+ ProcessEvent(*i);
+ }
+}
+
+void CreatureEventAI::JustDied(Unit* killer)
+{
+ Reset();
+
+ if (bEmptyList)
+ return;
+
+ //Handle Evade events
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ {
+ if ((*i).Event.event_type == EVENT_T_DEATH)
+ ProcessEvent(*i, killer);
+ }
+}
+
+void CreatureEventAI::KilledUnit(Unit* victim)
+{
+ if (bEmptyList || victim->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ {
+ if ((*i).Event.event_type == EVENT_T_KILL)
+ ProcessEvent(*i, victim);
+ }
+}
+
+void CreatureEventAI::JustSummoned(Creature* pUnit)
+{
+ if (bEmptyList || !pUnit)
+ return;
+
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ {
+ if ((*i).Event.event_type == EVENT_T_SUMMONED_UNIT)
+ ProcessEvent(*i, pUnit);
+ }
+}
+
+void CreatureEventAI::EnterCombat(Unit *enemy)
+{
+ //Check for on combat start events
+ if (!bEmptyList)
+ {
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ {
+ CreatureEventAI_Event const& event = (*i).Event;
+ switch (event.event_type)
+ {
+ case EVENT_T_AGGRO:
+ (*i).Enabled = true;
+ ProcessEvent(*i, enemy);
+ break;
+ //Reset all in combat timers
+ case EVENT_T_TIMER:
+ if ((*i).UpdateRepeatTimer(m_creature,event.timer.initialMin,event.timer.initialMax))
+ (*i).Enabled = true;
+ break;
+ //All normal events need to be re-enabled and their time set to 0
+ default:
+ (*i).Enabled = true;
+ (*i).Time = 0;
+ break;
+ }
+ }
+ }
+
+ EventUpdateTime = EVENT_UPDATE_TIME;
+ EventDiff = 0;
+}
+
+void CreatureEventAI::AttackStart(Unit *who)
+{
+ if (!who)
+ return;
+
+ if (m_creature->Attack(who, MeleeEnabled))
+ {
+ if (CombatMovementEnabled)
+ {
+ m_creature->GetMotionMaster()->MoveChase(who, AttackDistance, AttackAngle);
+ }
+ else
+ {
+ m_creature->GetMotionMaster()->MoveIdle();
+ }
+ }
+}
+
+void CreatureEventAI::MoveInLineOfSight(Unit *who)
+{
+ if(me->getVictim())
+ return;
+
+ //Check for OOC LOS Event
+ if (!bEmptyList)
+ {
+ for (std::list<CreatureEventAIHolder>::iterator itr = CreatureEventAIList.begin(); itr != CreatureEventAIList.end(); ++itr)
+ {
+ if ((*itr).Event.event_type == EVENT_T_OOC_LOS)
+ {
+ //can trigger if closer than fMaxAllowedRange
+ float fMaxAllowedRange = (*itr).Event.ooc_los.maxRange;
+
+ //if range is ok and we are actually in LOS
+ if (m_creature->IsWithinDistInMap(who, fMaxAllowedRange) && m_creature->IsWithinLOSInMap(who))
+ {
+ //if friendly event&&who is not hostile OR hostile event&&who is hostile
+ if (((*itr).Event.ooc_los.noHostile && !m_creature->IsHostileTo(who)) ||
+ ((!(*itr).Event.ooc_los.noHostile) && m_creature->IsHostileTo(who)))
+ ProcessEvent(*itr, who);
+ }
+ }
+ }
+ }
+
+ //if (m_creature->isCivilian() && m_creature->IsNeutralToAll())
+ // return;
+
+ if(me->canStartAttack(who))
+ AttackStart(who);
+}
+
+void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell)
+{
+
+ if (bEmptyList)
+ return;
+
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ if ((*i).Event.event_type == EVENT_T_SPELLHIT)
+ //If spell id matches (or no spell id) & if spell school matches (or no spell school)
+ if (!(*i).Event.spell_hit.spellId || pSpell->Id == (*i).Event.spell_hit.spellId)
+ if (pSpell->SchoolMask & (*i).Event.spell_hit.schoolMask)
+ ProcessEvent(*i, pUnit);
+}
+
+void CreatureEventAI::UpdateAI(const uint32 diff)
+{
+ //Check if we are in combat (also updates calls threat update code)
+ bool Combat = UpdateVictim();
+
+ if (!bEmptyList)
+ {
+ //Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events
+ if (EventUpdateTime < diff)
+ {
+ EventDiff += diff;
+
+ //Check for time based events
+ for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
+ {
+ //Decrement Timers
+ if ((*i).Time)
+ {
+ if ((*i).Time > EventDiff)
+ {
+ //Do not decrement timers if event cannot trigger in this phase
+ if (!((*i).Event.event_inverse_phase_mask & (1 << Phase)))
+ (*i).Time -= EventDiff;
+
+ //Skip processing of events that have time remaining
+ continue;
+ }
+ else (*i).Time = 0;
+ }
+
+ //Events that are updated every EVENT_UPDATE_TIME
+ switch ((*i).Event.event_type)
+ {
+ case EVENT_T_TIMER_OOC:
+ ProcessEvent(*i);
+ break;
+ case EVENT_T_TIMER:
+ case EVENT_T_MANA:
+ case EVENT_T_HP:
+ case EVENT_T_TARGET_HP:
+ case EVENT_T_TARGET_CASTING:
+ case EVENT_T_FRIENDLY_HP:
+ if (me->getVictim())
+ ProcessEvent(*i);
+ break;
+ case EVENT_T_RANGE:
+ if (me->getVictim())
+ if (m_creature->IsInMap(m_creature->getVictim()))
+ if (m_creature->IsInRange(m_creature->getVictim(),(float)(*i).Event.range.minDist,(float)(*i).Event.range.maxDist))
+ ProcessEvent(*i);
+ break;
+ }
+ }
+
+ EventDiff = 0;
+ EventUpdateTime = EVENT_UPDATE_TIME;
+ }
+ else
+ {
+ EventDiff += diff;
+ EventUpdateTime -= diff;
+ }
+ }
+
+ //Melee Auto-Attack
+ if (Combat && MeleeEnabled)
+ DoMeleeAttackIfReady();
+}
+
+inline Unit* CreatureEventAI::SelectUnit(AttackingTarget target, uint32 position)
+{
+ //ThreatList m_threatlist;
+ std::list<HostilReference*>& m_threatlist = m_creature->getThreatManager().getThreatList();
+ std::list<HostilReference*>::iterator i = m_threatlist.begin();
+ std::list<HostilReference*>::reverse_iterator r = m_threatlist.rbegin();
+
+ if (position >= m_threatlist.size() || !m_threatlist.size())
+ return NULL;
+
+ switch (target)
+ {
+ case ATTACKING_TARGET_RANDOM:
+ {
+ advance ( i , position + (rand() % (m_threatlist.size() - position ) ));
+ return Unit::GetUnit(*m_creature,(*i)->getUnitGuid());
+ }
+ case ATTACKING_TARGET_TOPAGGRO:
+ {
+ advance ( i , position);
+ return Unit::GetUnit(*m_creature,(*i)->getUnitGuid());
+ }
+ case ATTACKING_TARGET_BOTTOMAGGRO:
+ {
+ advance ( r , position);
+ return Unit::GetUnit(*m_creature,(*r)->getUnitGuid());
+ }
+ }
+ return NULL;
+}
+
+inline uint32 CreatureEventAI::GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3)
+{
+ switch (rnd % 3)
+ {
+ case 0: return param1;
+ case 1: return param2;
+ case 2: return param3;
+ }
+ return 0;
+}
+
+inline int32 CreatureEventAI::GetRandActionParam(uint32 rnd, int32 param1, int32 param2, int32 param3)
+{
+ switch (rnd % 3)
+ {
+ case 0: return param1;
+ case 1: return param2;
+ case 2: return param3;
+ }
+ return 0;
+}
+
+inline Unit* CreatureEventAI::GetTargetByType(uint32 Target, Unit* pActionInvoker)
+{
+ switch (Target)
+ {
+ case TARGET_T_SELF:
+ return m_creature;
+ case TARGET_T_HOSTILE:
+ return m_creature->getVictim();
+ case TARGET_T_HOSTILE_SECOND_AGGRO:
+ return SelectUnit(ATTACKING_TARGET_TOPAGGRO,1);
+ case TARGET_T_HOSTILE_LAST_AGGRO:
+ return SelectUnit(ATTACKING_TARGET_BOTTOMAGGRO,0);
+ case TARGET_T_HOSTILE_RANDOM:
+ return SelectUnit(ATTACKING_TARGET_RANDOM,0);
+ case TARGET_T_HOSTILE_RANDOM_NOT_TOP:
+ return SelectUnit(ATTACKING_TARGET_RANDOM,1);
+ case TARGET_T_ACTION_INVOKER:
+ return pActionInvoker;
+ default:
+ return NULL;
+ };
+}
+
+Unit* CreatureEventAI::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff)
+{
+ CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ Unit* pUnit = NULL;
+
+ MaNGOS::MostHPMissingInRange u_check(m_creature, range, MinHPDiff);
+ MaNGOS::UnitLastSearcher<MaNGOS::MostHPMissingInRange> searcher(m_creature, pUnit, u_check);
+
+ /*
+ typedef TYPELIST_4(GameObject, Creature*except pets*, DynamicObject, Corpse*Bones*) AllGridObjectTypes;
+ This means that if we only search grid then we cannot possibly return pets or players so this is safe
+ */
+ TypeContainerVisitor<MaNGOS::UnitLastSearcher<MaNGOS::MostHPMissingInRange>, GridTypeMapContainer > grid_unit_searcher(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_unit_searcher, *m_creature->GetMap());
+ return pUnit;
+}
+
+void CreatureEventAI::DoFindFriendlyCC(std::list<Creature*>& _list, float range)
+{
+ CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::FriendlyCCedInRange u_check(m_creature, range);
+ MaNGOS::CreatureListSearcher<MaNGOS::FriendlyCCedInRange> searcher(m_creature, _list, u_check);
+
+ TypeContainerVisitor<MaNGOS::CreatureListSearcher<MaNGOS::FriendlyCCedInRange>, GridTypeMapContainer > grid_creature_searcher(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap());
+}
+
+void CreatureEventAI::DoFindFriendlyMissingBuff(std::list<Creature*>& _list, float range, uint32 spellid)
+{
+ CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::FriendlyMissingBuffInRange u_check(m_creature, range, spellid);
+ MaNGOS::CreatureListSearcher<MaNGOS::FriendlyMissingBuffInRange> searcher(m_creature, _list, u_check);
+
+ TypeContainerVisitor<MaNGOS::CreatureListSearcher<MaNGOS::FriendlyMissingBuffInRange>, GridTypeMapContainer > grid_creature_searcher(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap());
+}
+
+//*********************************
+//*** Functions used globally ***
+
+void CreatureEventAI::DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target)
+{
+ if (!pSource)
+ {
+ sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i, invalid Source pointer.",textEntry);
+ return;
+ }
+
+ if (textEntry >= 0)
+ {
+ sLog.outErrorDb("CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.",pSource->GetEntry(),pSource->GetTypeId(),pSource->GetGUIDLow(),textEntry);
+ return;
+ }
+
+ CreatureEventAI_TextMap::const_iterator i = CreatureEAI_Mgr.GetCreatureEventAITextMap().find(textEntry);
+
+ if (i == CreatureEAI_Mgr.GetCreatureEventAITextMap().end())
+ {
+ sLog.outErrorDb("CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.",pSource->GetEntry(),pSource->GetTypeId(),pSource->GetGUIDLow(),textEntry);
+ return;
+ }
+
+ sLog.outDebug("CreatureEventAI: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u",textEntry,(*i).second.SoundId,(*i).second.Type,(*i).second.Language,(*i).second.Emote);
+
+ if((*i).second.SoundId)
+ {
+ if (GetSoundEntriesStore()->LookupEntry((*i).second.SoundId))
+ pSource->PlayDirectSound((*i).second.SoundId);
+ else
+ sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i tried to process invalid sound id %u.",textEntry,(*i).second.SoundId);
+ }
+
+ if((*i).second.Emote)
+ {
+ if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Unit*)pSource)->HandleEmoteCommand((*i).second.Emote);
+ }
+ else
+ sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i tried to process emote for invalid TypeId (%u).",textEntry,pSource->GetTypeId());
+ }
+
+ switch((*i).second.Type)
+ {
+ case CHAT_TYPE_SAY:
+ pSource->MonsterSay(textEntry, (*i).second.Language, target ? target->GetGUID() : 0);
+ break;
+ case CHAT_TYPE_YELL:
+ pSource->MonsterYell(textEntry, (*i).second.Language, target ? target->GetGUID() : 0);
+ break;
+ case CHAT_TYPE_TEXT_EMOTE:
+ pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0);
+ break;
+ case CHAT_TYPE_BOSS_EMOTE:
+ pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0, true);
+ break;
+ case CHAT_TYPE_WHISPER:
+ {
+ if (target && target->GetTypeId() == TYPEID_PLAYER)
+ pSource->MonsterWhisper(textEntry, target->GetGUID());
+ else sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry);
+ }break;
+ case CHAT_TYPE_BOSS_WHISPER:
+ {
+ if (target && target->GetTypeId() == TYPEID_PLAYER)
+ pSource->MonsterWhisper(textEntry, target->GetGUID(), true);
+ else sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry);
+ }break;
+ case CHAT_TYPE_ZONE_YELL:
+ pSource->MonsterYellToZone(textEntry, (*i).second.Language, target ? target->GetGUID() : 0);
+ break;
+ }
+}
+
+bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered)
+{
+ //No target so we can't cast
+ if (!Target || !Spell)
+ return false;
+
+ //Silenced so we can't cast
+ if (!Triggered && me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
+ return false;
+
+ //Check for power
+ if (!Triggered && me->GetPower((Powers)Spell->powerType) < Spell->manaCost)
+ return false;
+
+ SpellRangeEntry const *TempRange = NULL;
+
+ TempRange = GetSpellRangeStore()->LookupEntry(Spell->rangeIndex);
+
+ //Spell has invalid range store so we can't use it
+ if (!TempRange)
+ return false;
+
+ //Unit is out of range of this spell
+ if (!m_creature->IsInRange(Target,TempRange->minRangeHostile,TempRange->maxRangeHostile))
+ return false;
+
+ return true;
+}
+
+void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
+{
+ if (bEmptyList)
+ return;
+
+ for (std::list<CreatureEventAIHolder>::iterator itr = CreatureEventAIList.begin(); itr != CreatureEventAIList.end(); ++itr)
+ {
+ if ((*itr).Event.event_type == EVENT_T_RECEIVE_EMOTE)
+ {
+ if ((*itr).Event.receive_emote.emoteId != text_emote)
+ return;
+
+ PlayerCondition pcon((*itr).Event.receive_emote.condition,(*itr).Event.receive_emote.conditionValue1,(*itr).Event.receive_emote.conditionValue2);
+ if (pcon.Meets(pPlayer))
+ {
+ sLog.outDebug("CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing");
+ ProcessEvent(*itr, pPlayer);
+ }
+ }
+ }
+}
+
+bool CreatureEventAI::SpawnedEventConditionsCheck(CreatureEventAI_Event const& event)
+{
+ if(event.event_type != EVENT_T_SPAWNED)
+ return false;
+
+ switch (event.spawned.condition)
+ {
+ case SPAWNED_EVENT_ALWAY:
+ // always
+ return true;
+ case SPAWNED_EVENT_MAP:
+ // map ID check
+ return m_creature->GetMapId() == event.spawned.conditionValue1;
+ case SPAWNED_EVENT_ZONE:
+ {
+ // zone ID check
+ uint32 zone, area;
+ m_creature->GetZoneAndAreaId(zone,area);
+ return zone == event.spawned.conditionValue1 || area == event.spawned.conditionValue1;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h
new file mode 100644
index 00000000000..7b9fe84453e
--- /dev/null
+++ b/src/game/CreatureEventAI.h
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MANGOS_CREATURE_EAI_H
+#define MANGOS_CREATURE_EAI_H
+
+#include "Common.h"
+#include "Creature.h"
+#include "CreatureAI.h"
+#include "Unit.h"
+
+class Player;
+class WorldObject;
+
+#define EVENT_UPDATE_TIME 500
+#define MAX_ACTIONS 3
+#define MAX_PHASE 32
+
+enum EventAI_Type
+{
+ EVENT_T_TIMER = 0, // InitialMin, InitialMax, RepeatMin, RepeatMax
+ EVENT_T_TIMER_OOC = 1, // InitialMin, InitialMax, RepeatMin, RepeatMax
+ EVENT_T_HP = 2, // HPMax%, HPMin%, RepeatMin, RepeatMax
+ EVENT_T_MANA = 3, // ManaMax%,ManaMin% RepeatMin, RepeatMax
+ EVENT_T_AGGRO = 4, // NONE
+ EVENT_T_KILL = 5, // RepeatMin, RepeatMax
+ EVENT_T_DEATH = 6, // NONE
+ EVENT_T_EVADE = 7, // NONE
+ EVENT_T_SPELLHIT = 8, // SpellID, School, RepeatMin, RepeatMax
+ EVENT_T_RANGE = 9, // MinDist, MaxDist, RepeatMin, RepeatMax
+ EVENT_T_OOC_LOS = 10, // NoHostile, MaxRnage, RepeatMin, RepeatMax
+ EVENT_T_SPAWNED = 11, // Condition, CondValue1
+ EVENT_T_TARGET_HP = 12, // HPMax%, HPMin%, RepeatMin, RepeatMax
+ EVENT_T_TARGET_CASTING = 13, // RepeatMin, RepeatMax
+ EVENT_T_FRIENDLY_HP = 14, // HPDeficit, Radius, RepeatMin, RepeatMax
+ EVENT_T_FRIENDLY_IS_CC = 15, // DispelType, Radius, RepeatMin, RepeatMax
+ EVENT_T_FRIENDLY_MISSING_BUFF = 16, // SpellId, Radius, RepeatMin, RepeatMax
+ EVENT_T_SUMMONED_UNIT = 17, // CreatureId, RepeatMin, RepeatMax
+ EVENT_T_TARGET_MANA = 18, // ManaMax%, ManaMin%, RepeatMin, RepeatMax
+ EVENT_T_QUEST_ACCEPT = 19, // QuestID
+ EVENT_T_QUEST_COMPLETE = 20, //
+ EVENT_T_REACHED_HOME = 21, // NONE
+ EVENT_T_RECEIVE_EMOTE = 22, // EmoteId, Condition, CondValue1, CondValue2
+
+ EVENT_T_END,
+};
+
+enum EventAI_ActionType
+{
+ ACTION_T_NONE = 0, // No action
+ ACTION_T_TEXT = 1, // TextId1, optionally -TextId2, optionally -TextId3(if -TextId2 exist). If more than just -TextId1 is defined, randomize. Negative values.
+ ACTION_T_SET_FACTION = 2, // FactionId (or 0 for default)
+ ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph)
+ ACTION_T_SOUND = 4, // SoundId
+ ACTION_T_EMOTE = 5, // EmoteId
+ ACTION_T_RANDOM_SAY = 6, // UNUSED
+ ACTION_T_RANDOM_YELL = 7, // UNUSED
+ ACTION_T_RANDOM_TEXTEMOTE = 8, // UNUSED
+ ACTION_T_RANDOM_SOUND = 9, // SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field)
+ ACTION_T_RANDOM_EMOTE = 10, // EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field)
+ ACTION_T_CAST = 11, // SpellId, Target, CastFlags
+ ACTION_T_SUMMON = 12, // CreatureID, Target, Duration in ms
+ ACTION_T_THREAT_SINGLE_PCT = 13, // Threat%, Target
+ ACTION_T_THREAT_ALL_PCT = 14, // Threat%
+ ACTION_T_QUEST_EVENT = 15, // QuestID, Target
+ ACTION_T_CAST_EVENT = 16, // QuestID, SpellId, Target - must be removed as hack?
+ ACTION_T_SET_UNIT_FIELD = 17, // Field_Number, Value, Target
+ ACTION_T_SET_UNIT_FLAG = 18, // Flags (may be more than one field OR'd together), Target
+ ACTION_T_REMOVE_UNIT_FLAG = 19, // Flags (may be more than one field OR'd together), Target
+ ACTION_T_AUTO_ATTACK = 20, // AllowAttackState (0 = stop attack, anything else means continue attacking)
+ ACTION_T_COMBAT_MOVEMENT = 21, // AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
+ ACTION_T_SET_PHASE = 22, // Phase
+ ACTION_T_INC_PHASE = 23, // Value (may be negative to decrement phase, should not be 0)
+ ACTION_T_EVADE = 24, // No Params
+ ACTION_T_FLEE_FOR_ASSIST = 25, // No Params
+ ACTION_T_QUEST_EVENT_ALL = 26, // QuestID
+ ACTION_T_CAST_EVENT_ALL = 27, // CreatureId, SpellId
+ ACTION_T_REMOVEAURASFROMSPELL = 28, // Target, Spellid
+ ACTION_T_RANGED_MOVEMENT = 29, // Distance, Angle
+ ACTION_T_RANDOM_PHASE = 30, // PhaseId1, PhaseId2, PhaseId3
+ ACTION_T_RANDOM_PHASE_RANGE = 31, // PhaseMin, PhaseMax
+ ACTION_T_SUMMON_ID = 32, // CreatureId, Target, SpawnId
+ ACTION_T_KILLED_MONSTER = 33, // CreatureId, Target
+ ACTION_T_SET_INST_DATA = 34, // Field, Data
+ ACTION_T_SET_INST_DATA64 = 35, // Field, Target
+ ACTION_T_UPDATE_TEMPLATE = 36, // Entry, Team
+ ACTION_T_DIE = 37, // No Params
+ ACTION_T_ZONE_COMBAT_PULSE = 38, // No Params
+ ACTION_T_CALL_FOR_HELP = 39, // Radius
+
+ ACTION_T_SET_ACTIVE = 101, //Apply
+ ACTION_T_SET_AGGRESSIVE = 102, //Apply
+ ACTION_T_ATTACK_START_PULSE = 103, //Distance
+ ACTION_T_SUMMON_GO = 104, //GameObjectID, DespawnTime in ms
+
+ ACTION_T_END,
+};
+
+enum Target
+{
+ //Self (m_creature)
+ TARGET_T_SELF = 0, //Self cast
+
+ //Hostile targets (if pet then returns pet owner)
+ TARGET_T_HOSTILE, //Our current target (ie: highest aggro)
+ TARGET_T_HOSTILE_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks)
+ TARGET_T_HOSTILE_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for)
+ TARGET_T_HOSTILE_RANDOM, //Just any random target on our threat list
+ TARGET_T_HOSTILE_RANDOM_NOT_TOP, //Any random target except top threat
+
+ //Invoker targets (if pet then returns pet owner)
+ TARGET_T_ACTION_INVOKER, //Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF)
+
+ //Hostile targets (including pets)
+ TARGET_T_HOSTILE_WPET, //Current target (can be a pet)
+ TARGET_T_HOSTILE_WPET_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks)
+ TARGET_T_HOSTILE_WPET_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for)
+ TARGET_T_HOSTILE_WPET_RANDOM, //Just any random target on our threat list
+ TARGET_T_HOSTILE_WPET_RANDOM_NOT_TOP, //Any random target except top threat
+
+ TARGET_T_ACTION_INVOKER_WPET,
+
+ TARGET_T_END
+};
+
+enum CastFlags
+{
+ CAST_INTURRUPT_PREVIOUS = 0x01, //Interrupt any spell casting
+ CAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time)
+ CAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range
+ CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range
+ CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself
+ CAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell
+};
+
+enum EventFlags
+{
+ EFLAG_REPEATABLE = 0x01, //Event repeats
+ EFLAG_NORMAL = 0x02, //Event only occurs in Normal instance difficulty
+ EFLAG_HEROIC = 0x04, //Event only occurs in Heroic instance difficulty
+ EFLAG_RESERVED_3 = 0x08,
+ EFLAG_RESERVED_4 = 0x10,
+ EFLAG_RESERVED_5 = 0x20,
+ EFLAG_RESERVED_6 = 0x40,
+ EFLAG_DEBUG_ONLY = 0x80, //Event only occurs in debug build
+};
+
+enum SpawnedEventMode
+{
+ SPAWNED_EVENT_ALWAY = 0,
+ SPAWNED_EVENT_MAP = 1,
+ SPAWNED_EVENT_ZONE = 2
+};
+
+// String text additional data, used in (CreatureEventAI)
+struct StringTextData
+{
+ uint32 SoundId;
+ uint8 Type;
+ uint32 Language;
+ uint32 Emote;
+};
+// Text Maps
+typedef UNORDERED_MAP<int32, StringTextData> CreatureEventAI_TextMap;
+
+struct CreatureEventAI_Action
+{
+ EventAI_ActionType type: 16;
+ union
+ {
+ // ACTION_T_TEXT = 1
+ struct
+ {
+ int32 TextId1;
+ int32 TextId2;
+ int32 TextId3;
+ } text;
+ // ACTION_T_SET_FACTION = 2
+ struct
+ {
+ uint32 factionId; // faction or 0 for default)
+ } set_faction;
+ // ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3
+ struct
+ {
+ uint32 creatireId; // set one from fields (or 0 for both to demorph)
+ uint32 modelId;
+ } morph;
+ // ACTION_T_SOUND = 4
+ struct
+ {
+ uint32 soundId;
+ } sound;
+ // ACTION_T_EMOTE = 5
+ struct
+ {
+ uint32 emoteId;
+ } emote;
+ // ACTION_T_RANDOM_SOUND = 9
+ struct
+ {
+ int32 soundId1; // (-1 in any field means no output if randomed that field)
+ int32 soundId2;
+ int32 soundId3;
+ } random_sound;
+ // ACTION_T_RANDOM_EMOTE = 10
+ struct
+ {
+ int32 emoteId1; // (-1 in any field means no output if randomed that field)
+ int32 emoteId2;
+ int32 emoteId3;
+ } random_emote;
+ // ACTION_T_CAST = 11
+ struct
+ {
+ uint32 spellId;
+ uint32 target;
+ uint32 castFlags;
+ } cast;
+ // ACTION_T_SUMMON = 12
+ struct
+ {
+ uint32 creatured;
+ uint32 target;
+ uint32 duration;
+ } summon;
+ // ACTION_T_THREAT_SINGLE_PCT = 13
+ struct
+ {
+ int32 percent;
+ uint32 target;
+ } threat_single_pct;
+ // ACTION_T_THREAT_ALL_PCT = 14
+ struct
+ {
+ int32 percent;
+ } threat_all_pct;
+ // ACTION_T_QUEST_EVENT = 15
+ struct
+ {
+ uint32 questId;
+ uint32 target;
+ } quest_event;
+ // ACTION_T_CAST_EVENT = 16
+ struct
+ {
+ uint32 creatureId;
+ uint32 spellId;
+ uint32 target;
+ } cast_event;
+ // ACTION_T_SET_UNIT_FIELD = 17
+ struct
+ {
+ uint32 field;
+ uint32 value;
+ uint32 target;
+ } set_unit_field;
+ // ACTION_T_SET_UNIT_FLAG = 18, // value provided mask bits that will be set
+ // ACTION_T_REMOVE_UNIT_FLAG = 19, // value provided mask bits that will be clear
+ struct
+ {
+ uint32 value;
+ uint32 target;
+ } unit_flag;
+ // ACTION_T_AUTO_ATTACK = 20
+ struct
+ {
+ uint32 state; // 0 = stop attack, anything else means continue attacking
+ } auto_attack;
+ // ACTION_T_COMBAT_MOVEMENT = 21
+ struct
+ {
+ uint32 state; // 0 = stop combat based movement, anything else continue attacking
+ } combat_movement;
+ // ACTION_T_SET_PHASE = 22
+ struct
+ {
+ uint32 phase;
+ } set_phase;
+ // ACTION_T_INC_PHASE = 23
+ struct
+ {
+ int32 step;
+ } set_inc_phase;
+ // ACTION_T_QUEST_EVENT_ALL = 26
+ struct
+ {
+ uint32 questId;
+ } quest_event_all;
+ // ACTION_T_CAST_EVENT_ALL = 27
+ struct
+ {
+ uint32 creatureId;
+ uint32 spellId;
+ } cast_event_all;
+ // ACTION_T_REMOVEAURASFROMSPELL = 28
+ struct
+ {
+ uint32 target;
+ uint32 spellId;
+ } remove_aura;
+ // ACTION_T_RANGED_MOVEMENT = 29
+ struct
+ {
+ uint32 distance;
+ int32 angle;
+ } ranged_movement;
+ // ACTION_T_RANDOM_PHASE = 30
+ struct
+ {
+ uint32 phase1;
+ uint32 phase2;
+ uint32 phase3;
+ } random_phase;
+ // ACTION_T_RANDOM_PHASE_RANGE = 31
+ struct
+ {
+ uint32 phaseMin;
+ uint32 phaseMax;
+ } random_phase_range;
+ // ACTION_T_SUMMON_ID = 32
+ struct
+ {
+ uint32 creatureId;
+ uint32 target;
+ uint32 spawnId;
+ } summon_id;
+ // ACTION_T_KILLED_MONSTER = 33
+ struct
+ {
+ uint32 creatureId;
+ uint32 target;
+ } killed_monster;
+ // ACTION_T_SET_INST_DATA = 34
+ struct
+ {
+ uint32 field;
+ uint32 value;
+ } set_inst_data;
+ // ACTION_T_SET_INST_DATA64 = 35
+ struct
+ {
+ uint32 field;
+ uint32 target;
+ } set_inst_data64;
+ // ACTION_T_UPDATE_TEMPLATE = 36
+ struct
+ {
+ uint32 creatureId;
+ uint32 team;
+ } update_template;
+ // ACTION_T_CALL_FOR_HELP = 39
+ struct
+ {
+ uint32 radius;
+ } call_for_help;
+ // RAW
+ struct
+ {
+ uint32 param1;
+ uint32 param2;
+ uint32 param3;
+ } raw;
+ };
+};
+
+struct CreatureEventAI_Event
+{
+ uint32 event_id;
+
+ uint32 creature_id;
+
+ uint32 event_inverse_phase_mask;
+
+ EventAI_Type event_type : 16;
+ uint8 event_chance : 8;
+ uint8 event_flags : 8;
+
+ union
+ {
+ // EVENT_T_TIMER = 0
+ // EVENT_T_TIMER_OOC = 1
+ struct
+ {
+ uint32 initialMin;
+ uint32 initialMax;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } timer;
+ // EVENT_T_HP = 2
+ // EVENT_T_MANA = 3
+ // EVENT_T_TARGET_HP = 12
+ // EVENT_T_TARGET_MANA = 18
+ struct
+ {
+ uint32 percentMax;
+ uint32 percentMin;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } percent_range;
+ // EVENT_T_KILL = 5
+ struct
+ {
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } kill;
+ // EVENT_T_SPELLHIT = 8
+ struct
+ {
+ uint32 spellId;
+ uint32 schoolMask; // -1 (==0xffffffff) is ok value for full mask, or must be more limited mask like (0 < 1) = 1 for normal/physical school
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } spell_hit;
+ // EVENT_T_RANGE = 9
+ struct
+ {
+ uint32 minDist;
+ uint32 maxDist;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } range;
+ // EVENT_T_OOC_LOS = 10
+ struct
+ {
+ uint32 noHostile;
+ uint32 maxRange;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } ooc_los;
+ // EVENT_T_SPAWNED = 11
+ struct
+ {
+ uint32 condition;
+ uint32 conditionValue1;
+ } spawned;
+ // EVENT_T_TARGET_CASTING = 13
+ struct
+ {
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } target_casting;
+ // EVENT_T_FRIENDLY_HP = 14
+ struct
+ {
+ uint32 hpDeficit;
+ uint32 radius;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } friendly_hp;
+ // EVENT_T_FRIENDLY_IS_CC = 15
+ struct
+ {
+ uint32 dispelType; // unused ?
+ uint32 radius;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } friendly_is_cc;
+ // EVENT_T_FRIENDLY_MISSING_BUFF = 16
+ struct
+ {
+ uint32 spellId;
+ uint32 radius;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } friendly_buff;
+ // EVENT_T_SUMMONED_UNIT = 17
+ struct
+ {
+ uint32 creatureId;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } summon_unit;
+ // EVENT_T_QUEST_ACCEPT = 19
+ // EVENT_T_QUEST_COMPLETE = 20
+ struct
+ {
+ uint32 questId;
+ } quest;
+ // EVENT_T_RECEIVE_EMOTE = 22
+ struct
+ {
+ uint32 emoteId;
+ uint32 condition;
+ uint32 conditionValue1;
+ uint32 conditionValue2;
+ } receive_emote;
+
+ // RAW
+ struct
+ {
+ uint32 param1;
+ uint32 param2;
+ uint32 param3;
+ uint32 param4;
+ } raw;
+ };
+
+ CreatureEventAI_Action action[MAX_ACTIONS];
+};
+//Event_Map
+typedef UNORDERED_MAP<uint32, std::vector<CreatureEventAI_Event> > CreatureEventAI_Event_Map;
+
+struct CreatureEventAI_Summon
+{
+ uint32 id;
+
+ float position_x;
+ float position_y;
+ float position_z;
+ float orientation;
+ uint32 SpawnTimeSecs;
+};
+
+//EventSummon_Map
+typedef UNORDERED_MAP<uint32, CreatureEventAI_Summon> CreatureEventAI_Summon_Map;
+
+struct CreatureEventAIHolder
+{
+ CreatureEventAIHolder(CreatureEventAI_Event p) : Event(p), Time(0), Enabled(true){}
+
+ CreatureEventAI_Event Event;
+ uint32 Time;
+ bool Enabled;
+
+ // helper
+ bool UpdateRepeatTimer(Creature* creature, uint32 repeatMin, uint32 repeatMax);
+};
+
+class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI
+{
+
+ public:
+ explicit CreatureEventAI(Creature *c);
+ ~CreatureEventAI()
+ {
+ CreatureEventAIList.clear();
+ }
+ void JustRespawned();
+ void Reset();
+ void JustReachedHome();
+ void EnterCombat(Unit *enemy);
+ void EnterEvadeMode();
+ void JustDied(Unit* killer);
+ void KilledUnit(Unit* victim);
+ void JustSummoned(Creature* pUnit);
+ void AttackStart(Unit *who);
+ void MoveInLineOfSight(Unit *who);
+ void SpellHit(Unit* pUnit, const SpellEntry* pSpell);
+ void UpdateAI(const uint32 diff);
+ void ReceiveEmote(Player* pPlayer, uint32 text_emote);
+ static int Permissible(const Creature *);
+
+ bool ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker = NULL);
+ void ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker);
+ inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3);
+ inline int32 GetRandActionParam(uint32 rnd, int32 param1, int32 param2, int32 param3);
+ inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker);
+ inline Unit* SelectUnit(AttackingTarget target, uint32 position);
+
+ void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target);
+ bool CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered);
+
+ bool SpawnedEventConditionsCheck(CreatureEventAI_Event const& event);
+
+ Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff);
+ void DoFindFriendlyMissingBuff(std::list<Creature*>& _list, float range, uint32 spellid);
+ void DoFindFriendlyCC(std::list<Creature*>& _list, float range);
+
+ //Holder for events (stores enabled, time, and eventid)
+ std::list<CreatureEventAIHolder> CreatureEventAIList;
+ uint32 EventUpdateTime; //Time between event updates
+ uint32 EventDiff; //Time between the last event call
+ bool bEmptyList;
+
+ //Variables used by Events themselves
+ uint8 Phase; //Current phase, max 32 phases
+ bool CombatMovementEnabled; //If we allow targeted movment gen (movement twoards top threat)
+ bool MeleeEnabled; //If we allow melee auto attack
+ uint32 AttackDistance; //Distance to attack from
+ float AttackAngle; //Angle of attack
+};
+#endif
diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp
new file mode 100644
index 00000000000..1905fa72d41
--- /dev/null
+++ b/src/game/CreatureEventAIMgr.cpp
@@ -0,0 +1,707 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "Database/SQLStorage.h"
+#include "CreatureEventAI.h"
+#include "CreatureEventAIMgr.h"
+#include "ObjectMgr.h"
+#include "ProgressBar.h"
+#include "Policies/SingletonImp.h"
+#include "ObjectDefines.h"
+#include "GridDefines.h"
+
+INSTANTIATE_SINGLETON_1(CreatureEventAIMgr);
+
+// -------------------
+void CreatureEventAIMgr::LoadCreatureEventAI_Texts()
+{
+ // Drop Existing Text Map, only done once and we are ready to add data from multiple sources.
+ m_CreatureEventAI_TextMap.clear();
+
+ // Load EventAI Text
+ objmgr.LoadTrinityStrings(WorldDatabase,"creature_ai_texts",MIN_CREATURE_AI_TEXT_STRING_ID,MAX_CREATURE_AI_TEXT_STRING_ID);
+
+ // Gather Additional data from EventAI Texts
+ QueryResult *result = WorldDatabase.PQuery("SELECT entry, sound, type, language, emote FROM creature_ai_texts");
+
+ sLog.outString("Loading EventAI Texts additional data...");
+ if (result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 count = 0;
+
+ do
+ {
+ bar.step();
+ Field* fields = result->Fetch();
+ StringTextData temp;
+
+ int32 i = fields[0].GetInt32();
+ temp.SoundId = fields[1].GetInt32();
+ temp.Type = fields[2].GetInt32();
+ temp.Language = fields[3].GetInt32();
+ temp.Emote = fields[4].GetInt32();
+
+ // range negative
+ if (i > MIN_CREATURE_AI_TEXT_STRING_ID || i <= MAX_CREATURE_AI_TEXT_STRING_ID)
+ {
+ sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` is not in valid range(%d-%d)",i,MIN_CREATURE_AI_TEXT_STRING_ID,MAX_CREATURE_AI_TEXT_STRING_ID);
+ continue;
+ }
+
+ // range negative (don't must be happen, loaded from same table)
+ if (!objmgr.GetTrinityStringLocale(i))
+ {
+ sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` not found",i);
+ continue;
+ }
+
+ if (temp.SoundId)
+ {
+ if (!sSoundEntriesStore.LookupEntry(temp.SoundId))
+ sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has Sound %u but sound does not exist.",i,temp.SoundId);
+ }
+
+ if (!GetLanguageDescByID(temp.Language))
+ sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` using Language %u but Language does not exist.",i,temp.Language);
+
+ if (temp.Type > CHAT_TYPE_ZONE_YELL)
+ sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has Type %u but this Chat Type does not exist.",i,temp.Type);
+
+ if (temp.Emote)
+ {
+ if (!sEmotesStore.LookupEntry(temp.Emote))
+ sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has Emote %u but emote does not exist.",i,temp.Emote);
+ }
+
+ m_CreatureEventAI_TextMap[i] = temp;
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u additional CreatureEventAI Texts data.", count);
+ }
+ else
+ {
+ barGoLink bar(1);
+ bar.step();
+ sLog.outString();
+ sLog.outString(">> Loaded 0 additional CreatureEventAI Texts data. DB table `creature_ai_texts` is empty.");
+ }
+
+}
+
+// -------------------
+void CreatureEventAIMgr::LoadCreatureEventAI_Summons()
+{
+
+ //Drop Existing EventSummon Map
+ m_CreatureEventAI_Summon_Map.clear();
+
+ //Gather additional data for EventAI
+ QueryResult *result = WorldDatabase.PQuery("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM creature_ai_summons");
+ if (result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 Count = 0;
+
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+
+ CreatureEventAI_Summon temp;
+
+ uint32 i = fields[0].GetUInt32();
+ temp.position_x = fields[1].GetFloat();
+ temp.position_y = fields[2].GetFloat();
+ temp.position_z = fields[3].GetFloat();
+ temp.orientation = fields[4].GetFloat();
+ temp.SpawnTimeSecs = fields[5].GetUInt32();
+
+ if(!MaNGOS::IsValidMapCoord(temp.position_x,temp.position_y,temp.position_z,temp.orientation))
+ {
+ sLog.outErrorDb("CreatureEventAI: Summon id %u have wrong coordinates (%f,%f,%f,%f), skipping.", i,temp.position_x,temp.position_y,temp.position_z,temp.orientation);
+ continue;
+ }
+
+ //Add to map
+ m_CreatureEventAI_Summon_Map[i] = temp;
+ ++Count;
+ }while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u CreatureEventAI summon definitions", Count);
+ }else
+ {
+ barGoLink bar(1);
+ bar.step();
+ sLog.outString();
+ sLog.outString(">> Loaded 0 CreatureEventAI Summon definitions. DB table `creature_ai_summons` is empty.");
+ }
+
+}
+
+// -------------------
+void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
+{
+ //Drop Existing EventAI List
+ m_CreatureEventAI_Event_Map.clear();
+
+ //Gather event data
+ QueryResult *result = WorldDatabase.PQuery("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, "
+ "event_param1, event_param2, event_param3, event_param4, "
+ "action1_type, action1_param1, action1_param2, action1_param3, "
+ "action2_type, action2_param1, action2_param2, action2_param3, "
+ "action3_type, action3_param1, action3_param2, action3_param3 "
+ "FROM creature_ai_scripts");
+ if (result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 Count = 0;
+
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+
+ CreatureEventAI_Event temp;
+ temp.event_id = EventAI_Type(fields[0].GetUInt32());
+ uint32 i = temp.event_id;
+
+ temp.creature_id = fields[1].GetUInt32();
+ uint32 creature_id = temp.creature_id;
+
+ uint32 e_type = fields[2].GetUInt32();
+ //Report any errors in event
+ if (e_type >= EVENT_T_END)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u have wrong type (%u), skipping.", i,e_type);
+ continue;
+ }
+ temp.event_type = EventAI_Type(e_type);
+
+ temp.event_inverse_phase_mask = fields[3].GetUInt32();
+ temp.event_chance = fields[4].GetUInt8();
+ temp.event_flags = fields[5].GetUInt8();
+ temp.raw.param1 = fields[6].GetUInt32();
+ temp.raw.param2 = fields[7].GetUInt32();
+ temp.raw.param3 = fields[8].GetUInt32();
+ temp.raw.param4 = fields[9].GetUInt32();
+
+ //Creature does not exist in database
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.creature_id))
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u has script for non-existing creature entry (%u), skipping.", i, temp.creature_id);
+ continue;
+ }
+
+ //No chance of this event occuring
+ if (temp.event_chance == 0)
+ sLog.outErrorDb("CreatureEventAI: Event %u has 0 percent chance. Event will never trigger!", i);
+ //Chance above 100, force it to be 100
+ else if (temp.event_chance > 100)
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using event %u with more than 100 percent chance. Adjusting to 100 percent.", temp.creature_id, i);
+ temp.event_chance = 100;
+ }
+
+ //Individual event checks
+ switch (temp.event_type)
+ {
+ case EVENT_T_TIMER:
+ case EVENT_T_TIMER_OOC:
+ if (temp.timer.initialMax < temp.timer.initialMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using timed event(%u) with param2 < param1 (InitialMax < InitialMin). Event will never repeat.", temp.creature_id, i);
+ if (temp.timer.repeatMax < temp.timer.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_HP:
+ case EVENT_T_MANA:
+ case EVENT_T_TARGET_HP:
+ case EVENT_T_TARGET_MANA:
+ if (temp.percent_range.percentMax > 100)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp.creature_id, i);
+
+ if (temp.percent_range.percentMax <= temp.percent_range.percentMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using percentage event(%u) with param1 <= param2 (MaxPercent <= MinPercent). Event will never trigger! ", temp.creature_id, i);
+
+ if (temp.event_flags & EFLAG_REPEATABLE && !temp.percent_range.repeatMin && !temp.percent_range.repeatMax)
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u has param3 and param4=0 (RepeatMin/RepeatMax) but cannot be repeatable without timers. Removing EFLAG_REPEATABLE for event %u.", temp.creature_id, i);
+ temp.event_flags &= ~EFLAG_REPEATABLE;
+ }
+ break;
+ case EVENT_T_SPELLHIT:
+ if (temp.spell_hit.spellId)
+ {
+ SpellEntry const* pSpell = sSpellStore.LookupEntry(temp.spell_hit.spellId);
+ if (!pSpell)
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.spell_hit.spellId, i);
+ continue;
+ }
+
+ if ((temp.spell_hit.schoolMask & pSpell->SchoolMask) != pSpell->SchoolMask)
+ sLog.outErrorDb("CreatureEventAI: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp.creature_id, temp.spell_hit.schoolMask, i);
+ }
+
+ if (!temp.spell_hit.schoolMask)
+ sLog.outErrorDb("CreatureEventAI: Creature %u is using invalid SpellSchoolMask(%u) defined in event %u.", temp.creature_id, temp.spell_hit.schoolMask, i);
+
+ if (temp.spell_hit.repeatMax < temp.spell_hit.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_RANGE:
+ if (temp.range.maxDist < temp.range.minDist)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (MaxDist < MinDist). Event will never repeat.", temp.creature_id, i);
+ if (temp.range.repeatMax < temp.range.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_OOC_LOS:
+ if (temp.ooc_los.repeatMax < temp.ooc_los.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_SPAWNED:
+ switch(temp.spawned.condition)
+ {
+ case SPAWNED_EVENT_ALWAY:
+ break;
+ case SPAWNED_EVENT_MAP:
+ if(!sMapStore.LookupEntry(temp.spawned.conditionValue1))
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using spawned event(%u) with param1 = %u 'map specific' but with not existed map (%u) in param2. Event will never repeat.", temp.creature_id, i, temp.spawned.condition, temp.spawned.conditionValue1);
+ break;
+ case SPAWNED_EVENT_ZONE:
+ if(!GetAreaEntryByAreaID(temp.spawned.conditionValue1))
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using spawned event(%u) with param1 = %u 'area specific' but with not existed area (%u) in param2. Event will never repeat.", temp.creature_id, i, temp.spawned.condition, temp.spawned.conditionValue1);
+ default:
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using invalid spawned event %u mode (%u) in param1", temp.creature_id, i, temp.spawned.condition);
+ break;
+ }
+ break;
+ case EVENT_T_FRIENDLY_HP:
+ if (temp.friendly_hp.repeatMax < temp.friendly_hp.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_FRIENDLY_IS_CC:
+ if (temp.friendly_is_cc.repeatMax < temp.friendly_is_cc.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_FRIENDLY_MISSING_BUFF:
+ {
+ SpellEntry const* pSpell = sSpellStore.LookupEntry(temp.spell_hit.spellId);
+ if (!pSpell)
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.spell_hit.spellId, i);
+ continue;
+ }
+ if (temp.friendly_buff.repeatMax < temp.friendly_buff.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ }
+ case EVENT_T_KILL:
+ if (temp.kill.repeatMax < temp.kill.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_TARGET_CASTING:
+ if (temp.target_casting.repeatMax < temp.target_casting.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_SUMMONED_UNIT:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.summon_unit.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with not existed creature template id (%u) in param1, skipped.", temp.creature_id, i, temp.summon_unit.creatureId);
+ if (temp.summon_unit.repeatMax < temp.summon_unit.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ case EVENT_T_QUEST_ACCEPT:
+ case EVENT_T_QUEST_COMPLETE:
+ if (!objmgr.GetQuestTemplate(temp.quest.questId))
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with not existed qyest id (%u) in param1, skipped.", temp.creature_id, i, temp.quest.questId);
+ sLog.outErrorDb("CreatureEventAI: Creature %u using not implemented event (%u) in event %u.", temp.creature_id, temp.event_id, i);
+ continue;
+
+ case EVENT_T_AGGRO:
+ case EVENT_T_DEATH:
+ case EVENT_T_EVADE:
+ case EVENT_T_REACHED_HOME:
+ {
+ if (temp.event_flags & EFLAG_REPEATABLE)
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event %u.", temp.creature_id, i);
+ temp.event_flags &= ~EFLAG_REPEATABLE;
+ }
+
+ break;
+ }
+
+ case EVENT_T_RECEIVE_EMOTE:
+ {
+ if (!sEmotesTextStore.LookupEntry(temp.receive_emote.emoteId))
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param1 (EmoteTextId: %u) are not valid.",temp.creature_id, i, temp.receive_emote.emoteId);
+ continue;
+ }
+
+ if (!PlayerCondition::IsValid(ConditionType(temp.receive_emote.condition), temp.receive_emote.conditionValue1, temp.receive_emote.conditionValue2))
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param2 (Condition: %u) are not valid.",temp.creature_id, i, temp.receive_emote.condition);
+ continue;
+ }
+
+ if (!(temp.event_flags & EFLAG_REPEATABLE))
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: EFLAG_REPEATABLE not set. Event must always be repeatable. Flag applied.", temp.creature_id, i);
+ temp.event_flags |= EFLAG_REPEATABLE;
+ }
+
+ break;
+ }
+
+ default:
+ sLog.outErrorDb("CreatureEventAI: Creature %u using not checked at load event (%u) in event %u. Need check code update?", temp.creature_id, temp.event_id, i);
+ break;
+ }
+
+ for (uint32 j = 0; j < MAX_ACTIONS; j++)
+ {
+ uint16 action_type = fields[10+(j*4)].GetUInt16();
+ if (action_type >= ACTION_T_END)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u has incorrect action type (%u), replace by ACTION_T_NONE.", i, j+1, action_type);
+ temp.action[j].type = ACTION_T_NONE;
+ continue;
+ }
+
+ CreatureEventAI_Action& action = temp.action[j];
+
+ action.type = EventAI_ActionType(action_type);
+ action.raw.param1 = fields[11+(j*4)].GetUInt32();
+ action.raw.param2 = fields[12+(j*4)].GetUInt32();
+ action.raw.param3 = fields[13+(j*4)].GetUInt32();
+
+ //Report any errors in actions
+ switch (action.type)
+ {
+ case ACTION_T_NONE:
+ break;
+ case ACTION_T_TEXT:
+ {
+ if (action.text.TextId1 < 0)
+ {
+ if (m_CreatureEventAI_TextMap.find(action.text.TextId1) == m_CreatureEventAI_TextMap.end())
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 refrences non-existing entry in texts table.", i, j+1);
+ }
+ if (action.text.TextId2 < 0)
+ {
+ if (m_CreatureEventAI_TextMap.find(action.text.TextId2) == m_CreatureEventAI_TextMap.end())
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 refrences non-existing entry in texts table.", i, j+1);
+
+ if (!action.text.TextId1)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u has param2, but param1 is not set. Required for randomized text.", i, j+1);
+ }
+ if (action.text.TextId3 < 0)
+ {
+ if (m_CreatureEventAI_TextMap.find(action.text.TextId3) == m_CreatureEventAI_TextMap.end())
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 refrences non-existing entry in texts table.", i, j+1);
+
+ if (!action.text.TextId1 || !action.text.TextId2)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u has param3, but param1 and/or param2 is not set. Required for randomized text.", i, j+1);
+ }
+ break;
+ }
+ case ACTION_T_SET_FACTION:
+ if (action.set_faction.factionId !=0 && !sFactionStore.LookupEntry(action.set_faction.factionId))
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent FactionId %u.", i, j+1, action.set_faction.factionId);
+ action.set_faction.factionId = 0;
+ }
+ break;
+ case ACTION_T_MORPH_TO_ENTRY_OR_MODEL:
+ if (action.morph.creatireId !=0 || action.morph.modelId !=0)
+ {
+ if (action.morph.creatireId && !sCreatureStorage.LookupEntry<CreatureInfo>(action.morph.creatireId))
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Creature entry %u.", i, j+1, action.morph.creatireId);
+ action.morph.creatireId = 0;
+ }
+
+ if (action.morph.modelId)
+ {
+ if (action.morph.creatireId)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u have unused ModelId %u with also set creature id %u.", i, j+1, action.morph.modelId,action.morph.creatireId);
+ action.morph.modelId = 0;
+ }
+ else if (!sCreatureDisplayInfoStore.LookupEntry(action.morph.modelId))
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant ModelId %u.", i, j+1, action.morph.modelId);
+ action.morph.modelId = 0;
+ }
+ }
+
+ break;
+ }
+ case ACTION_T_SOUND:
+ if (!sSoundEntriesStore.LookupEntry(action.sound.soundId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, action.sound.soundId);
+ break;
+ case ACTION_T_EMOTE:
+ if (!sEmotesStore.LookupEntry(action.emote.emoteId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (EmoteId: %u) are not valid.", i, j+1, action.emote.emoteId);
+ break;
+ case ACTION_T_RANDOM_SOUND:
+ if (!sSoundEntriesStore.LookupEntry(action.random_sound.soundId1))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 uses non-existant SoundID %u.", i, j+1, action.random_sound.soundId1);
+ if (action.random_sound.soundId2 >= 0 && !sSoundEntriesStore.LookupEntry(action.random_sound.soundId2))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 uses non-existant SoundID %u.", i, j+1, action.random_sound.soundId2);
+ if (action.random_sound.soundId3 >= 0 && !sSoundEntriesStore.LookupEntry(action.random_sound.soundId3))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 uses non-existant SoundID %u.", i, j+1, action.random_sound.soundId3);
+ break;
+ case ACTION_T_RANDOM_EMOTE:
+ if (!sEmotesStore.LookupEntry(action.random_emote.emoteId1))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (EmoteId: %u) are not valid.", i, j+1, action.random_emote.emoteId1);
+ if (action.random_emote.emoteId2 >= 0 && !sEmotesStore.LookupEntry(action.random_emote.emoteId2))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 (EmoteId: %u) are not valid.", i, j+1, action.random_emote.emoteId2);
+ if (action.random_emote.emoteId3 >= 0 && !sEmotesStore.LookupEntry(action.random_emote.emoteId3))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 (EmoteId: %u) are not valid.", i, j+1, action.random_emote.emoteId3);
+ break;
+ case ACTION_T_CAST:
+ {
+ const SpellEntry *spell = sSpellStore.LookupEntry(action.cast.spellId);
+ if (!spell)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.cast.spellId);
+ /* FIXME: temp.raw.param3 not have event tipes with recovery time in it....
+ else
+ {
+ if (spell->RecoveryTime > 0 && temp.event_flags & EFLAG_REPEATABLE)
+ {
+ //output as debug for now, also because there's no general rule all spells have RecoveryTime
+ if (temp.event_param3 < spell->RecoveryTime)
+ sLog.outDebug("CreatureEventAI: Event %u Action %u uses SpellID %u but cooldown is longer(%u) than minumum defined in event param3(%u).", i, j+1,action.cast.spellId, spell->RecoveryTime, temp.event_param3);
+ }
+ }
+ */
+
+ //Cast is always triggered if target is forced to cast on self
+ if (action.cast.castFlags & CAST_FORCE_TARGET_SELF)
+ action.cast.castFlags |= CAST_TRIGGERED;
+
+ if (action.cast.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ }
+ case ACTION_T_SUMMON:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.summon.creatured))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent creature entry %u.", i, j+1, action.summon.creatured);
+
+ if (action.summon.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_THREAT_SINGLE_PCT:
+ if (std::abs(action.threat_single_pct.percent) > 100)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses invalid percent value %u.", i, j+1, action.threat_single_pct.percent);
+ if (action.threat_single_pct.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_THREAT_ALL_PCT:
+ if (std::abs(action.threat_all_pct.percent) > 100)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses invalid percent value %u.", i, j+1, action.threat_all_pct.percent);
+ break;
+ case ACTION_T_QUEST_EVENT:
+ if (Quest const* qid = objmgr.GetQuestTemplate(action.quest_event.questId))
+ {
+ if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, action.quest_event.questId);
+ }
+ else
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent Quest entry %u.", i, j+1, action.quest_event.questId);
+
+ if (action.quest_event.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+
+ break;
+ case ACTION_T_CAST_EVENT:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.cast_event.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent creature entry %u.", i, j+1, action.cast_event.creatureId);
+ if (!sSpellStore.LookupEntry(action.cast_event.spellId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.cast_event.spellId);
+ if (action.cast_event.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_SET_UNIT_FIELD:
+ if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i, j+1);
+ if (action.set_unit_field.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_SET_UNIT_FLAG:
+ case ACTION_T_REMOVE_UNIT_FLAG:
+ if (action.unit_flag.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_SET_PHASE:
+ if (action.set_phase.phase >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ break;
+ case ACTION_T_INC_PHASE:
+ if (action.set_inc_phase.step == 0)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1);
+ else if (std::abs(action.set_inc_phase.step) > MAX_PHASE-1)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u is change phase by too large for any use %i.", i, j+1, action.set_inc_phase.step);
+ break;
+ case ACTION_T_QUEST_EVENT_ALL:
+ if (Quest const* qid = objmgr.GetQuestTemplate(action.quest_event_all.questId))
+ {
+ if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, action.quest_event_all.questId);
+ }
+ else
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent Quest entry %u.", i, j+1, action.quest_event_all.questId);
+ break;
+ case ACTION_T_CAST_EVENT_ALL:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.cast_event_all.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent creature entry %u.", i, j+1, action.cast_event_all.creatureId);
+ if (!sSpellStore.LookupEntry(action.cast_event_all.spellId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.cast_event_all.spellId);
+ break;
+ case ACTION_T_REMOVEAURASFROMSPELL:
+ if (!sSpellStore.LookupEntry(action.remove_aura.spellId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.remove_aura.spellId);
+ if (action.remove_aura.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_RANDOM_PHASE: //PhaseId1, PhaseId2, PhaseId3
+ if (action.random_phase.phase1 >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase1 >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ if (action.random_phase.phase2 >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase2 >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ if (action.random_phase.phase3 >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase3 >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ break;
+ case ACTION_T_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax
+ if (action.random_phase_range.phaseMin >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phaseMin >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ if (action.random_phase_range.phaseMin >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phaseMax >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ if (action.random_phase_range.phaseMin >= action.random_phase_range.phaseMax)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phaseMax <= phaseMin.", i, j+1);
+ std::swap(action.random_phase_range.phaseMin,action.random_phase_range.phaseMax);
+ // equal case processed at call
+ }
+ break;
+ case ACTION_T_SUMMON_ID:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.summon_id.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, action.summon_id.creatureId);
+ if (action.summon_id.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ if (m_CreatureEventAI_Summon_Map.find(action.summon_id.spawnId) == m_CreatureEventAI_Summon_Map.end())
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u summons missing CreatureEventAI_Summon %u", i, j+1, action.summon_id.spawnId);
+ break;
+ case ACTION_T_KILLED_MONSTER:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.killed_monster.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, action.killed_monster.creatureId);
+ if (action.killed_monster.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_SET_INST_DATA:
+ if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1);
+ if (action.set_inst_data.value > 4/*SPECIAL*/)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set instance data above encounter state 4. Custom case?", i, j+1);
+ break;
+ case ACTION_T_SET_INST_DATA64:
+ if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1);
+ if (action.set_inst_data64.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_UPDATE_TEMPLATE:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.update_template.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, action.update_template.creatureId);
+ break;
+ case ACTION_T_EVADE: //No Params
+ case ACTION_T_FLEE_FOR_ASSIST: //No Params
+ case ACTION_T_DIE: //No Params
+ case ACTION_T_ZONE_COMBAT_PULSE: //No Params
+ case ACTION_T_AUTO_ATTACK: //AllowAttackState (0 = stop attack, anything else means continue attacking)
+ case ACTION_T_COMBAT_MOVEMENT: //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
+ case ACTION_T_RANGED_MOVEMENT: //Distance, Angle
+ case ACTION_T_CALL_FOR_HELP: //Distance
+ break;
+
+ case ACTION_T_RANDOM_SAY:
+ case ACTION_T_RANDOM_YELL:
+ case ACTION_T_RANDOM_TEXTEMOTE:
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u currently unused ACTION type. Did you forget to update database?", i, j+1);
+ break;
+
+ case ACTION_T_SET_ACTIVE:
+ case ACTION_T_SET_AGGRESSIVE:
+ case ACTION_T_ATTACK_START_PULSE:
+ case ACTION_T_SUMMON_GO:
+ break;
+
+ default:
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i, j+1, temp.action[j].type);
+ break;
+ }
+ }
+
+ //Add to list
+ m_CreatureEventAI_Event_Map[creature_id].push_back(temp);
+ ++Count;
+
+ if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(temp.creature_id))
+ {
+ if(!cInfo->AIName || !cInfo->AIName[0])
+ {
+ //sLog.outErrorDb("CreatureEventAI: Creature Entry %u has EventAI script but its AIName is empty. Set to EventAI as default.", cInfo->Entry);
+ size_t len = strlen("EventAI")+1;
+ const_cast<CreatureInfo*>(cInfo)->AIName = new char[len];
+ strncpy(const_cast<char*>(cInfo->AIName), "EventAI", len);
+ }
+ if(strcmp(cInfo->AIName, "EventAI"))
+ {
+ //sLog.outErrorDb("CreatureEventAI: Creature Entry %u has EventAI script but it has AIName %s. EventAI script will be overriden.", cInfo->Entry, cInfo->AIName);
+ }
+ if(cInfo->ScriptID)
+ {
+ //sLog.outErrorDb("CreatureEventAI: Creature Entry %u has EventAI script but it also has C++ script. EventAI script will be overriden.", cInfo->Entry);
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u CreatureEventAI scripts", Count);
+ }else
+ {
+ barGoLink bar(1);
+ bar.step();
+ sLog.outString();
+ sLog.outString(">> Loaded 0 CreatureEventAI scripts. DB table `creature_ai_scripts` is empty.");
+ }
+}
diff --git a/src/game/CreatureEventAIMgr.h b/src/game/CreatureEventAIMgr.h
new file mode 100644
index 00000000000..b4672460cc6
--- /dev/null
+++ b/src/game/CreatureEventAIMgr.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MANGOS_CREATURE_EAI_MGR_H
+#define MANGOS_CREATURE_EAI_MGR_H
+
+#include "Common.h"
+#include "CreatureEventAI.h"
+
+class CreatureEventAIMgr
+{
+ public:
+ CreatureEventAIMgr(){};
+ ~CreatureEventAIMgr(){};
+
+ void LoadCreatureEventAI_Texts();
+ void LoadCreatureEventAI_Summons();
+ void LoadCreatureEventAI_Scripts();
+
+ CreatureEventAI_Event_Map const& GetCreatureEventAIMap() const { return m_CreatureEventAI_Event_Map; }
+ CreatureEventAI_Summon_Map const& GetCreatureEventAISummonMap() const { return m_CreatureEventAI_Summon_Map; }
+ CreatureEventAI_TextMap const& GetCreatureEventAITextMap() const { return m_CreatureEventAI_TextMap; }
+
+ private:
+ CreatureEventAI_Event_Map m_CreatureEventAI_Event_Map;
+ CreatureEventAI_Summon_Map m_CreatureEventAI_Summon_Map;
+ CreatureEventAI_TextMap m_CreatureEventAI_TextMap;
+};
+
+#define CreatureEAI_Mgr MaNGOS::Singleton<CreatureEventAIMgr>::Instance()
+#endif
diff --git a/src/game/CreatureGroups.cpp b/src/game/CreatureGroups.cpp
index 3b7a27cdab5..45e1c7ee11c 100644
--- a/src/game/CreatureGroups.cpp
+++ b/src/game/CreatureGroups.cpp
@@ -115,8 +115,8 @@ void CreatureGroupManager::LoadCreatureFormations()
//If creature is group leader we may skip loading of dist/angle
if(group_member->leaderGUID != memberGUID)
{
- group_member->follow_dist = fields[2].GetUInt32();
- group_member->follow_angle = fields[3].GetUInt32();
+ group_member->follow_dist = fields[2].GetFloat();
+ group_member->follow_angle = fields[3].GetFloat() * M_PI / 180;
}
// check data correctness
diff --git a/src/game/DBCEnums.h b/src/game/DBCEnums.h
new file mode 100644
index 00000000000..44ab34d7a11
--- /dev/null
+++ b/src/game/DBCEnums.h
@@ -0,0 +1,331 @@
+/*
+* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef DBCENUMS_H
+#define DBCENUMS_H
+
+// client supported max level for player/pets/etc. Avoid overflow or client stability affected.
+// also see GT_MAX_LEVEL define
+#define MAX_LEVEL 100
+
+// Server side limitation. Base at used code requirements.
+// also see MAX_LEVEL and GT_MAX_LEVEL define
+#define STRONG_MAX_LEVEL 255
+
+enum AreaTeams
+{
+ AREATEAM_NONE = 0,
+ AREATEAM_ALLY = 2,
+ AREATEAM_HORDE = 4
+};
+
+enum AchievementFactionFlags
+{
+ ACHIEVEMENT_FACTION_FLAG_HORDE = 0x00000000,
+ ACHIEVEMENT_FACTION_FLAG_ALLIANCE = 0x00000001,
+};
+
+enum AchievementFlags
+{
+ ACHIEVEMENT_FLAG_COUNTER = 0x00000001, // Just count statistic (never stop and complete)
+ ACHIEVEMENT_FLAG_UNK2 = 0x00000002, // not used
+ ACHIEVEMENT_FLAG_STORE_MAX_VALUE = 0x00000004, // Store only max value? used only in "Reach level xx"
+ ACHIEVEMENT_FLAG_SUMM = 0x00000008, // Use summ criteria value from all reqirements (and calculate max value)
+ ACHIEVEMENT_FLAG_MAX_USED = 0x00000010, // Show max criteria (and calculate max value ??)
+ ACHIEVEMENT_FLAG_REQ_COUNT = 0x00000020, // Use not zero req count (and calculate max value)
+ ACHIEVEMENT_FLAG_AVERAGE = 0x00000040, // Show as average value (value / time_in_days) depend from other flag (by def use last criteria value)
+ ACHIEVEMENT_FLAG_BAR = 0x00000080, // Show as progress bar (value / max vale) depend from other flag (by def use last criteria value)
+ ACHIEVEMENT_FLAG_REALM_FIRST_REACH = 0x00000100, //
+ ACHIEVEMENT_FLAG_REALM_FIRST_KILL = 0x00000200, //
+};
+
+enum AchievementCriteriaCondition
+{
+ ACHIEVEMENT_CRITERIA_CONDITION_NONE = 0,
+ ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH = 1,
+ ACHIEVEMENT_CRITERIA_CONDITION_UNK1 = 2, // only used in "Complete a daily quest every day for five consecutive days"
+ ACHIEVEMENT_CRITERIA_CONDITION_MAP = 3, // requires you to be on specific map
+ ACHIEVEMENT_CRITERIA_CONDITION_NO_LOOSE = 4, // only used in "Win 10 arenas without losing"
+ ACHIEVEMENT_CRITERIA_CONDITION_UNK2 = 9, // unk
+ ACHIEVEMENT_CRITERIA_CONDITION_UNK3 = 13, // unk
+};
+
+enum AchievementCriteriaCompletionFlags
+{
+ ACHIEVEMENT_CRITERIA_FLAG_SHOW_PROGRESS_BAR = 0x00000001, // Show progress as bar
+ ACHIEVEMENT_CRITERIA_FLAG_HIDE_CRITERIA = 0x00000002, // Not show criteria in client
+ ACHIEVEMENT_CRITERIA_FLAG_UNK3 = 0x00000004, // BG related??
+ ACHIEVEMENT_CRITERIA_FLAG_UNK4 = 0x00000008, //
+ ACHIEVEMENT_CRITERIA_FLAG_UNK5 = 0x00000010, // not used
+ ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER = 0x00000020, // Displays counter as money
+};
+
+enum AchievementCriteriaGroupFlags
+{
+ // you mustn't be in a group while fulfilling this achievement
+ ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP = 2,
+};
+
+enum AchievementCriteriaTypes
+{
+ ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0,
+ ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1,
+ ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5,
+ ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7,
+ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8,
+ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9,
+ // you have to complete a daily quest x times in a row
+ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10,
+ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11,
+ ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13,
+ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14,
+ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND= 15,
+ ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP= 16,
+ ACHIEVEMENT_CRITERIA_TYPE_DEATH= 17,
+ ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18,
+ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19,
+ ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20,
+ ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER = 23,
+ ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24,
+ ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26,
+ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27,
+ ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28,
+ ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL= 29,
+ ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30,
+ ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31,
+ ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32,
+ ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33,
+ ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34,
+ // TODO: this criteria has additional conditions which can not be found in the dbcs
+ ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL = 35,
+ ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36,
+ // TODO: the archievements 1162 and 1163 requires a special rating which can't be found in the dbc
+ ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38,
+ ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39,
+ ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40,
+ ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41,
+ ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM= 42,
+ ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43,
+ ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK= 44,
+ ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT= 45,
+ ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION= 46,
+ ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION= 47,
+ // noted: rewarded as soon as the player payed, not at taking place at the seat
+ ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP= 48,
+ ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49,
+ // TODO: itemlevel is mentioned in text but not present in dbc
+ ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50,
+ ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT= 51,
+ ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52,
+ ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53,
+ ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54,
+ ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55,
+ // TODO: in some cases map not present, and in some cases need do without die
+ ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56,
+ ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57,
+ ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS = 59,
+ ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS = 60,
+ ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS = 61,
+ ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD = 62,
+ ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING = 63,
+ ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER = 65,
+ ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL = 66,
+ ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67,
+ ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68,
+ ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2= 69,
+ ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL= 70,
+ ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72,
+ // TODO: title id is not mentioned in dbc
+ ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE = 74,
+ ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS= 75,
+ ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76,
+ ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL = 77,
+ // TODO: creature type (demon, undead etc.) is not stored in dbc
+ ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE = 78,
+ ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS= 80,
+ ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION= 82,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID= 83,
+ ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS= 84,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD = 85,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED = 86,
+ ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION = 87,
+ ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION = 88,
+ ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS = 89,
+ ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM = 90,
+ ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM = 91,
+ ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED = 93,
+ ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED = 94,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH = 95,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR = 99,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT = 101,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED = 102,
+ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED = 103,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED = 104,
+ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED = 105,
+ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED = 106,
+ ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED = 107,
+ ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN = 108,
+ ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109,
+ // TODO: target entry is missing
+ ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110,
+ ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE= 112,
+ ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113,
+ ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS = 114,
+ // 0..114 => 115 criteria types total
+ ACHIEVEMENT_CRITERIA_TYPE_TOTAL = 115,
+};
+
+enum AreaFlags
+{
+ AREA_FLAG_SNOW = 0x00000001, // snow (only Dun Morogh, Naxxramas, Razorfen Downs and Winterspring)
+ AREA_FLAG_UNK1 = 0x00000002, // may be necropolis?
+ AREA_FLAG_UNK2 = 0x00000004, // Only used for areas on map 571 (development before)
+ AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // city and city subsones
+ AREA_FLAG_UNK3 = 0x00000010, // can't find common meaning
+ AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag?
+ AREA_FLAG_UNK4 = 0x00000040, // many zones have this flag
+ AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas
+ AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag
+ AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?)
+ AREA_FLAG_OUTLAND = 0x00000400, // expansion zones? (only Eye of the Storm not have this flag, but have 0x00004000 flag)
+ AREA_FLAG_SANCTUARY = 0x00000800, // sanctuary area (PvP disabled)
+ AREA_FLAG_NEED_FLY = 0x00001000, // only Netherwing Ledge, Socrethar's Seat, Tempest Keep, The Arcatraz, The Botanica, The Mechanar, Sorrow Wing Point, Dragonspine Ridge, Netherwing Mines, Dragonmaw Base Camp, Dragonmaw Skyway
+ AREA_FLAG_UNUSED1 = 0x00002000, // not used now (no area/zones with this flag set in 3.0.3)
+ AREA_FLAG_OUTLAND2 = 0x00004000, // expansion zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag)
+ AREA_FLAG_PVP = 0x00008000, // pvp objective area? (Death's Door also has this flag although it's no pvp object area)
+ AREA_FLAG_ARENA_INSTANCE = 0x00010000, // used by instanced arenas only
+ AREA_FLAG_UNUSED2 = 0x00020000, // not used now (no area/zones with this flag set in 3.0.3)
+ AREA_FLAG_UNK5 = 0x00040000, // only used for Amani Pass, Hatchet Hills
+ AREA_FLAG_UNK6 = 0x00080000, // Valgarde and Acherus: The Ebon Hold
+ AREA_FLAG_LOWLEVEL = 0x00100000, // used for some starting areas with area_level <=15
+ AREA_FLAG_TOWN = 0x00200000, // small towns with Inn
+ AREA_FLAG_UNK7 = 0x00400000, // Warsong Hold, Acherus: The Ebon Hold, New Agamand Inn, Vengeance Landing Inn
+ AREA_FLAG_UNK8 = 0x00800000, // Westguard Inn, Acherus: The Ebon Hold, Valgarde
+ AREA_FLAG_OUTDOOR_PVP = 0x01000000, // Wintergrasp and it's subzones
+ AREA_FLAG_UNK9 = 0x02000000, // unknown
+ AREA_FLAG_UNK10 = 0x04000000, // unknown
+ AREA_FLAG_OUTDOOR_PVP2 = 0x08000000 // Wintergrasp and it's subzones
+};
+
+enum FactionTemplateFlags
+{
+ FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats
+};
+
+enum FactionMasks
+{
+ FACTION_MASK_PLAYER = 1, // any player
+ FACTION_MASK_ALLIANCE = 2, // player or creature from alliance team
+ FACTION_MASK_HORDE = 4, // player or creature from horde team
+ FACTION_MASK_MONSTER = 8 // aggressive creature from monster team
+ // if none flags set then non-aggressive creature
+};
+
+enum MapTypes
+{
+ MAP_COMMON = 0,
+ MAP_INSTANCE = 1,
+ MAP_RAID = 2,
+ MAP_BATTLEGROUND = 3,
+ MAP_ARENA = 4
+};
+
+enum AbilytyLearnType
+{
+ ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1,
+ ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2
+};
+
+enum ItemEnchantmentType
+{
+ ITEM_ENCHANTMENT_TYPE_NONE = 0,
+ ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL = 1,
+ ITEM_ENCHANTMENT_TYPE_DAMAGE = 2,
+ ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL = 3,
+ ITEM_ENCHANTMENT_TYPE_RESISTANCE = 4,
+ ITEM_ENCHANTMENT_TYPE_STAT = 5,
+ ITEM_ENCHANTMENT_TYPE_TOTEM = 6,
+ ITEM_ENCHANTMENT_TYPE_USE_SPELL = 7,
+ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET = 8
+};
+
+enum TotemCategoryType
+{
+ TOTEM_CATEGORY_TYPE_KNIFE = 1,
+ TOTEM_CATEGORY_TYPE_TOTEM = 2,
+ TOTEM_CATEGORY_TYPE_ROD = 3,
+ TOTEM_CATEGORY_TYPE_PICK = 21,
+ TOTEM_CATEGORY_TYPE_STONE = 22,
+ TOTEM_CATEGORY_TYPE_HAMMER = 23,
+ TOTEM_CATEGORY_TYPE_SPANNER = 24
+};
+
+// SummonProperties.dbc, col 1
+enum SummonPropGroup
+{
+ SUMMON_PROP_GROUP_UNKNOWN1 = 0, // 1160 spells in 3.0.3
+ SUMMON_PROP_GROUP_UNKNOWN2 = 1, // 861 spells in 3.0.3
+ SUMMON_PROP_GROUP_PETS = 2, // 52 spells in 3.0.3, pets mostly
+ SUMMON_PROP_GROUP_CONTROLLABLE = 3, // 13 spells in 3.0.3, mostly controllable
+ SUMMON_PROP_GROUP_UNKNOWN3 = 4 // 86 spells in 3.0.3, taxi/mounts
+};
+
+// SummonProperties.dbc, col 3
+enum SummonPropType
+{
+ SUMMON_PROP_TYPE_UNKNOWN = 0, // different summons, 1330 spells in 3.0.3
+ SUMMON_PROP_TYPE_SUMMON = 1, // generic summons, 49 spells in 3.0.3
+ SUMMON_PROP_TYPE_GUARDIAN = 2, // summon guardian, 393 spells in 3.0.3
+ SUMMON_PROP_TYPE_ARMY = 3, // summon army, 5 spells in 3.0.3
+ SUMMON_PROP_TYPE_TOTEM = 4, // summon totem, 169 spells in 3.0.3
+ SUMMON_PROP_TYPE_CRITTER = 5, // critter/minipet, 195 spells in 3.0.3
+ SUMMON_PROP_TYPE_DK = 6, // summon DRW/Ghoul, 2 spells in 3.0.3
+ SUMMON_PROP_TYPE_BOMB = 7, // summon bot/bomb, 4 spells in 3.0.3
+ SUMMON_PROP_TYPE_PHASING = 8, // something todo with DK prequest line, 2 spells in 3.0.3
+ SUMMON_PROP_TYPE_SIEGE_VEH = 9, // summon different vehicles, 14 spells in 3.0.3
+ SUMMON_PROP_TYPE_DRAKE_VEH = 10, // summon drake (vehicle), 3 spells
+ SUMMON_PROP_TYPE_LIGHTWELL = 11 // summon lightwell, 6 spells in 3.0.3
+};
+
+// SummonProperties.dbc, col 5
+enum SummonPropFlags
+{
+ SUMMON_PROP_FLAG_NONE = 0x0000, // 1342 spells in 3.0.3
+ SUMMON_PROP_FLAG_UNK1 = 0x0001, // 75 spells in 3.0.3, something unfriendly
+ SUMMON_PROP_FLAG_UNK2 = 0x0002, // 616 spells in 3.0.3, something friendly
+ SUMMON_PROP_FLAG_UNK3 = 0x0004, // 22 spells in 3.0.3, no idea...
+ SUMMON_PROP_FLAG_UNK4 = 0x0008, // 49 spells in 3.0.3, some mounts
+ SUMMON_PROP_FLAG_UNK5 = 0x0010, // 25 spells in 3.0.3, quest related?
+ SUMMON_PROP_FLAG_UNK6 = 0x0020, // 0 spells in 3.0.3, unused
+ SUMMON_PROP_FLAG_UNK7 = 0x0040, // 12 spells in 3.0.3, no idea
+ SUMMON_PROP_FLAG_UNK8 = 0x0080, // 4 spells in 3.0.3, no idea
+ SUMMON_PROP_FLAG_UNK9 = 0x0100, // 51 spells in 3.0.3, no idea, many quest related
+ SUMMON_PROP_FLAG_UNK10 = 0x0200, // 51 spells in 3.0.3, something defensive
+ SUMMON_PROP_FLAG_UNK11 = 0x0400, // 3 spells, requires something near?
+ SUMMON_PROP_FLAG_UNK12 = 0x0800, // 30 spells in 3.0.3, no idea
+ SUMMON_PROP_FLAG_UNK13 = 0x1000, // 8 spells in 3.0.3, siege vehicle
+ SUMMON_PROP_FLAG_UNK14 = 0x2000, // 2 spells in 3.0.3, escort?
+};
+
+#endif
+
diff --git a/src/game/DBCStores.cpp b/src/game/DBCStores.cpp
new file mode 100644
index 00000000000..ff193abaad6
--- /dev/null
+++ b/src/game/DBCStores.cpp
@@ -0,0 +1,763 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "DBCStores.h"
+#include "Policies/SingletonImp.h"
+#include "Log.h"
+#include "ProgressBar.h"
+#include "SharedDefines.h"
+
+#include "DBCfmt.h"
+
+#include <map>
+
+typedef std::map<uint16,uint32> AreaFlagByAreaID;
+typedef std::map<uint32,uint32> AreaFlagByMapID;
+
+DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
+DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
+DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt);
+static AreaFlagByAreaID sAreaFlagByAreaID;
+static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
+
+DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt);
+DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
+DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
+DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt);
+DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEntryfmt);
+DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryfmt);
+DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore(BarberShopStyleEntryfmt);
+DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore(CharStartOutfitEntryfmt);
+DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
+DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
+DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
+DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
+DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt);
+DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
+DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
+DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt);
+DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt);
+DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt);
+
+DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore(DurabilityQualityfmt);
+DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCostsfmt);
+
+DBCStorage <EmotesEntry> sEmotesStore(EmotesEntryfmt);
+DBCStorage <EmotesTextEntry> sEmotesTextStore(EmotesTextEntryfmt);
+
+typedef std::map<uint32,SimpleFactionsList> FactionTeamMap;
+static FactionTeamMap sFactionTeamMap;
+DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt);
+DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt);
+
+DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt);
+
+DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt);
+DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore(GlyphPropertiesfmt);
+DBCStorage <GlyphSlotEntry> sGlyphSlotStore(GlyphSlotfmt);
+
+DBCStorage <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore(GtBarberShopCostBasefmt);
+DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore(GtCombatRatingsfmt);
+DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore(GtChanceToMeleeCritBasefmt);
+DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore(GtChanceToMeleeCritfmt);
+DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore(GtChanceToSpellCritBasefmt);
+DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore(GtChanceToSpellCritfmt);
+DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt);
+//DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore(GtOCTRegenMPfmt); -- not used currently
+DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore(GtRegenHPPerSptfmt);
+DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt);
+
+DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
+
+DBCStorage <ItemEntry> sItemStore(Itemfmt);
+DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
+//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
+//DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently
+DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
+DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore(ItemLimitCategoryEntryfmt);
+DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt);
+DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt);
+DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt);
+
+DBCStorage <LockEntry> sLockStore(LockEntryfmt);
+
+DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt);
+DBCStorage <MapEntry> sMapStore(MapEntryfmt);
+DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt);
+
+DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt);
+
+DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore(RandomPropertiesPointsfmt);
+DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore(ScalingStatDistributionfmt);
+DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore(ScalingStatValuesfmt);
+
+DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt);
+DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt);
+
+DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
+
+DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt);
+DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt);
+DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
+SpellCategoryStore sSpellCategoryStore;
+PetFamilySpellsStore sPetFamilySpellsStore;
+
+DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore(SpellCastTimefmt);
+DBCStorage <SpellDurationEntry> sSpellDurationStore(SpellDurationfmt);
+DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore(SpellFocusObjectfmt);
+DBCStorage <SpellRadiusEntry> sSpellRadiusStore(SpellRadiusfmt);
+DBCStorage <SpellRangeEntry> sSpellRangeStore(SpellRangefmt);
+DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore(SpellRuneCostfmt);
+DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt);
+DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
+DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
+DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
+TalentSpellPosMap sTalentSpellPosMap;
+DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt);
+
+// store absolute bit position for first rank for talent inspect
+typedef std::map<uint32,uint32> TalentInspectMap;
+static TalentInspectMap sTalentPosInInspect;
+static TalentInspectMap sTalentTabSizeInInspect;
+static uint32 sTalentTabPages[12/*MAX_CLASSES*/][3];
+
+DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt);
+TaxiMask sTaxiNodesMask;
+TaxiMask sOldContinentsNodesMask;
+
+// DBC used only for initialization sTaxiPathSetBySource at startup.
+TaxiPathSetBySource sTaxiPathSetBySource;
+DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt);
+
+// DBC used only for initialization sTaxiPathSetBySource at startup.
+TaxiPathNodesByPath sTaxiPathNodesByPath;
+
+static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
+DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
+DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt);
+DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt);
+DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
+DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
+DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt);
+
+typedef std::list<std::string> StoreProblemList;
+
+static bool LoadDBC_assert_print(uint32 fsize,uint32 rsize, const std::string& filename)
+{
+ sLog.outError("ERROR: Size of '%s' setted by format string (%u) not equal size of C++ structure (%u).",filename.c_str(),fsize,rsize);
+
+ // assert must fail after function call
+ return false;
+}
+
+template<class T>
+inline void LoadDBC(uint32& availableDbcLocales,barGoLink& bar, StoreProblemList& errlist, DBCStorage<T>& storage, const std::string& dbc_path, const std::string& filename)
+{
+ // compatibility format and C++ structure sizes
+ assert(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()),sizeof(T),filename));
+
+ std::string dbc_filename = dbc_path + filename;
+ if(storage.Load(dbc_filename.c_str()))
+ {
+ bar.step();
+ for(uint8 i = 0; i < MAX_LOCALE; ++i)
+ {
+ if(!(availableDbcLocales & (1 << i)))
+ continue;
+
+ std::string dbc_filename_loc = dbc_path + localeNames[i] + "/" + filename;
+ if(!storage.LoadStringsFrom(dbc_filename_loc.c_str()))
+ availableDbcLocales &= ~(1<<i); // mark as not available for speedup next checks
+ }
+ }
+ else
+ {
+ // sort problematic dbc to (1) non compatible and (2) non-existed
+ FILE * f=fopen(dbc_filename.c_str(),"rb");
+ if(f)
+ {
+ char buf[100];
+ snprintf(buf,100," (exist, but have %d fields instead %d) Wrong client version DBC file?",storage.GetFieldCount(),strlen(storage.GetFormat()));
+ errlist.push_back(dbc_filename + buf);
+ fclose(f);
+ }
+ else
+ errlist.push_back(dbc_filename);
+ }
+}
+
+void LoadDBCStores(const std::string& dataPath)
+{
+ std::string dbcPath = dataPath+"dbc/";
+
+ const uint32 DBCFilesCount = 78;
+
+ barGoLink bar( DBCFilesCount );
+
+ StoreProblemList bad_dbc_files;
+ uint32 availableDbcLocales = 0xFFFFFFFF;
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaStore, dbcPath,"AreaTable.dbc");
+
+ // must be after sAreaStore loading
+ for(uint32 i = 0; i < sAreaStore.GetNumRows(); ++i) // areaflag numbered from 0
+ {
+ if(AreaTableEntry const* area = sAreaStore.LookupEntry(i))
+ {
+ // fill AreaId->DBC records
+ sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID),area->exploreFlag));
+
+ // fill MapId->DBC records ( skip sub zones and continents )
+ if(area->zone==0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530 && area->mapid != 571 )
+ sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid,area->exploreFlag));
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAchievementStore, dbcPath,"Achievement.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAchievementCriteriaStore, dbcPath,"Achievement_Criteria.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaTriggerStore, dbcPath,"AreaTrigger.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaGroupStore, dbcPath,"AreaGroup.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaPOIStore, dbcPath,"AreaPOI.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAuctionHouseStore, dbcPath,"AuctionHouse.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBankBagSlotPricesStore, dbcPath,"BankBagSlotPrices.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBattlemasterListStore, dbcPath,"BattlemasterList.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBarberShopStyleStore, dbcPath,"BarberShopStyle.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharStartOutfitStore, dbcPath,"CharStartOutfit.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharTitlesStore, dbcPath,"CharTitles.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChatChannelsStore, dbcPath,"ChatChannels.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrClassesStore, dbcPath,"ChrClasses.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrRacesStore, dbcPath,"ChrRaces.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCinematicSequencesStore, dbcPath,"CinematicSequences.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoStore, dbcPath,"CreatureDisplayInfo.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureFamilyStore, dbcPath,"CreatureFamily.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureSpellDataStore, dbcPath,"CreatureSpellData.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureTypeStore, dbcPath,"CreatureType.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCurrencyTypesStore, dbcPath,"CurrencyTypes.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityCostsStore, dbcPath,"DurabilityCosts.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityQualityStore, dbcPath,"DurabilityQuality.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sEmotesStore, dbcPath,"Emotes.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sEmotesTextStore, dbcPath,"EmotesText.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionStore, dbcPath,"Faction.dbc");
+ for (uint32 i=0;i<sFactionStore.GetNumRows(); ++i)
+ {
+ FactionEntry const * faction = sFactionStore.LookupEntry(i);
+ if (faction && faction->team)
+ {
+ SimpleFactionsList &flist = sFactionTeamMap[faction->team];
+ flist.push_back(i);
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionTemplateStore, dbcPath,"FactionTemplate.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGameObjectDisplayInfoStore, dbcPath,"GameObjectDisplayInfo.dbc");
+ for(uint32 i = 0; i < sGameObjectDisplayInfoStore.GetNumRows(); ++i)
+ {
+ if(GameObjectDisplayInfoEntry const * info = sGameObjectDisplayInfoStore.LookupEntry(i))
+ {
+ if(info->maxX < info->minX)
+ std::swap(*(float*)(&info->maxX), *(float*)(&info->minX));
+ if(info->maxY < info->minY)
+ std::swap(*(float*)(&info->maxY), *(float*)(&info->minY));
+ if(info->maxZ < info->minZ)
+ std::swap(*(float*)(&info->maxZ), *(float*)(&info->minZ));
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGemPropertiesStore, dbcPath,"GemProperties.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGlyphPropertiesStore, dbcPath,"GlyphProperties.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGlyphSlotStore, dbcPath,"GlyphSlot.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtBarberShopCostBaseStore,dbcPath,"gtBarberShopCostBase.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtCombatRatingsStore, dbcPath,"gtCombatRatings.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToMeleeCritBaseStore, dbcPath,"gtChanceToMeleeCritBase.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToMeleeCritStore, dbcPath,"gtChanceToMeleeCrit.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToSpellCritBaseStore, dbcPath,"gtChanceToSpellCritBase.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToSpellCritStore, dbcPath,"gtChanceToSpellCrit.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenHPStore, dbcPath,"gtOCTRegenHP.dbc");
+ //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenMPStore, dbcPath,"gtOCTRegenMP.dbc"); -- not used currently
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenHPPerSptStore, dbcPath,"gtRegenHPPerSpt.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenMPPerSptStore, dbcPath,"gtRegenMPPerSpt.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sHolidaysStore, dbcPath,"Holidays.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemStore, dbcPath,"Item.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemBagFamilyStore, dbcPath,"ItemBagFamily.dbc");
+ //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemDisplayInfoStore, dbcPath,"ItemDisplayInfo.dbc"); -- not used currently
+ //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemCondExtCostsStore, dbcPath,"ItemCondExtCosts.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemExtendedCostStore, dbcPath,"ItemExtendedCost.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemLimitCategoryStore, dbcPath,"ItemLimitCategory.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomPropertiesStore,dbcPath,"ItemRandomProperties.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomSuffixStore, dbcPath,"ItemRandomSuffix.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemSetStore, dbcPath,"ItemSet.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sLockStore, dbcPath,"Lock.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMailTemplateStore, dbcPath,"MailTemplate.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapStore, dbcPath,"Map.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMovieStore, dbcPath,"Movie.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestSortStore, dbcPath,"QuestSort.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sRandomPropertiesPointsStore, dbcPath,"RandPropPoints.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sScalingStatDistributionStore, dbcPath,"ScalingStatDistribution.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sScalingStatValuesStore, dbcPath,"ScalingStatValues.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineStore, dbcPath,"SkillLine.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineAbilityStore, dbcPath,"SkillLineAbility.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSoundEntriesStore, dbcPath,"SoundEntries.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellStore, dbcPath,"Spell.dbc");
+ for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
+ {
+ SpellEntry const * spell = sSpellStore.LookupEntry(i);
+ if(spell && spell->Category)
+ sSpellCategoryStore[spell->Category].insert(i);
+
+ /*// DBC not support uint64 fields but SpellEntry have SpellFamilyFlags mapped at 2 uint32 fields
+ // uint32 field already converted to bigendian if need, but must be swapped for correct uint64 bigendian view
+ #if TRINITY_ENDIAN == TRINITY_BIGENDIAN
+ std::swap(*((uint32*)(&spell->SpellFamilyFlags)),*(((uint32*)(&spell->SpellFamilyFlags))+1));
+ #endif*/
+ }
+
+ for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
+ {
+ SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j);
+
+ if(!skillLine)
+ continue;
+
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
+
+ if(spellInfo && (spellInfo->Attributes & 0x1D0) == 0x1D0)
+ {
+ for (uint32 i = 1; i < sCreatureFamilyStore.GetNumRows(); ++i)
+ {
+ CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(i);
+ if(!cFamily)
+ continue;
+
+ if(skillLine->skillId != cFamily->skillLine[0] && skillLine->skillId != cFamily->skillLine[1])
+ continue;
+ if(spellInfo->spellLevel)
+ continue;
+
+ if(skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL)
+ continue;
+
+ sPetFamilySpellsStore[i].insert(spellInfo->Id);
+ }
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellCastTimesStore, dbcPath,"SpellCastTimes.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellDurationStore, dbcPath,"SpellDuration.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellFocusObjectStore, dbcPath,"SpellFocusObject.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellItemEnchantmentStore,dbcPath,"SpellItemEnchantment.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellItemEnchantmentConditionStore,dbcPath,"SpellItemEnchantmentCondition.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRadiusStore, dbcPath,"SpellRadius.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRangeStore, dbcPath,"SpellRange.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRuneCostStore, dbcPath,"SpellRuneCost.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellShapeshiftStore, dbcPath,"SpellShapeshiftForm.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sStableSlotPricesStore, dbcPath,"StableSlotPrices.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSummonPropertiesStore, dbcPath,"SummonProperties.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentStore, dbcPath,"Talent.dbc");
+
+ // create talent spells set
+ for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
+ {
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
+ if (!talentInfo) continue;
+ for (int j = 0; j < MAX_TALENT_RANK; j++)
+ if(talentInfo->RankID[j])
+ sTalentSpellPosMap[talentInfo->RankID[j]] = TalentSpellPos(i,j);
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentTabStore, dbcPath,"TalentTab.dbc");
+
+ // prepare fast data access to bit pos of talent ranks for use at inspecting
+ {
+ // fill table by amount of talent ranks and fill sTalentTabBitSizeInInspect
+ // store in with (row,col,talent)->size key for correct sorting by (row,col)
+ typedef std::map<uint32,uint32> TalentBitSize;
+ TalentBitSize sTalentBitSize;
+ for(uint32 i = 1; i < sTalentStore.GetNumRows(); ++i)
+ {
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
+ if (!talentInfo) continue;
+
+ TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
+ if(!talentTabInfo)
+ continue;
+
+ // find talent rank
+ uint32 curtalent_maxrank = 0;
+ for(uint32 k = MAX_TALENT_RANK; k > 0; --k)
+ {
+ if(talentInfo->RankID[k-1])
+ {
+ curtalent_maxrank = k;
+ break;
+ }
+ }
+
+ sTalentBitSize[(talentInfo->Row<<24) + (talentInfo->Col<<16)+talentInfo->TalentID] = curtalent_maxrank;
+ sTalentTabSizeInInspect[talentInfo->TalentTab] += curtalent_maxrank;
+ }
+
+ // now have all max ranks (and then bit amount used for store talent ranks in inspect)
+ for(uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId)
+ {
+ TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentTabId );
+ if(!talentTabInfo)
+ continue;
+
+ // prevent memory corruption; otherwise cls will become 12 below
+ if ((talentTabInfo->ClassMask & CLASSMASK_ALL_PLAYABLE)==0)
+ continue;
+
+ // store class talent tab pages
+ uint32 cls = 1;
+ for(uint32 m=1;!(m & talentTabInfo->ClassMask) && cls < MAX_CLASSES;m <<=1, ++cls) {}
+
+ sTalentTabPages[cls][talentTabInfo->tabpage]=talentTabId;
+
+ // add total amount bits for first rank starting from talent tab first talent rank pos.
+ uint32 pos = 0;
+ for(TalentBitSize::iterator itr = sTalentBitSize.begin(); itr != sTalentBitSize.end(); ++itr)
+ {
+ uint32 talentId = itr->first & 0xFFFF;
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentId );
+ if(!talentInfo)
+ continue;
+
+ if(talentInfo->TalentTab != talentTabId)
+ continue;
+
+ sTalentPosInInspect[talentId] = pos;
+ pos+= itr->second;
+ }
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiNodesStore, dbcPath,"TaxiNodes.dbc");
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiPathStore, dbcPath,"TaxiPath.dbc");
+ for(uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i)
+ if(TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(i))
+ sTaxiPathSetBySource[entry->from][entry->to] = TaxiPathBySourceAndDestination(entry->ID,entry->price);
+ uint32 pathCount = sTaxiPathStore.GetNumRows();
+
+ //## TaxiPathNode.dbc ## Loaded only for initialization different structures
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiPathNodeStore, dbcPath,"TaxiPathNode.dbc");
+ // Calculate path nodes count
+ std::vector<uint32> pathLength;
+ pathLength.resize(pathCount); // 0 and some other indexes not used
+ for(uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
+ if(TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
+ {
+ if (pathLength[entry->path] < entry->index + 1)
+ pathLength[entry->path] = entry->index + 1;
+ }
+ // Set path length
+ sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used
+ for(uint32 i = 1; i < sTaxiPathNodesByPath.size(); ++i)
+ sTaxiPathNodesByPath[i].resize(pathLength[i]);
+ // fill data
+ for(uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
+ if(TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
+ sTaxiPathNodesByPath[entry->path][entry->index] = TaxiPathNode(entry->mapid,entry->x,entry->y,entry->z,entry->actionFlag,entry->delay);
+ sTaxiPathNodeStore.Clear();
+
+ // Initialize global taxinodes mask
+ // include existed nodes that have at least single not spell base (scripted) path
+ {
+ std::set<uint32> spellPaths;
+ for(uint32 i = 1; i < sSpellStore.GetNumRows (); ++i)
+ if(SpellEntry const* sInfo = sSpellStore.LookupEntry (i))
+ for(int j=0; j < 3; ++j)
+ if(sInfo->Effect[j]==123 /*SPELL_EFFECT_SEND_TAXI*/)
+ spellPaths.insert(sInfo->EffectMiscValue[j]);
+
+ memset(sTaxiNodesMask,0,sizeof(sTaxiNodesMask));
+ memset(sOldContinentsNodesMask,0,sizeof(sTaxiNodesMask));
+ for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
+ {
+ TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
+ if(!node)
+ continue;
+
+ TaxiPathSetBySource::const_iterator src_i = sTaxiPathSetBySource.find(i);
+ if(src_i!=sTaxiPathSetBySource.end() && !src_i->second.empty())
+ {
+ bool ok = false;
+ for(TaxiPathSetForSource::const_iterator dest_i = src_i->second.begin();dest_i != src_i->second.end(); ++dest_i)
+ {
+ // not spell path
+ if(spellPaths.find(dest_i->second.ID)==spellPaths.end())
+ {
+ ok = true;
+ break;
+ }
+ }
+
+ if(!ok)
+ continue;
+ }
+
+ // valid taxi network node
+ uint8 field = (uint8)((i - 1) / 32);
+ uint32 submask = 1<<((i-1)%32);
+ sTaxiNodesMask[field] |= submask;
+
+ // old continent node (+ nodes virtually at old continents, check explicitly to avoid loading map files for zone info)
+ if (node->map_id < 2 || i == 82 || i == 83 || i == 93 || i == 94)
+ sOldContinentsNodesMask[field] |= submask;
+ }
+ }
+
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTotemCategoryStore, dbcPath,"TotemCategory.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sVehicleStore, dbcPath,"Vehicle.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sVehicleSeatStore, dbcPath,"VehicleSeat.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapAreaStore, dbcPath,"WorldMapArea.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapOverlayStore, dbcPath,"WorldMapOverlay.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldSafeLocsStore, dbcPath,"WorldSafeLocs.dbc");
+
+ // error checks
+ if(bad_dbc_files.size() >= DBCFilesCount )
+ {
+ sLog.outError("\nIncorrect DataDir value in Trinityd.conf or ALL required *.dbc files (%d) not found by path: %sdbc",DBCFilesCount,dataPath.c_str());
+ exit(1);
+ }
+ else if(!bad_dbc_files.empty() )
+ {
+ std::string str;
+ for(std::list<std::string>::iterator i = bad_dbc_files.begin(); i != bad_dbc_files.end(); ++i)
+ str += *i + "\n";
+
+ sLog.outError("\nSome required *.dbc files (%u from %d) not found or not compatible:\n%s",(uint32)bad_dbc_files.size(),DBCFilesCount,str.c_str());
+ exit(1);
+ }
+
+ // Check loaded DBC files proper version
+ if( !sSpellStore.LookupEntry(62735) || // last added spell in 3.0.9
+ !sMapStore.LookupEntry(624) || // last map added in 3.0.8a/3.0.9
+ !sGemPropertiesStore.LookupEntry(1557) || // last gem property added in 3.0.8a/3.0.9
+ !sItemExtendedCostStore.LookupEntry(2589) || // last item extended cost added in 3.0.8a/3.0.9
+ !sCharTitlesStore.LookupEntry(144) || // last char title added in 3.0.8a/3.0.9
+ !sAreaStore.LookupEntry(2769) || // last area (areaflag) added in 3.0.8a/3.0.9
+ !sItemStore.LookupEntry(45037) ) // last client known item added in 3.0.9
+ {
+ sLog.outError("\nYou have _outdated_ DBC files. Please extract correct versions from current using client.");
+ exit(1);
+ }
+
+ sLog.outString();
+ sLog.outString( ">> Initialized %d data stores", DBCFilesCount );
+}
+
+SimpleFactionsList const* GetFactionTeamList(uint32 faction)
+{
+ FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction);
+ if(itr==sFactionTeamMap.end())
+ return NULL;
+ return &itr->second;
+}
+
+char* GetPetName(uint32 petfamily, uint32 dbclang)
+{
+ if(!petfamily)
+ return NULL;
+ CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(petfamily);
+ if(!pet_family)
+ return NULL;
+ return pet_family->Name[dbclang]?pet_family->Name[dbclang]:NULL;
+}
+
+TalentSpellPos const* GetTalentSpellPos(uint32 spellId)
+{
+ TalentSpellPosMap::const_iterator itr = sTalentSpellPosMap.find(spellId);
+ if(itr==sTalentSpellPosMap.end())
+ return NULL;
+
+ return &itr->second;
+}
+
+uint32 GetTalentSpellCost(uint32 spellId)
+{
+ if(TalentSpellPos const* pos = GetTalentSpellPos(spellId))
+ return pos->rank+1;
+
+ return 0;
+}
+
+int32 GetAreaFlagByAreaID(uint32 area_id)
+{
+ AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
+ if(i == sAreaFlagByAreaID.end())
+ return -1;
+
+ return i->second;
+}
+
+AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
+{
+ int32 areaflag = GetAreaFlagByAreaID(area_id);
+ if(areaflag < 0)
+ return NULL;
+
+ return sAreaStore.LookupEntry(areaflag );
+}
+
+AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id)
+{
+ if(area_flag)
+ return sAreaStore.LookupEntry(area_flag);
+
+ if(MapEntry const* mapEntry = sMapStore.LookupEntry(map_id))
+ return GetAreaEntryByAreaID(mapEntry->linked_zone);
+
+ return NULL;
+}
+
+uint32 GetAreaFlagByMapId(uint32 mapid)
+{
+ AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid);
+ if(i == sAreaFlagByMapID.end())
+ return 0;
+ else
+ return i->second;
+}
+
+uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
+{
+ if(mapid != 530 && mapid != 571) // speed for most cases
+ return mapid;
+
+ if(WorldMapAreaEntry const* wma = sWorldMapAreaStore.LookupEntry(zoneId))
+ return wma->virtual_map_id >= 0 ? wma->virtual_map_id : wma->map_id;
+
+ return mapid;
+}
+
+ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId)
+{
+ mapid = GetVirtualMapForMapAndZone(mapid,zoneId);
+ if(mapid < 2)
+ return CONTENT_1_60;
+
+ MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
+ if(!mapEntry)
+ return CONTENT_1_60;
+
+ switch(mapEntry->Expansion())
+ {
+ default: return CONTENT_1_60;
+ case 1: return CONTENT_61_70;
+ case 2: return CONTENT_71_80;
+ }
+}
+
+ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id)
+{
+ // not sorted, numbering index from 0
+ for(uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
+ {
+ ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(i);
+ if(ch && ch->ChannelID == channel_id)
+ return ch;
+ }
+ return NULL;
+}
+
+bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId)
+{
+ if(requiredTotemCategoryId==0)
+ return true;
+ if(itemTotemCategoryId==0)
+ return false;
+
+ TotemCategoryEntry const* itemEntry = sTotemCategoryStore.LookupEntry(itemTotemCategoryId);
+ if(!itemEntry)
+ return false;
+ TotemCategoryEntry const* reqEntry = sTotemCategoryStore.LookupEntry(requiredTotemCategoryId);
+ if(!reqEntry)
+ return false;
+
+ if(itemEntry->categoryType!=reqEntry->categoryType)
+ return false;
+
+ return (itemEntry->categoryMask & reqEntry->categoryMask)==reqEntry->categoryMask;
+}
+
+void Zone2MapCoordinates(float& x,float& y,uint32 zone)
+{
+ WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
+
+ // if not listed then map coordinates (instance)
+ if(!maEntry)
+ return;
+
+ std::swap(x,y); // at client map coords swapped
+ x = x*((maEntry->x2-maEntry->x1)/100)+maEntry->x1;
+ y = y*((maEntry->y2-maEntry->y1)/100)+maEntry->y1; // client y coord from top to down
+}
+
+void Map2ZoneCoordinates(float& x,float& y,uint32 zone)
+{
+ WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
+
+ // if not listed then map coordinates (instance)
+ if(!maEntry)
+ return;
+
+ x = (x-maEntry->x1)/((maEntry->x2-maEntry->x1)/100);
+ y = (y-maEntry->y1)/((maEntry->y2-maEntry->y1)/100); // client y coord from top to down
+ std::swap(x,y); // client have map coords swapped
+}
+
+uint32 GetTalentInspectBitPosInTab(uint32 talentId)
+{
+ TalentInspectMap::const_iterator itr = sTalentPosInInspect.find(talentId);
+ if(itr == sTalentPosInInspect.end())
+ return 0;
+
+ return itr->second;
+}
+
+uint32 GetTalentTabInspectBitSize(uint32 talentTabId)
+{
+ TalentInspectMap::const_iterator itr = sTalentTabSizeInInspect.find(talentTabId);
+ if(itr == sTalentTabSizeInInspect.end())
+ return 0;
+
+ return itr->second;
+}
+
+uint32 const* GetTalentTabPages(uint32 cls)
+{
+ return sTalentTabPages[cls];
+}
+
+// script support functions
+TRINITY_DLL_SPEC DBCStorage <SoundEntriesEntry> const* GetSoundEntriesStore() { return &sSoundEntriesStore; }
+TRINITY_DLL_SPEC DBCStorage <SpellEntry> const* GetSpellStore() { return &sSpellStore; }
+TRINITY_DLL_SPEC DBCStorage <SpellRangeEntry> const* GetSpellRangeStore() { return &sSpellRangeStore; }
+TRINITY_DLL_SPEC DBCStorage <FactionEntry> const* GetFactionStore() { return &sFactionStore; }
+TRINITY_DLL_SPEC DBCStorage <ItemEntry> const* GetItemDisplayStore() { return &sItemStore; }
+TRINITY_DLL_SPEC DBCStorage <CreatureDisplayInfoEntry> const* GetCreatureDisplayStore() { return &sCreatureDisplayInfoStore; }
+TRINITY_DLL_SPEC DBCStorage <EmotesEntry> const* GetEmotesStore() { return &sEmotesStore; }
+TRINITY_DLL_SPEC DBCStorage <EmotesTextEntry> const* GetEmotesTextStore() { return &sEmotesTextStore; }
diff --git a/src/game/DBCStores.h b/src/game/DBCStores.h
new file mode 100644
index 00000000000..4da1911a0b7
--- /dev/null
+++ b/src/game/DBCStores.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MANGOS_DBCSTORES_H
+#define MANGOS_DBCSTORES_H
+
+#include "Common.h"
+#include "Database/DBCStore.h"
+#include "DBCStructure.h"
+
+#include <list>
+
+typedef std::list<uint32> SimpleFactionsList;
+
+SimpleFactionsList const* GetFactionTeamList(uint32 faction);
+char* GetPetName(uint32 petfamily, uint32 dbclang);
+uint32 GetTalentSpellCost(uint32 spellId);
+TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
+
+int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
+AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
+AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id);
+uint32 GetAreaFlagByMapId(uint32 mapid);
+
+uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId);
+
+enum ContentLevels
+{
+ CONTENT_1_60 = 0,
+ CONTENT_61_70,
+ CONTENT_71_80
+};
+ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId);
+
+ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id);
+
+bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId);
+
+void Zone2MapCoordinates(float& x,float& y,uint32 zone);
+void Map2ZoneCoordinates(float& x,float& y,uint32 zone);
+
+uint32 GetTalentInspectBitPosInTab(uint32 talentId);
+uint32 GetTalentTabInspectBitSize(uint32 talentTabId);
+uint32 const* /*[3]*/ GetTalentTabPages(uint32 cls);
+
+extern DBCStorage <AchievementEntry> sAchievementStore;
+extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
+extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
+extern DBCStorage <AreaGroupEntry> sAreaGroupStore;
+extern DBCStorage <AreaPOIEntry> sAreaPOIStore;
+extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
+extern DBCStorage <AuctionHouseEntry> sAuctionHouseStore;
+extern DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore;
+extern DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore;
+extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore;
+//extern DBCStorage <ChatChannelsEntry> sChatChannelsStore; -- accessed using function, no usable index
+extern DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore;
+extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
+extern DBCStorage <ChrClassesEntry> sChrClassesStore;
+extern DBCStorage <ChrRacesEntry> sChrRacesStore;
+extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore;
+extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
+extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
+extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore;
+extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore;
+extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore;
+extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore;
+extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore;
+extern DBCStorage <EmotesEntry> sEmotesStore;
+extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
+extern DBCStorage <FactionEntry> sFactionStore;
+extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
+extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore;
+extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore;
+extern DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore;
+extern DBCStorage <GlyphSlotEntry> sGlyphSlotStore;
+
+extern DBCStorage <GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore;
+extern DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore;
+extern DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore;
+extern DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore;
+extern DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore;
+extern DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore;
+extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore;
+//extern DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore; -- not used currently
+extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
+extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
+extern DBCStorage <HolidaysEntry> sHolidaysStore;
+extern DBCStorage <ItemEntry> sItemStore;
+extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore;
+//extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore; -- not used currently
+extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
+extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore;
+extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore;
+extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore;
+extern DBCStorage <ItemSetEntry> sItemSetStore;
+extern DBCStorage <LockEntry> sLockStore;
+extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
+extern DBCStorage <MapEntry> sMapStore;
+extern DBCStorage <MovieEntry> sMovieStore;
+extern DBCStorage <QuestSortEntry> sQuestSortStore;
+extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore;
+extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore;
+extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore;
+extern DBCStorage <SkillLineEntry> sSkillLineStore;
+extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore;
+extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore;
+extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore;
+extern DBCStorage <SpellDurationEntry> sSpellDurationStore;
+extern DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore;
+extern DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore;
+extern DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore;
+extern SpellCategoryStore sSpellCategoryStore;
+extern PetFamilySpellsStore sPetFamilySpellsStore;
+extern DBCStorage <SpellRadiusEntry> sSpellRadiusStore;
+extern DBCStorage <SpellRangeEntry> sSpellRangeStore;
+extern DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore;
+extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore;
+extern DBCStorage <SpellEntry> sSpellStore;
+extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore;
+extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore;
+extern DBCStorage <TalentEntry> sTalentStore;
+extern DBCStorage <TalentTabEntry> sTalentTabStore;
+extern DBCStorage <TaxiNodesEntry> sTaxiNodesStore;
+extern DBCStorage <TaxiPathEntry> sTaxiPathStore;
+extern TaxiMask sTaxiNodesMask;
+extern TaxiMask sOldContinentsNodesMask;
+extern TaxiPathSetBySource sTaxiPathSetBySource;
+extern TaxiPathNodesByPath sTaxiPathNodesByPath;
+extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
+extern DBCStorage <VehicleEntry> sVehicleStore;
+extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore;
+//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
+extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore;
+extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore;
+
+void LoadDBCStores(const std::string& dataPath);
+
+// script support functions
+TRINITY_DLL_SPEC DBCStorage <SoundEntriesEntry> const* GetSoundEntriesStore();
+TRINITY_DLL_SPEC DBCStorage <SpellEntry> const* GetSpellStore();
+TRINITY_DLL_SPEC DBCStorage <SpellRangeEntry> const* GetSpellRangeStore();
+TRINITY_DLL_SPEC DBCStorage <FactionEntry> const* GetFactionStore();
+TRINITY_DLL_SPEC DBCStorage <ItemEntry> const* GetItemDisplayStore();
+TRINITY_DLL_SPEC DBCStorage <CreatureDisplayInfoEntry> const* GetCreatureDisplayStore();
+TRINITY_DLL_SPEC DBCStorage <EmotesEntry> const* GetEmotesStore();
+TRINITY_DLL_SPEC DBCStorage <EmotesTextEntry> const* GetEmotesTextStore();
+#endif
diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h
new file mode 100644
index 00000000000..50a543859cd
--- /dev/null
+++ b/src/game/DBCStructure.h
@@ -0,0 +1,1813 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MANGOS_DBCSTRUCTURE_H
+#define MANGOS_DBCSTRUCTURE_H
+
+#include "DBCEnums.h"
+#include "Platform/Define.h"
+#include "Util.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+// Structures using to access raw DBC data and required packing to portability
+
+// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
+#if defined( __GNUC__ )
+#pragma pack(1)
+#else
+#pragma pack(push,1)
+#endif
+
+struct AchievementEntry
+{
+ uint32 ID; // 0
+ uint32 factionFlag; // 1 -1=all, 0=horde, 1=alliance
+ uint32 mapID; // 2 -1=none
+ //uint32 parentAchievement; // 3 its Achievement parent (can`t start while parent uncomplete, use its Criteria if don`t have own, use its progress on begin)
+ //char *name[16]; // 4-19
+ //uint32 name_flags; // 20
+ //char *description[16]; // 21-36
+ //uint32 desc_flags; // 37
+ uint32 categoryId; // 38
+ uint32 points; // 39 reward points
+ //uint32 OrderInCategory; // 40
+ uint32 flags; // 41
+ //uint32 icon; // 42 icon (from SpellIcon.dbc)
+ //char *titleReward[16]; // 43-58
+ //uint32 titleReward_flags; // 59
+ uint32 count; // 60 - need this count of completed criterias (own or referenced achievement criterias)
+ uint32 refAchievement; // 61 - referenced achievement (counting of all completed criterias)
+};
+
+struct AchievementCategoryEntry
+{
+ uint32 ID; // 0
+ uint32 parentCategory; // 1 -1 for main category
+ //char *name[16]; // 2-17
+ //uint32 name_flags; // 18
+ //uint32 sortOrder; // 19
+};
+
+struct AchievementCriteriaEntry
+{
+ uint32 ID; // 0
+ uint32 referredAchievement; // 1
+ uint32 requiredType; // 2
+ union
+ {
+ // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0
+ // TODO: also used for player deaths..
+ struct
+ {
+ uint32 creatureID; // 3
+ uint32 creatureCount; // 4
+ } kill_creature;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1
+ // TODO: there are further criterias instead just winning
+ struct
+ {
+ uint32 bgMapID; // 3
+ uint32 winCount; // 4
+ } win_bg;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5
+ struct
+ {
+ uint32 unused; // 3
+ uint32 level; // 4
+ } reach_level;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7
+ struct
+ {
+ uint32 skillID; // 3
+ uint32 skillLevel; // 4
+ } reach_skill_level;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8
+ struct
+ {
+ uint32 linkedAchievement; // 3
+ } complete_achievement;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9
+ struct
+ {
+ uint32 unused; // 3
+ uint32 totalQuestCount; // 4
+ } complete_quest_count;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10
+ struct
+ {
+ uint32 unused; // 3
+ uint32 numberOfDays; // 4
+ } complete_daily_quest_daily;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11
+ struct
+ {
+ uint32 zoneID; // 3
+ uint32 questCount; // 4
+ } complete_quests_in_zone;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14
+ struct
+ {
+ uint32 unused; // 3
+ uint32 questCount; // 4
+ } complete_daily_quest;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15
+ struct
+ {
+ uint32 mapID; // 3
+ } complete_battleground;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16
+ struct
+ {
+ uint32 mapID; // 3
+ } death_at_map;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18
+ struct
+ {
+ uint32 manLimit; // 3
+ } death_in_dungeon;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19
+ struct
+ {
+ uint32 groupSize; // 3 can be 5, 10 or 25
+ } complete_raid;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20
+ struct
+ {
+ uint32 creatureEntry; // 3
+ } killed_by_creature;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24
+ struct
+ {
+ uint32 unused; // 3
+ uint32 fallHeight; // 4
+ } fall_without_dying;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26
+ struct
+ {
+ uint32 type; // 3, see enum EnviromentalDamage
+ } death_from;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27
+ struct
+ {
+ uint32 questID; // 3
+ uint32 questCount; // 4
+ } complete_quest;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28
+ // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69
+ struct
+ {
+ uint32 spellID; // 3
+ uint32 spellCount; // 4
+ } be_spell_target;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29
+ // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110
+ struct
+ {
+ uint32 spellID; // 3
+ uint32 castCount; // 4
+ } cast_spell;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31
+ struct
+ {
+ uint32 areaID; // 3 Reference to AreaTable.dbc
+ uint32 killCount; // 4
+ } honorable_kill_at_area;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32
+ struct
+ {
+ uint32 mapID; // 3 Reference to Map.dbc
+ } win_arena;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33
+ struct
+ {
+ uint32 mapID; // 3 Reference to Map.dbc
+ } play_arena;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34
+ struct
+ {
+ uint32 spellID; // 3 Reference to Map.dbc
+ } learn_spell;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36
+ struct
+ {
+ uint32 itemID; // 3
+ uint32 itemCount; // 4
+ } own_item;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37
+ struct
+ {
+ uint32 unused; // 3
+ uint32 count; // 4
+ uint32 flag; // 5 4=in a row
+ } win_rated_arena;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38
+ struct
+ {
+ uint32 teamtype; // 3 {2,3,5}
+ } highest_team_rating;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39
+ struct
+ {
+ uint32 teamtype; // 3 {2,3,5}
+ uint32 teamrating; // 4
+ } reach_team_rating;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40
+ struct
+ {
+ uint32 skillID; // 3
+ uint32 skillLevel; // 4 apprentice=1, journeyman=2, expert=3, artisan=4, master=5, grand master=6
+ } learn_skill_level;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41
+ struct
+ {
+ uint32 itemID; // 3
+ uint32 itemCount; // 4
+ } use_item;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42
+ struct
+ {
+ uint32 itemID; // 3
+ uint32 itemCount; // 4
+ } loot_item;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43
+ struct
+ {
+ // TODO: This rank is _NOT_ the index from AreaTable.dbc
+ uint32 areaReference; // 3
+ } explore_area;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44
+ struct
+ {
+ // TODO: This rank is _NOT_ the index from CharTitles.dbc
+ uint32 rank; // 3
+ } own_rank;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45
+ struct
+ {
+ uint32 unused; // 3
+ uint32 numberOfSlots; // 4
+ } buy_bank_slot;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46
+ struct
+ {
+ uint32 factionID; // 3
+ uint32 reputationAmount; // 4 Total reputation amount, so 42000 = exalted
+ } gain_reputation;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION= 47
+ struct
+ {
+ uint32 unused; // 3
+ uint32 numberOfExaltedFactions; // 4
+ } gain_exalted_reputation;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48
+ struct
+ {
+ uint32 unused; // 3
+ uint32 numberOfVisits; // 4
+ } visit_barber;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49
+ // TODO: where is the required itemlevel stored?
+ struct
+ {
+ uint32 itemSlot; // 3
+ } equip_epic_item;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50
+ struct
+ {
+ uint32 rollValue; // 3
+ uint32 count; // 4
+ } roll_need_on_loot;
+ // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51
+ struct
+ {
+ uint32 rollValue; // 3
+ uint32 count; // 4
+ } roll_greed_on_loot;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52
+ struct
+ {
+ uint32 classID; // 3
+ uint32 count; // 4
+ } hk_class;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53
+ struct
+ {
+ uint32 raceID; // 3
+ uint32 count; // 4
+ } hk_race;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54
+ // TODO: where is the information about the target stored?
+ struct
+ {
+ uint32 emoteID; // 3 enum TextEmotes
+ uint32 count; // 4 count of emotes, always required special target or requirements
+ } do_emote;
+ // ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13
+ // ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55
+ // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56
+ struct
+ {
+ uint32 unused; // 3
+ uint32 count; // 4
+ uint32 flag; // 5 =3 for battleground healing
+ uint32 mapid; // 6
+ } healing_done;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57
+ struct
+ {
+ uint32 itemID; // 3
+ uint32 count; // 4
+ } equip_item;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD= 62
+ struct
+ {
+ uint32 unused; // 3
+ uint32 goldInCopper; // 4
+ } quest_reward_money;
+
+
+ // ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67
+ struct
+ {
+ uint32 unused; // 3
+ uint32 goldInCopper; // 4
+ } loot_money;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68
+ struct
+ {
+ uint32 goEntry; // 3
+ uint32 useCount; // 4
+ } use_gameobject;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70
+ // TODO: are those special criteria stored in the dbc or do we have to add another sql table?
+ struct
+ {
+ uint32 unused; // 3
+ uint32 killCount; // 4
+ } special_pvp_kill;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72
+ struct
+ {
+ uint32 goEntry; // 3
+ uint32 lootCount; // 4
+ } fish_in_gameobject;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75
+ struct
+ {
+ uint32 skillLine; // 3
+ uint32 spellCount; // 4
+ } learn_skillline_spell;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76
+ struct
+ {
+ uint32 unused; // 3
+ uint32 duelCount; // 4
+ } win_duel;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96
+ struct
+ {
+ uint32 powerType; // 3 mana=0, 1=rage, 3=energy, 6=runic power
+ } highest_power;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97
+ struct
+ {
+ uint32 statType; // 3 4=spirit, 3=int, 2=stamina, 1=agi, 0=strength
+ } highest_stat;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98
+ struct
+ {
+ uint32 spellSchool; // 3
+ } highest_spellpower;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100
+ struct
+ {
+ uint32 ratingType; // 3
+ } highest_rating;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109
+ struct
+ {
+ uint32 lootType; // 3 3=fishing, 2=pickpocket, 4=disentchant
+ uint32 lootTypeCount; // 4
+ } loot_type;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112
+ struct
+ {
+ uint32 skillLine; // 3
+ uint32 spellCount; // 4
+ } learn_skill_line;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113
+ struct
+ {
+ uint32 unused; // 3
+ uint32 killCount; // 4
+ } honorable_kill;
+
+ struct
+ {
+ uint32 field3; // 3 main requirement
+ uint32 count; // 4 main requirement count
+ uint32 additionalRequirement1_type; // 5 additional requirement 1 type
+ uint32 additionalRequirement1_value; // 6 additional requirement 1 value
+ uint32 additionalRequirement2_type; // 7 additional requirement 2 type
+ uint32 additionalRequirement2_value; // 8 additional requirement 1 value
+ } raw;
+ };
+ //char* name[16]; // 9-24
+ //uint32 name_flags; // 25
+ uint32 completionFlag; // 26
+ uint32 groupFlag; // 27
+ //uint32 unk1; // 28
+ uint32 timeLimit; // 29 time limit in seconds
+ //uint32 showOrder; // 30 show order
+};
+
+struct AreaTableEntry
+{
+ uint32 ID; // 0
+ uint32 mapid; // 1
+ uint32 zone; // 2 if 0 then it's zone, else it's zone id of this area
+ uint32 exploreFlag; // 3, main index
+ uint32 flags; // 4, unknown value but 312 for all cities
+ // 5-9 unused
+ int32 area_level; // 10
+ char* area_name[16]; // 11-26
+ // 27, string flags, unused
+ uint32 team; // 28
+};
+
+struct AreaGroupEntry
+{
+ uint32 AreaGroupId; // 0
+ uint32 AreaId[6]; // 1-6
+ uint32 nextGroup; // 7 index of next group
+};
+
+struct AreaPOIEntry
+{
+ uint32 id; //0
+ //uint32 icon[11]; //1-11
+ float x; //12
+ float y; //13
+ float z; //14
+ uint32 mapId; //15
+ //uint32 val1; //16
+ uint32 zoneId; //17
+ //char* name[16]; //18-33
+ //uint32 name_flag; //34
+ //char* name2[16]; //35-50
+ //uint32 name_flag2; //51
+ uint32 worldState; //52
+ //uint32 val2; //53
+};
+
+struct AreaTriggerEntry
+{
+ uint32 id; // 0 m_ID
+ uint32 mapid; // 1 m_ContinentID
+ float x; // 2 m_x
+ float y; // 3 m_y
+ float z; // 4 m_z
+ float radius; // 5 m_radius
+ float box_x; // 6 m_box_length
+ float box_y; // 7 m_box_width
+ float box_z; // 8 m_box_heigh
+ float box_orientation; // 9 m_box_yaw
+};
+
+struct AuctionHouseEntry
+{
+ uint32 houseId; // 0 index
+ uint32 faction; // 1 id of faction.dbc for player factions associated with city
+ uint32 depositPercent; // 2 1/3 from real
+ uint32 cutPercent; // 3
+ //char* name[16]; // 4-19
+ // 20 string flag, unused
+};
+
+struct BankBagSlotPricesEntry
+{
+ uint32 ID;
+ uint32 price;
+};
+
+struct BarberShopStyleEntry
+{
+ uint32 Id; // 0
+ uint32 type; // 1 value 0 -> hair, value 2 -> facialhair
+ //char* name[16]; // 2-17 name of hair style
+ //uint32 name_flags; // 18
+ //uint32 unk_name[16]; // 19-34, all empty
+ //uint32 unk_flags; // 35
+ //float CostMultiplier; // 36 values 1 and 0.75
+ uint32 race; // 37 race
+ uint32 gender; // 38 0 -> male, 1 -> female
+ uint32 hair_id; // 39 real ID to hair/facial hair
+};
+
+struct BattlemasterListEntry
+{
+ uint32 id; // 0
+ int32 mapid[8]; // 1-8 mapid
+ uint32 type; // 9 (3 - BG, 4 - arena)
+ uint32 minlvl; // 10
+ uint32 maxlvl; // 11
+ uint32 maxplayersperteam; // 12
+ // 13 minplayers
+ // 14 0 or 9
+ // 15
+ char* name[16]; // 16-31
+ // 32 string flag, unused
+ // 33 unused
+};
+
+#define MAX_OUTFIT_ITEMS 24
+
+struct CharStartOutfitEntry
+{
+ //uint32 Id; // 0
+ uint32 RaceClassGender; // 1 (UNIT_FIELD_BYTES_0 & 0x00FFFFFF) comparable (0 byte = race, 1 byte = class, 2 byte = gender)
+ int32 ItemId[MAX_OUTFIT_ITEMS]; // 2-13
+ //int32 ItemDisplayId[MAX_OUTFIT_ITEMS]; // 14-25 not required at server side
+ //int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 26-37 not required at server side
+ //uint32 Unknown1; // 38, unique values (index-like with gaps ordered in other way as ids)
+ //uint32 Unknown2; // 39
+ //uint32 Unknown3; // 40
+};
+
+struct CharTitlesEntry
+{
+ uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId()
+ //uint32 unk1; // 1 flags?
+ //char* name[16]; // 2-17, unused
+ // 18 string flag, unused
+ //char* name2[16]; // 19-34, unused
+ // 35 string flag, unused
+ uint32 bit_index; // 36 used in PLAYER_CHOSEN_TITLE and 1<<index in PLAYER__FIELD_KNOWN_TITLES
+};
+
+struct ChatChannelsEntry
+{
+ uint32 ChannelID; // 0
+ uint32 flags; // 1
+ char* pattern[16]; // 3-18
+ // 19 string flags, unused
+ //char* name[16]; // 20-35 unused
+ // 36 string flag, unused
+};
+
+struct ChrClassesEntry
+{
+ uint32 ClassID; // 0
+ // 1, unused
+ uint32 powerType; // 2
+ // 3-4, unused
+ //char* name[16]; // 5-20 unused
+ // 21 string flag, unused
+ //char* nameFemale[16]; // 21-36 unused, if different from base (male) case
+ // 37 string flag, unused
+ //char* nameNeutralGender[16]; // 38-53 unused, if different from base (male) case
+ // 54 string flag, unused
+ // 55, unused
+ uint32 spellfamily; // 56
+ // 57, unused
+ uint32 CinematicSequence; // 58 id from CinematicSequences.dbc
+ uint32 addon; // 59 (0 - original race, 1 - tbc addon, ...)
+};
+
+struct ChrRacesEntry
+{
+ uint32 RaceID; // 0
+ // 1 unused
+ uint32 FactionID; // 2 facton template id
+ // 3 unused
+ uint32 model_m; // 4
+ uint32 model_f; // 5
+ // 6-7 unused
+ uint32 TeamID; // 8 (7-Alliance 1-Horde)
+ // 9-12 unused
+ uint32 CinematicSequence; // 13 id from CinematicSequences.dbc
+ char* name[16]; // 14-29 used for DBC language detection/selection
+ // 30 string flags, unused
+ //char* nameFemale[16]; // 31-46, if different from base (male) case
+ // 47 string flags, unused
+ //char* nameNeutralGender[16]; // 48-63, if different from base (male) case
+ // 64 string flags, unused
+ // 65-67 unused
+ uint32 addon; // 68 (0 - original race, 1 - tbc addon, ...)
+};
+
+/* not used
+struct CinematicCameraEntry
+{
+ uint32 id; // 0 index
+ char* filename; // 1
+ uint32 soundid; // 2 in SoundEntries.dbc or 0
+ float start_x; // 3
+ float start_y; // 4
+ float start_z; // 5
+ float unk6; // 6 speed?
+};
+*/
+
+struct CinematicSequencesEntry
+{
+ uint32 Id; // 0 index
+ //uint32 unk1; // 1 always 0
+ //uint32 cinematicCamera; // 2 id in CinematicCamera.dbc
+ // 3-9 always 0
+};
+
+struct CreatureDisplayInfoEntry
+{
+ uint32 Displayid; // 0 m_ID
+ // 1 m_modelID
+ // 2 m_soundID
+ // 3 m_extendedDisplayInfoID
+ float scale; // 4 m_creatureModelScale
+ // 5 m_creatureModelAlpha
+ // 6-8 m_textureVariation[3]
+ // 9 m_portraitTextureName
+ // 10 m_sizeClass
+ // 11 m_bloodID
+ // 12 m_NPCSoundID
+ // 13 m_particleColorID
+ // 14 m_creatureGeosetData
+ // 15 m_objectEffectPackageID
+};
+
+struct CreatureFamilyEntry
+{
+ uint32 ID; // 0 m_ID
+ float minScale; // 1 m_minScale
+ uint32 minScaleLevel; // 2 m_minScaleLevel
+ float maxScale; // 3 m_maxScale
+ uint32 maxScaleLevel; // 4 m_maxScaleLevel
+ uint32 skillLine[2]; // 5-6 m_skillLine
+ uint32 petFoodMask; // 7 m_petFoodMask
+ int32 petTalentType; // 8 m_petTalentType
+ // 9 m_categoryEnumID
+ char* Name[16]; // 10-25 m_name_lang
+ // 26 string flags
+ // 27 m_iconFile
+};
+
+#define MAX_CREATURE_SPELL_DATA_SLOT 4
+
+struct CreatureSpellDataEntry
+{
+ uint32 ID; // 0 m_ID
+ uint32 spellId[MAX_CREATURE_SPELL_DATA_SLOT]; // 1-4 m_spells[4]
+ //uint32 availability[MAX_CREATURE_SPELL_DATA_SLOT]; // 4-7 m_availability[4]
+};
+
+struct CreatureTypeEntry
+{
+ uint32 ID; // 0 m_ID
+ //char* Name[16]; // 1-16 name
+ // 17 string flags
+ //uint32 no_expirience; // 18 no exp? critters, non-combat pets, gas cloud.
+};
+
+/* not used
+struct CurrencyCategoryEntry
+{
+ uint32 ID; // 0
+ uint32 Unk1; // 1 0 for known categories and 3 for unknown one (3.0.9)
+ char* Name[16]; // 2-17 name
+ // // 18 string flags
+};
+*/
+
+struct CurrencyTypesEntry
+{
+ //uint32 ID; // 0 not used
+ uint32 ItemId; // 1 used as real index
+ uint32 BitIndex; // 2 bit index in PLAYER_FIELD_KNOWN_CURRENCIES (1 << (index-1))
+};
+
+struct DurabilityCostsEntry
+{
+ uint32 Itemlvl; // 0
+ uint32 multiplier[29]; // 1-29
+};
+
+struct DurabilityQualityEntry
+{
+ uint32 Id; // 0
+ float quality_mod; // 1
+};
+
+struct EmotesEntry
+{
+ uint32 Id; // 0
+ //char* Name; // 1, internal name
+ //uint32 AnimationId; // 2, ref to animationData
+ uint32 Flags; // 3, bitmask, may be unit_flags
+ uint32 EmoteType; // 4, Can be 0, 1 or 2 (determine how emote are shown)
+ uint32 UnitStandState; // 5, uncomfirmed, may be enum UnitStandStateType
+ //uint32 SoundId; // 6, ref to soundEntries
+};
+
+struct EmotesTextEntry
+{
+ uint32 Id;
+ uint32 textid;
+};
+
+struct FactionEntry
+{
+ uint32 ID; // 0 m_ID
+ int32 reputationListID; // 1 m_reputationIndex
+ uint32 BaseRepRaceMask[4]; // 2-5 m_reputationRaceMask
+ uint32 BaseRepClassMask[4]; // 6-9 m_reputationClassMask
+ int32 BaseRepValue[4]; // 10-13 m_reputationBase
+ uint32 ReputationFlags[4]; // 14-17 m_reputationFlags
+ uint32 team; // 18 m_parentFactionID
+ char* name[16]; // 19-34 m_name_lang
+ // 35 string flags
+ //char* description[16]; // 36-51 m_description_lang
+ // 52 string flags
+};
+
+struct FactionTemplateEntry
+{
+ uint32 ID; // 0 m_ID
+ uint32 faction; // 1 m_faction
+ uint32 factionFlags; // 2 m_flags
+ uint32 ourMask; // 3 m_factionGroup
+ uint32 friendlyMask; // 4 m_friendGroup
+ uint32 hostileMask; // 5 m_enemyGroup
+ uint32 enemyFaction[4]; // 6 m_enemies[4]
+ uint32 friendFaction[4]; // 10 m_friend[4]
+ //------------------------------------------------------- end structure
+
+ // helpers
+ bool IsFriendlyTo(FactionTemplateEntry const& entry) const
+ {
+ if(ID == entry.ID)
+ return true;
+ if(entry.faction)
+ {
+ for(int i = 0; i < 4; ++i)
+ if (enemyFaction[i] == entry.faction)
+ return false;
+ for(int i = 0; i < 4; ++i)
+ if (friendFaction[i] == entry.faction)
+ return true;
+ }
+ return (friendlyMask & entry.ourMask) || (ourMask & entry.friendlyMask);
+ }
+ bool IsHostileTo(FactionTemplateEntry const& entry) const
+ {
+ if(ID == entry.ID)
+ return false;
+ if(entry.faction)
+ {
+ for(int i = 0; i < 4; ++i)
+ if (enemyFaction[i] == entry.faction)
+ return true;
+ for(int i = 0; i < 4; ++i)
+ if (friendFaction[i] == entry.faction)
+ return false;
+ }
+ return (hostileMask & entry.ourMask) != 0;
+ }
+ bool IsHostileToPlayers() const { return (hostileMask & FACTION_MASK_PLAYER) !=0; }
+ bool IsNeutralToAll() const
+ {
+ for(int i = 0; i < 4; ++i)
+ if (enemyFaction[i] != 0)
+ return false;
+ return hostileMask == 0 && friendlyMask == 0;
+ }
+ bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD)!=0; }
+};
+
+struct GameObjectDisplayInfoEntry
+{
+ uint32 ID; //0
+ //char* mdx; //1
+ //uint32 unk1[10]; //2-11
+ float minX;
+ float minY;
+ float minZ;
+ float maxX;
+ float maxY;
+ float maxZ;
+ //uint32 transport; //18
+};
+
+struct GemPropertiesEntry
+{
+ uint32 ID;
+ uint32 spellitemenchantement;
+ uint32 color;
+};
+
+struct GlyphPropertiesEntry
+{
+ uint32 Id;
+ uint32 SpellId;
+ uint32 TypeFlags;
+ uint32 Unk1; // GlyphIconId (SpellIcon.dbc)
+};
+
+struct GlyphSlotEntry
+{
+ uint32 Id;
+ uint32 TypeFlags;
+ uint32 Order;
+};
+
+// All Gt* DBC store data for 100 levels, some by 100 per class/race
+#define GT_MAX_LEVEL 100
+
+struct GtBarberShopCostBaseEntry
+{
+ float cost;
+};
+
+struct GtCombatRatingsEntry
+{
+ float ratio;
+};
+
+struct GtChanceToMeleeCritBaseEntry
+{
+ float base;
+};
+
+struct GtChanceToMeleeCritEntry
+{
+ float ratio;
+};
+
+struct GtChanceToSpellCritBaseEntry
+{
+ float base;
+};
+
+struct GtChanceToSpellCritEntry
+{
+ float ratio;
+};
+
+struct GtOCTRegenHPEntry
+{
+ float ratio;
+};
+
+//struct GtOCTRegenMPEntry
+//{
+// float ratio;
+//};
+
+struct GtRegenHPPerSptEntry
+{
+ float ratio;
+};
+
+struct GtRegenMPPerSptEntry
+{
+ float ratio;
+};
+
+/* no used
+struct HolidayDescriptionsEntry
+{
+ uint32 ID; // 0, this is NOT holiday id
+ //char* name[16] // 1-16 m_name_lang
+ // 17 name flags
+};
+*/
+
+/* no used
+struct HolidayNamesEntry
+{
+ uint32 ID; // 0, this is NOT holiday id
+ //char* name[16] // 1-16 m_name_lang
+ // 17 name flags
+};
+*/
+
+struct HolidaysEntry
+{
+ uint32 ID; // 0, holiday id
+ //uint32 unk1; // 1
+ //uint32 unk2; // 2
+ //uint32 unk3[8] // 3-10, empty fields
+ //uint32 unk11[13] // 11-23, some unknown data (bit strings?)
+ //uint32 unk11[13] // 24-36, some empty fields (continue prev?)
+ //uint32 unk11[12] // 37-48, counters?
+ //uint32 holidayNameId; // 49, id for HolidayNames.dbc
+ //uint32 holidayDescriptionId; // 50, id for HolidayDescriptions.dbc
+ //uint32 unk51; // 51
+ //uint32 unk52; // 52
+ //uint32 unk53; // 53
+};
+
+struct ItemEntry
+{
+ uint32 ID; // 0
+ uint32 Class; // 1
+ uint32 SubClass; // 2 some items have strnage subclasses
+ int32 Unk0; // 3
+ int32 Material; // 4
+ uint32 DisplayId; // 5
+ uint32 InventoryType; // 6
+ uint32 Sheath; // 7
+};
+
+struct ItemBagFamilyEntry
+{
+ uint32 ID; // 0
+ //char* name[16] // 1-16 m_name_lang
+ // // 17 name flags
+};
+
+struct ItemDisplayInfoEntry
+{
+ uint32 ID; // 0 m_ID
+ // 1 m_modelName[2]
+ // 2 m_modelTexture[2]
+ // 3 m_inventoryIcon
+ // 4 m_geosetGroup[3]
+ // 5 m_flags
+ // 6 m_spellVisualID
+ // 7 m_groupSoundIndex
+ // 8 m_helmetGeosetVis[2]
+ // 9 m_texture[2]
+ // 10 m_itemVisual[8]
+ // 11 m_particleColorID
+};
+
+//struct ItemCondExtCostsEntry
+//{
+// uint32 ID;
+// uint32 condExtendedCost; // ItemPrototype::CondExtendedCost
+// uint32 itemextendedcostentry; // ItemPrototype::ExtendedCost
+// uint32 arenaseason; // arena season number(1-4)
+//};
+
+struct ItemExtendedCostEntry
+{
+ uint32 ID; // 0 extended-cost entry id
+ uint32 reqhonorpoints; // 1 required honor points
+ uint32 reqarenapoints; // 2 required arena points
+ uint32 reqitem[5]; // 3-7 required item id
+ uint32 reqitemcount[5]; // 8-12 required count of 1st item
+ uint32 reqpersonalarenarating; // 13 required personal arena rating
+};
+
+struct ItemLimitCategoryEntry
+{
+ uint32 ID; // 0 Id
+ //char* name[16] // 1-16 m_name_lang
+ // 17 name flags
+ uint32 maxCount; // max allowed equipped as item or in gem slot
+ //uint32 unk; // 1 for prismatic gems only...
+};
+
+struct ItemRandomPropertiesEntry
+{
+ uint32 ID; // 0 m_ID
+ //char* internalName // 1 m_Name
+ uint32 enchant_id[5]; // 2-6 m_Enchantment
+ //char* nameSuffix[16] // 7-22 m_name_lang
+ // 23 name flags
+};
+
+struct ItemRandomSuffixEntry
+{
+ uint32 ID; // 0 m_ID
+ //char* name[16] // 1-16 m_name_lang
+ // 17, name flags
+ // 18 m_internalName
+ uint32 enchant_id[5]; // 19-21 m_enchantment
+ uint32 prefix[5]; // 22-24 m_allocationPct
+};
+
+struct ItemSetEntry
+{
+ //uint32 id // 0 m_ID
+ char* name[16]; // 1-16 m_name_lang
+ // 17 string flags, unused
+ //uint32 itemId[17]; // 18-34 m_itemID
+ uint32 spells[8]; // 35-42 m_setSpellID
+ uint32 items_to_triggerspell[8]; // 43-50 m_setThreshold
+ uint32 required_skill_id; // 51 m_requiredSkill
+ uint32 required_skill_value; // 52 m_requiredSkillRank
+};
+
+#define MAX_LOCK_CASE 8
+
+struct LockEntry
+{
+ uint32 ID; // 0 m_ID
+ uint32 Type[MAX_LOCK_CASE]; // 1-8 m_Type
+ uint32 Index[MAX_LOCK_CASE]; // 9-16 m_Index
+ uint32 Skill[MAX_LOCK_CASE]; // 17-24 m_Skill
+ //uint32 Action[MAX_LOCK_CASE]; // 25-32 m_Action
+};
+
+struct MailTemplateEntry
+{
+ uint32 ID; // 0
+ //char* subject[16]; // 1-16
+ // 17 name flags, unused
+ //char* content[16]; // 18-33
+};
+
+struct MapEntry
+{
+ uint32 MapID; // 0
+ //char* internalname; // 1 unused
+ uint32 map_type; // 2
+ // 3 0 or 1 for battlegrounds (not arenas)
+ char* name[16]; // 4-19
+ // 20 name flags, unused
+ uint32 linked_zone; // 21 common zone for instance and continent map
+ //char* hordeIntro[16]; // 23-37 text for PvP Zones
+ // 38 intro text flags
+ //char* allianceIntro[16]; // 39-54 text for PvP Zones
+ // 55 intro text flags
+ uint32 multimap_id; // 56
+ // 57
+ //chat* unknownText1[16]; // 58-73 unknown empty text fields, possible normal Intro text.
+ // 74 text flags
+ //chat* heroicIntroText[16]; // 75-90 heroic mode requirement text
+ // 91 text flags
+ //chat* unknownText2[16]; // 92-107 unknown empty text fields
+ // 108 text flags
+ int32 entrance_map; // 109 map_id of entrance map
+ float entrance_x; // 110 entrance x coordinate (if exist single entry)
+ float entrance_y; // 111 entrance y coordinate (if exist single entry)
+ uint32 resetTimeRaid; // 112
+ uint32 resetTimeHeroic; // 113
+ // 114 all 0
+ // 115 -1, 0 and 720
+ uint32 addon; // 116 (0-original maps,1-tbc addon)
+ // 117 some kind of time?
+
+ // Helpers
+ uint32 Expansion() const { return addon; }
+
+
+ bool IsDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
+ bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID || map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; }
+ bool IsRaid() const { return map_type == MAP_RAID; }
+ bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; }
+ bool IsBattleArena() const { return map_type == MAP_ARENA; }
+ bool IsBattleGroundOrArena() const { return map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; }
+ bool SupportsHeroicMode() const { return resetTimeHeroic != 0; }
+ bool HasResetTime() const { return resetTimeHeroic || resetTimeRaid; }
+
+ bool IsMountAllowed() const
+ {
+ return !IsDungeon() ||
+ MapID==209 || MapID==269 || MapID==309 || // TanarisInstance, CavernsOfTime, Zul'gurub
+ MapID==509 || MapID==534 || MapID==560 || // AhnQiraj, HyjalPast, HillsbradPast
+ MapID==568 || MapID==580 || MapID==615 || // ZulAman, Sunwell Plateau, Obsidian Sanctrum
+ MapID==616; // Eye Of Eternity
+ }
+
+ bool IsContinent() const
+ {
+ return MapID == 0 || MapID == 1 || MapID == 530 || MapID == 571;
+ }
+};
+
+struct MovieEntry
+{
+ uint32 Id; // 0 index
+ //char* filename; // 1
+ //uint32 unk2; // 2 always 100
+};
+
+struct QuestSortEntry
+{
+ uint32 id; // 0 m_ID
+ //char* name[16]; // 1-16 m_SortName_lang
+ // 17 name flags
+};
+
+struct RandomPropertiesPointsEntry
+{
+ //uint32 Id; // 0 hidden key
+ uint32 itemLevel; // 1
+ uint32 EpicPropertiesPoints[5]; // 2-6
+ uint32 RarePropertiesPoints[5]; // 7-11
+ uint32 UncommonPropertiesPoints[5]; // 12-16
+};
+
+struct ScalingStatDistributionEntry
+{
+ uint32 Id;
+ int32 StatMod[10];
+ uint32 Modifier[10];
+ uint32 MaxLevel;
+};
+
+struct ScalingStatValuesEntry
+{
+ uint32 Id;
+ uint32 Level;
+ uint32 ssdMultiplier[5]; // Multiplier for ScalingStatDistribution
+ uint32 armorMod[4]; // Armor for level
+ uint32 dpsMod[6]; // DPS mod for level
+ uint32 spellBonus; // not sure.. TODO: need more info about
+ uint32 feralBonus; // Feral AP bonus
+
+ uint32 getssdMultiplier(uint32 mask) const
+ {
+ if (mask&0x001F)
+ {
+ if(mask & 0x00000001) return ssdMultiplier[0];
+ if(mask & 0x00000002) return ssdMultiplier[1];
+ if(mask & 0x00000004) return ssdMultiplier[2];
+ if(mask & 0x00000008) return ssdMultiplier[3];
+ if(mask & 0x00000010) return ssdMultiplier[4];
+ }
+ return 0;
+ }
+ uint32 getArmorMod(uint32 mask) const
+ {
+ if (mask&0x01E0)
+ {
+ if(mask & 0x00000020) return armorMod[0];
+ if(mask & 0x00000040) return armorMod[1];
+ if(mask & 0x00000080) return armorMod[2];
+ if(mask & 0x00000100) return armorMod[3];
+ }
+ return 0;
+ }
+ uint32 getDPSMod(uint32 mask) const
+ {
+ if (mask&0x7E00)
+ {
+ if(mask & 0x00000200) return dpsMod[0];
+ if(mask & 0x00000400) return dpsMod[1];
+ if(mask & 0x00000800) return dpsMod[2];
+ if(mask & 0x00001000) return dpsMod[3];
+ if(mask & 0x00002000) return dpsMod[4];
+ if(mask & 0x00004000) return dpsMod[5];
+ }
+ return 0;
+ }
+ uint32 getSpellBonus(uint32 mask) const
+ {
+ if (mask & 0x00008000) return spellBonus;
+ return 0;
+ }
+ uint32 getFeralBonus(uint32 mask) const
+ {
+ if (mask & 0x00010000) return feralBonus;
+ return 0;
+ }
+};
+
+//struct SkillLineCategoryEntry{
+// uint32 id; // 0 m_ID
+// char* name[16]; // 1-17 m_name_lang
+// // 18 string flag
+// uint32 displayOrder; // 19 m_sortIndex
+//};
+
+//struct SkillRaceClassInfoEntry{
+// uint32 id; // 0 m_ID
+// uint32 skillId; // 1 m_skillID
+// uint32 raceMask; // 2 m_raceMask
+// uint32 classMask; // 3 m_classMask
+// uint32 flags; // 4 m_flags
+// uint32 reqLevel; // 5 m_minLevel
+// uint32 skillTierId; // 6 m_skillTierID
+// uint32 skillCostID; // 7 m_skillCostIndex
+//};
+
+//struct SkillTiersEntry{
+// uint32 id; // 0 m_ID
+// uint32 skillValue[16]; // 1-17 m_cost
+// uint32 maxSkillValue[16]; // 18-32 m_valueMax
+//};
+
+struct SkillLineEntry
+{
+ uint32 id; // 0 m_ID
+ int32 categoryId; // 1 m_categoryID
+ //uint32 skillCostID; // 2 m_skillCostsID
+ char* name[16]; // 3-18 m_displayName_lang
+ // 19 string flags
+ //char* description[16]; // 20-35 m_description_lang
+ // 36 string flags
+ uint32 spellIcon; // 37 m_spellIconID
+ //char* alternateVerb[16]; // 38-53 m_alternateVerb_lang
+ // 54 string flags
+ // 55 m_canLink
+};
+
+struct SkillLineAbilityEntry
+{
+ uint32 id; // 0 m_ID
+ uint32 skillId; // 1 m_skillLine
+ uint32 spellId; // 2 m_spell
+ uint32 racemask; // 3 m_raceMask
+ uint32 classmask; // 4 m_classMask
+ //uint32 racemaskNot; // 5 m_excludeRace
+ //uint32 classmaskNot; // 6 m_excludeClass
+ uint32 req_skill_value; // 7 m_minSkillLineRank
+ uint32 forward_spellid; // 8 m_supercededBySpell
+ uint32 learnOnGetSkill; // 9 m_acquireMethod
+ uint32 max_value; // 10 m_trivialSkillLineRankHigh
+ uint32 min_value; // 11 m_trivialSkillLineRankLow
+ //uint32 characterPoints[2]; // 12-13 m_characterPoints[2]
+};
+
+struct SoundEntriesEntry
+{
+ uint32 Id; // 0 m_ID
+ //uint32 Type; // 1 m_soundType
+ //char* InternalName; // 2 m_name
+ //char* FileName[10]; // 3-12 m_File[10]
+ //uint32 Unk13[10]; // 13-22 m_Freq[10]
+ //char* Path; // 23 m_DirectoryBase
+ // 24 m_volumeFloat
+ // 25 m_flags
+ // 26 m_minDistance
+ // 27 m_distanceCutoff
+ // 28 m_EAXDef
+};
+
+#define MAX_SPELL_EFFECTS 3
+
+struct SpellEntry
+{
+ uint32 Id; // 0 m_ID
+ uint32 Category; // 1 m_category
+ uint32 Dispel; // 2 m_dispelType
+ uint32 Mechanic; // 3 m_mechanic
+ uint32 Attributes; // 4 m_attribute
+ uint32 AttributesEx; // 5 m_attributesEx
+ uint32 AttributesEx2; // 6 m_attributesExB
+ uint32 AttributesEx3; // 7 m_attributesExC
+ uint32 AttributesEx4; // 8 m_attributesExD
+ uint32 AttributesEx5; // 9 m_attributesExE
+ //uint32 AttributesEx6; // 10 m_attributesExF not used
+ uint32 Stances; // 11 m_shapeshiftMask
+ uint32 StancesNot; // 12 m_shapeshiftExclude
+ uint32 Targets; // 13 m_targets
+ uint32 TargetCreatureType; // 14 m_targetCreatureType
+ uint32 RequiresSpellFocus; // 15 m_requiresSpellFocus
+ uint32 FacingCasterFlags; // 16 m_facingCasterFlags
+ uint32 CasterAuraState; // 17 m_casterAuraState
+ uint32 TargetAuraState; // 18 m_targetAuraState
+ uint32 CasterAuraStateNot; // 19 m_excludeCasterAuraState
+ uint32 TargetAuraStateNot; // 20 m_excludeTargetAuraState
+ uint32 casterAuraSpell; // 21 m_casterAuraSpell
+ uint32 targetAuraSpell; // 22 m_targetAuraSpell
+ uint32 excludeCasterAuraSpell; // 23 m_excludeCasterAuraSpell
+ uint32 excludeTargetAuraSpell; // 24 m_excludeTargetAuraSpell
+ uint32 CastingTimeIndex; // 25 m_castingTimeIndex
+ uint32 RecoveryTime; // 26 m_recoveryTime
+ uint32 CategoryRecoveryTime; // 27 m_categoryRecoveryTime
+ uint32 InterruptFlags; // 28 m_interruptFlags
+ uint32 AuraInterruptFlags; // 29 m_auraInterruptFlags
+ uint32 ChannelInterruptFlags; // 30 m_channelInterruptFlags
+ uint32 procFlags; // 31 m_procTypeMask
+ uint32 procChance; // 32 m_procChance
+ uint32 procCharges; // 33 m_procCharges
+ uint32 maxLevel; // 34 m_maxLevel
+ uint32 baseLevel; // 35 m_baseLevel
+ uint32 spellLevel; // 36 m_spellLevel
+ uint32 DurationIndex; // 37 m_durationIndex
+ uint32 powerType; // 38 m_powerType
+ uint32 manaCost; // 39 m_manaCost
+ uint32 manaCostPerlevel; // 40 m_manaCostPerLevel
+ uint32 manaPerSecond; // 41 m_manaPerSecond
+ uint32 manaPerSecondPerLevel; // 42 m_manaPerSecondPerLeve
+ uint32 rangeIndex; // 43 m_rangeIndex
+ float speed; // 44 m_speed
+ //uint32 modalNextSpell; // 45 m_modalNextSpell not used
+ uint32 StackAmount; // 46 m_cumulativeAura
+ uint32 Totem[2]; // 47-48 m_totem
+ int32 Reagent[8]; // 49-56 m_reagent
+ uint32 ReagentCount[8]; // 57-64 m_reagentCount
+ int32 EquippedItemClass; // 65 m_equippedItemClass (value)
+ int32 EquippedItemSubClassMask; // 66 m_equippedItemSubclass (mask)
+ int32 EquippedItemInventoryTypeMask; // 67 m_equippedItemInvTypes (mask)
+ uint32 Effect[MAX_SPELL_EFFECTS]; // 68-70 m_effect
+ int32 EffectDieSides[MAX_SPELL_EFFECTS]; // 71-73 m_effectDieSides
+ uint32 EffectBaseDice[MAX_SPELL_EFFECTS]; // 74-76 m_effectBaseDice
+ float EffectDicePerLevel[MAX_SPELL_EFFECTS]; // 77-79 m_effectDicePerLevel
+ float EffectRealPointsPerLevel[MAX_SPELL_EFFECTS]; // 80-82 m_effectRealPointsPerLevel
+ int32 EffectBasePoints[MAX_SPELL_EFFECTS]; // 83-85 m_effectBasePoints (don't must be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints)
+ uint32 EffectMechanic[MAX_SPELL_EFFECTS]; // 86-88 m_effectMechanic
+ uint32 EffectImplicitTargetA[MAX_SPELL_EFFECTS]; // 89-91 m_implicitTargetA
+ uint32 EffectImplicitTargetB[MAX_SPELL_EFFECTS]; // 92-94 m_implicitTargetB
+ uint32 EffectRadiusIndex[MAX_SPELL_EFFECTS]; // 95-97 m_effectRadiusIndex - spellradius.dbc
+ uint32 EffectApplyAuraName[MAX_SPELL_EFFECTS]; // 98-100 m_effectAura
+ uint32 EffectAmplitude[MAX_SPELL_EFFECTS]; // 101-103 m_effectAuraPeriod
+ float EffectMultipleValue[MAX_SPELL_EFFECTS]; // 104-106 m_effectAmplitude
+ uint32 EffectChainTarget[MAX_SPELL_EFFECTS]; // 107-109 m_effectChainTargets
+ uint32 EffectItemType[MAX_SPELL_EFFECTS]; // 110-112 m_effectItemType
+ int32 EffectMiscValue[MAX_SPELL_EFFECTS]; // 113-115 m_effectMiscValue
+ int32 EffectMiscValueB[MAX_SPELL_EFFECTS]; // 116-118 m_effectMiscValueB
+ uint32 EffectTriggerSpell[MAX_SPELL_EFFECTS]; // 119-121 m_effectTriggerSpell
+ float EffectPointsPerComboPoint[MAX_SPELL_EFFECTS]; // 122-124 m_effectPointsPerCombo
+ flag96 EffectSpellClassMask[MAX_SPELL_EFFECTS]; //
+ uint32 SpellVisual[2]; // 134-135 m_spellVisualID
+ uint32 SpellIconID; // 136 m_spellIconID
+ uint32 activeIconID; // 137 m_activeIconID
+ //uint32 spellPriority; // 138 not used
+ char* SpellName[16]; // 139-154 m_name_lang
+ //uint32 SpellNameFlag; // 155 not used
+ char* Rank[16]; // 156-171 m_nameSubtext_lang
+ //uint32 RankFlags; // 172 not used
+ //char* Description[16]; // 173-188 m_description_lang not used
+ //uint32 DescriptionFlags; // 189 not used
+ //char* ToolTip[16]; // 190-205 m_auraDescription_lang not used
+ //uint32 ToolTipFlags; // 206 not used
+ uint32 ManaCostPercentage; // 207 m_manaCostPct
+ uint32 StartRecoveryCategory; // 208 m_startRecoveryCategory
+ uint32 StartRecoveryTime; // 209 m_startRecoveryTime
+ uint32 MaxTargetLevel; // 210 m_maxTargetLevel
+ uint32 SpellFamilyName; // 211 m_spellClassSet
+ flag96 SpellFamilyFlags; // 212-214
+ uint32 MaxAffectedTargets; // 215 m_maxTargets
+ uint32 DmgClass; // 216 m_defenseType
+ uint32 PreventionType; // 217 m_preventionType
+ //uint32 StanceBarOrder; // 218 m_stanceBarOrder not used
+ float DmgMultiplier[3]; // 219-221 m_effectChainAmplitude
+ //uint32 MinFactionId; // 222 m_minFactionID not used
+ //uint32 MinReputation; // 223 m_minReputation not used
+ //uint32 RequiredAuraVision; // 224 m_requiredAuraVision not used
+ uint32 TotemCategory[2]; // 225-226 m_requiredTotemCategoryID
+ int32 AreaGroupId; // 227 m_requiredAreaGroupId
+ uint32 SchoolMask; // 228 m_schoolMask
+ uint32 runeCostID; // 229 m_runeCostID
+ //uint32 spellMissileID; // 230 m_spellMissileID not used
+
+ // helpers
+ int32 CalculateSimpleValue(uint8 eff) const { return EffectBasePoints[eff]+int32(EffectBaseDice[eff]); }
+
+ private:
+ // prevent creating custom entries (copy data from original in fact)
+ SpellEntry(SpellEntry const&); // DON'T must have implementation
+};
+
+typedef std::set<uint32> SpellCategorySet;
+typedef std::map<uint32,SpellCategorySet > SpellCategoryStore;
+typedef std::set<uint32> PetFamilySpellsSet;
+typedef std::map<uint32,PetFamilySpellsSet > PetFamilySpellsStore;
+
+struct SpellCastTimesEntry
+{
+ uint32 ID; // 0
+ int32 CastTime; // 1
+ //float CastTimePerLevel; // 2 unsure / per skill?
+ //int32 MinCastTime; // 3 unsure
+};
+
+struct SpellFocusObjectEntry
+{
+ uint32 ID; // 0
+ //char* Name[16]; // 1-15 unused
+ // 16 string flags, unused
+};
+
+// stored in SQL table
+struct SpellThreatEntry
+{
+ uint32 spellId;
+ int32 threat;
+};
+
+struct SpellRadiusEntry
+{
+ uint32 ID;
+ float radiusHostile;
+ //uint32 Unk //always 0
+ float radiusFriend;
+};
+
+struct SpellRangeEntry
+{
+ uint32 ID;
+ float minRangeHostile;
+ float minRangeFriend;
+ float maxRangeHostile;
+ float maxRangeFriend; //friend means unattackable unit here
+ uint32 type;
+ //char* Name[16]; // 7-23 unused
+ // 24 string flags, unused
+ //char* Name2[16]; // 25-40 unused
+ // 41 string flags, unused
+};
+
+struct SpellRuneCostEntry
+{
+ uint32 ID; // 0
+ uint32 RuneCost[3]; // 1-3 (0=blood, 1=frost, 2=unholy)
+ uint32 runePowerGain; // 4
+
+ bool NoRuneCost() const { return RuneCost[0] == 0 && RuneCost[1] == 0 && RuneCost[2] == 0; }
+ bool NoRunicPowerGain() const { return runePowerGain == 0; }
+};
+
+struct SpellShapeshiftEntry
+{
+ uint32 ID; // 0
+ //uint32 buttonPosition; // 1 unused
+ //char* Name[16]; // 2-17 unused
+ //uint32 NameFlags; // 18 unused
+ uint32 flags1; // 19
+ int32 creatureType; // 20 <=0 humanoid, other normal creature types
+ //uint32 unk1; // 21 unused
+ uint32 attackSpeed; // 22
+ //uint32 modelID; // 23 unused, alliance modelid (where horde case?)
+ //uint32 unk2; // 24 unused
+ //uint32 unk3; // 25 unused
+ //uint32 unk4; // 26 unused
+ //uint32 unk5; // 27 unused
+ //uint32 unk6; // 28 unused
+ //uint32 unk7; // 29 unused
+ //uint32 unk8; // 30 unused
+ //uint32 unk9; // 31 unused
+ //uint32 unk10; // 32 unused
+ //uint32 unk11; // 33 unused
+ //uint32 unk12; // 34 unused
+};
+
+struct SpellDurationEntry
+{
+ uint32 ID;
+ int32 Duration[3];
+};
+
+struct SpellItemEnchantmentEntry
+{
+ uint32 ID; // 0 m_ID
+ //uint32 charges; // 1 m_charges
+ uint32 type[3]; // 2-4 m_effect[3]
+ uint32 amount[3]; // 5-7 m_effectPointsMin[3]
+ //uint32 amount2[3] // 8-10 m_effectPointsMax[3]
+ uint32 spellid[3]; // 11-13 m_effectArg[3]
+ char* description[16]; // 14-29 m_name_lang[16]
+ //uint32 descriptionFlags; // 30 name flags
+ uint32 aura_id; // 31 m_itemVisual
+ uint32 slot; // 32 m_flags
+ uint32 GemID; // 33 m_src_itemID
+ uint32 EnchantmentCondition; // 34 m_condition_id
+ //uint32 requiredSkill; // 35 m_requiredSkillID
+ //uint32 requiredSkillValue; // 36 m_requiredSkillRank
+};
+
+struct SpellItemEnchantmentConditionEntry
+{
+ uint32 ID; // 0 m_ID
+ uint8 Color[5]; // 1-5 m_lt_operandType[5]
+ //uint32 LT_Operand[5]; // 6-10 m_lt_operand[5]
+ uint8 Comparator[5]; // 11-15 m_operator[5]
+ uint8 CompareColor[5]; // 15-20 m_rt_operandType[5]
+ uint32 Value[5]; // 21-25 m_rt_operand[5]
+ //uint8 Logic[5] // 25-30 m_logic[5]
+};
+
+struct StableSlotPricesEntry
+{
+ uint32 Slot;
+ uint32 Price;
+};
+
+struct SummonPropertiesEntry
+{
+ uint32 Id; // 0
+ uint32 Category; // 1, 0 - can't be controlled?, 1 - something guardian?, 2 - pet?, 3 - something controllable?, 4 - taxi/mount?
+ uint32 Faction; // 2, 14 rows > 0
+ uint32 Type; // 3, see enum
+ uint32 Slot; // 4, 0-6
+ uint32 Flags; // 5
+};
+
+#define MAX_TALENT_RANK 5
+#define MAX_PET_TALENT_RANK 3 // use in calculations, expected <= MAX_TALENT_RANK
+
+struct TalentEntry
+{
+ uint32 TalentID; // 0
+ uint32 TalentTab; // 1 index in TalentTab.dbc (TalentTabEntry)
+ uint32 Row; // 2
+ uint32 Col; // 3
+ uint32 RankID[MAX_TALENT_RANK]; // 4-8
+ // 9-12 not used, always 0, maybe not used high ranks
+ uint32 DependsOn; // 13 index in Talent.dbc (TalentEntry)
+ // 14-15 not used
+ uint32 DependsOnRank; // 16
+ // 17-18 not used
+ //uint32 needAddInSpellBook; // 19 also need disable higest ranks on reset talent tree
+ //uint32 unk2; // 20, all 0
+ //uint64 allowForPet; // 21 its a 64 bit mask for pet 1<<m_categoryEnumID in CreatureFamily.dbc
+};
+
+struct TalentTabEntry
+{
+ uint32 TalentTabID; // 0
+ //char* name[16]; // 1-16, unused
+ //uint32 nameFlags; // 17, unused
+ //unit32 spellicon; // 18
+ // 19 not used
+ uint32 ClassMask; // 20
+ uint32 petTalentMask; // 21
+ uint32 tabpage; // 22
+ //char* internalname; // 23
+};
+
+struct TaxiNodesEntry
+{
+ uint32 ID; // 0 m_ID
+ uint32 map_id; // 1 m_ContinentID
+ float x; // 2 m_x
+ float y; // 3 m_y
+ float z; // 4 m_z
+ char* name[16]; // 5-21 m_Name_lang
+ // 22 string flags
+ uint32 MountCreatureID[2]; // 23-24 m_MountCreatureID[2]
+};
+
+struct TaxiPathEntry
+{
+ uint32 ID; // 0 m_ID
+ uint32 from; // 1 m_FromTaxiNode
+ uint32 to; // 2 m_ToTaxiNode
+ uint32 price; // 3 m_Cost
+};
+
+struct TaxiPathNodeEntry
+{
+ // 0 m_ID
+ uint32 path; // 1 m_PathID
+ uint32 index; // 2 m_NodeIndex
+ uint32 mapid; // 3 m_ContinentID
+ float x; // 4 m_LocX
+ float y; // 5 m_LocY
+ float z; // 6 m_LocZ
+ uint32 actionFlag; // 7 m_flags
+ uint32 delay; // 8 m_delay
+ // 9 m_arrivalEventID
+ // 10 m_departureEventID
+};
+
+struct TotemCategoryEntry
+{
+ uint32 ID; // 0
+ //char* name[16]; // 1-16
+ // 17 string flags, unused
+ uint32 categoryType; // 18 (one for specialization)
+ uint32 categoryMask; // 19 (compatibility mask for same type: different for totems, compatible from high to low for rods)
+};
+
+struct VehicleEntry
+{
+ uint32 m_ID; // 0
+ uint32 m_flags; // 1
+ float m_turnSpeed; // 2
+ float m_pitchSpeed; // 3
+ float m_pitchMin; // 4
+ float m_pitchMax; // 5
+ uint32 m_seatID[8]; // 6-13
+ float m_mouseLookOffsetPitch; // 14
+ float m_cameraFadeDistScalarMin; // 15
+ float m_cameraFadeDistScalarMax; // 16
+ float m_cameraPitchOffset; // 17
+ int m_powerType[3]; // 18-20
+ int m_powerToken[3]; // 21-23
+ float m_facingLimitRight; // 24
+ float m_facingLimitLeft; // 25
+ float m_msslTrgtTurnLingering; // 26
+ float m_msslTrgtPitchLingering; // 27
+ float m_msslTrgtMouseLingering; // 28
+ float m_msslTrgtEndOpacity; // 29
+ float m_msslTrgtArcSpeed; // 30
+ float m_msslTrgtArcRepeat; // 31
+ float m_msslTrgtArcWidth; // 32
+ float m_msslTrgtImpactRadius[2]; // 33-34
+ char* m_msslTrgtArcTexture; // 35
+ char* m_msslTrgtImpactTexture; // 36
+ char* m_msslTrgtImpactModel[2]; // 37-38
+ float m_cameraYawOffset; // 39
+ uint32 m_uiLocomotionType; // 40
+ float m_msslTrgtImpactTexRadius; // 41
+ uint32 m_uiSeatIndicatorType; // 42
+};
+
+struct VehicleSeatEntry
+{
+ uint32 m_ID; // 0
+ uint32 m_flags; // 1
+ int32 m_attachmentID; // 2
+ float m_attachmentOffsetX; // 3
+ float m_attachmentOffsetY; // 4
+ float m_attachmentOffsetZ; // 5
+ float m_enterPreDelay; // 6
+ float m_enterSpeed; // 7
+ float m_enterGravity; // 8
+ float m_enterMinDuration; // 9
+ float m_enterMaxDuration; // 10
+ float m_enterMinArcHeight; // 11
+ float m_enterMaxArcHeight; // 12
+ int32 m_enterAnimStart; // 13
+ int32 m_enterAnimLoop; // 14
+ int32 m_rideAnimStart; // 15
+ int32 m_rideAnimLoop; // 16
+ int32 m_rideUpperAnimStart; // 17
+ int32 m_rideUpperAnimLoop; // 18
+ float m_exitPreDelay; // 19
+ float m_exitSpeed; // 20
+ float m_exitGravity; // 21
+ float m_exitMinDuration; // 22
+ float m_exitMaxDuration; // 23
+ float m_exitMinArcHeight; // 24
+ float m_exitMaxArcHeight; // 25
+ int32 m_exitAnimStart; // 26
+ int32 m_exitAnimLoop; // 27
+ int32 m_exitAnimEnd; // 28
+ float m_passengerYaw; // 29
+ float m_passengerPitch; // 30
+ float m_passengerRoll; // 31
+ int32 m_passengerAttachmentID; // 32
+ int32 m_vehicleEnterAnim; // 33
+ int32 m_vehicleExitAnim; // 34
+ int32 m_vehicleRideAnimLoop; // 35
+ int32 m_vehicleEnterAnimBone; // 36
+ int32 m_vehicleExitAnimBone; // 37
+ int32 m_vehicleRideAnimLoopBone; // 38
+ float m_vehicleEnterAnimDelay; // 39
+ float m_vehicleExitAnimDelay; // 40
+ uint32 m_vehicleAbilityDisplay; // 41
+ uint32 m_enterUISoundID; // 42
+ uint32 m_exitUISoundID; // 43
+ int32 m_uiSkin; // 44
+ uint32 m_flagsB; // 45
+
+ bool IsUsable() const { return m_flags & 0x2000000; }
+};
+
+struct WorldMapAreaEntry
+{
+ //uint32 ID; // 0
+ uint32 map_id; // 1
+ uint32 area_id; // 2 index (continent 0 areas ignored)
+ //char* internal_name // 3
+ float y1; // 4
+ float y2; // 5
+ float x1; // 6
+ float x2; // 7
+ int32 virtual_map_id; // 8 -1 (map_id have correct map) other: virtual map where zone show (map_id - where zone in fact internally)
+ // int32 dungeonMap_id; // 9 pointer to DungeonMap.dbc (owerride x1,x2,y1,y2 coordinates)
+};
+
+#define MAX_WORLD_MAP_OVERLAY_AREA_IDX 4
+
+struct WorldMapOverlayEntry
+{
+ uint32 ID; // 0
+ //uint32 worldMapAreaId; // 1 idx in WorldMapArea.dbc
+ uint32 areatableID[MAX_WORLD_MAP_OVERLAY_AREA_IDX]; // 2-5
+ // 6-7 always 0, possible part of areatableID[]
+ //char* internal_name // 8
+ // 9-16 some ints
+};
+
+struct WorldSafeLocsEntry
+{
+ uint32 ID; // 0
+ uint32 map_id; // 1
+ float x; // 2
+ float y; // 3
+ float z; // 4
+ //char* name[16] // 5-20 name, unused
+ // 21 name flags, unused
+};
+
+// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
+#if defined( __GNUC__ )
+#pragma pack()
+#else
+#pragma pack(pop)
+#endif
+
+// Structures not used for casting to loaded DBC data and not required then packing
+struct TalentSpellPos
+{
+ TalentSpellPos() : talent_id(0), rank(0) {}
+ TalentSpellPos(uint16 _talent_id, uint8 _rank) : talent_id(_talent_id), rank(_rank) {}
+
+ uint16 talent_id;
+ uint8 rank;
+};
+
+typedef std::map<uint32,TalentSpellPos> TalentSpellPosMap;
+
+struct TaxiPathBySourceAndDestination
+{
+ TaxiPathBySourceAndDestination() : ID(0),price(0) {}
+ TaxiPathBySourceAndDestination(uint32 _id,uint32 _price) : ID(_id),price(_price) {}
+
+ uint32 ID;
+ uint32 price;
+};
+typedef std::map<uint32,TaxiPathBySourceAndDestination> TaxiPathSetForSource;
+typedef std::map<uint32,TaxiPathSetForSource> TaxiPathSetBySource;
+
+struct TaxiPathNode
+{
+ TaxiPathNode() : mapid(0), x(0),y(0),z(0),actionFlag(0),delay(0) {}
+ TaxiPathNode(uint32 _mapid, float _x, float _y, float _z, uint32 _actionFlag, uint32 _delay) : mapid(_mapid), x(_x),y(_y),z(_z),actionFlag(_actionFlag),delay(_delay) {}
+
+ uint32 mapid;
+ float x;
+ float y;
+ float z;
+ uint32 actionFlag;
+ uint32 delay;
+};
+typedef std::vector<TaxiPathNode> TaxiPathNodeList;
+typedef std::vector<TaxiPathNodeList> TaxiPathNodesByPath;
+
+#define TaxiMaskSize 12
+typedef uint32 TaxiMask[TaxiMaskSize];
+#endif
+
diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h
new file mode 100644
index 00000000000..9187cc85e3d
--- /dev/null
+++ b/src/game/DBCfmt.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MANGOS_DBCSFRM_H
+#define MANGOS_DBCSFRM_H
+
+const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
+const char AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiixix";
+const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx";
+const char AreaGroupEntryfmt[]="niiiiiii";
+const char AreaPOIEntryfmt[]="nxxxxxxxxxxxfffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix";
+const char AreaTriggerEntryfmt[]="niffffffff";
+const char AuctionHouseEntryfmt[]="niiixxxxxxxxxxxxxxxxx";
+const char BankBagSlotPricesEntryfmt[]="ni";
+const char BarberShopStyleEntryfmt[]="nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii";
+const char BattlemasterListEntryfmt[]="niiiiiiiiiiiixxxssssssssssssssssxx";
+const char CharStartOutfitEntryfmt[]="diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char CharTitlesEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi";
+const char ChatChannelsEntryfmt[]="iixssssssssssssssssxxxxxxxxxxxxxxxxxx";
+ // ChatChannelsEntryfmt, index not used (more compact store)
+const char ChrClassesEntryfmt[]="nxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii";
+const char ChrRacesEntryfmt[]="nxixiixxixxxxissssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi";
+const char CinematicSequencesEntryfmt[]="nxxxxxxxxx";
+const char CreatureDisplayInfofmt[]="nxxxfxxxxxxxxxxx";
+const char CreatureFamilyfmt[]="nfifiiiiixssssssssssssssssxx";
+const char CreatureSpellDatafmt[]="niiiixxxx";
+const char CreatureTypefmt[]="nxxxxxxxxxxxxxxxxxx";
+const char CurrencyTypesfmt[]="xnxi";
+const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
+const char DurabilityQualityfmt[]="nf";
+const char EmotesEntryfmt[]="nxxiiix";
+const char EmotesTextEntryfmt[]="nxixxxxxxxxxxxxxxxx";
+const char FactionEntryfmt[]="niiiiiiiiiiiiiiiiiissssssssssssssssxxxxxxxxxxxxxxxxxx";
+const char FactionTemplateEntryfmt[]="niiiiiiiiiiiii";
+const char GameObjectDisplayInfofmt[]="nxxxxxxxxxxxffffffx";
+const char GemPropertiesEntryfmt[]="nixxi";
+const char GlyphPropertiesfmt[]="niii";
+const char GlyphSlotfmt[]="nii";
+const char GtBarberShopCostBasefmt[]="f";
+const char GtCombatRatingsfmt[]="f";
+const char GtChanceToMeleeCritBasefmt[]="f";
+const char GtChanceToMeleeCritfmt[]="f";
+const char GtChanceToSpellCritBasefmt[]="f";
+const char GtChanceToSpellCritfmt[]="f";
+const char GtOCTRegenHPfmt[]="f";
+//const char GtOCTRegenMPfmt[]="f";
+const char GtRegenHPPerSptfmt[]="f";
+const char GtRegenMPPerSptfmt[]="f";
+const char Holidaysfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char Itemfmt[]="niiiiiii";
+const char ItemBagFamilyfmt[]="nxxxxxxxxxxxxxxxxx";
+//const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";
+//const char ItemCondExtCostsEntryfmt[]="xiii";
+const char ItemExtendedCostEntryfmt[]="niiiiiiiiiiiiix";
+const char ItemLimitCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxix";
+const char ItemRandomPropertiesfmt[]="nxiiiiixxxxxxxxxxxxxxxxx";
+const char ItemRandomSuffixfmt[]="nxxxxxxxxxxxxxxxxxxiiiiiiiiii";
+const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii";
+const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
+const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char MapEntryfmt[]="nxixssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiffiixxix";
+const char MovieEntryfmt[]="nxx";
+const char QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx";
+const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii";
+const char ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiii";
+const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiii";
+const char SkillLinefmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxx";
+const char SkillLineAbilityfmt[]="niiiixxiiiiixx";
+const char SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char SpellCastTimefmt[]="nixx";
+const char SpellDurationfmt[]="niii";
+const char SpellEntryfmt[]="niiiiiiiiixiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiixfffxxxiiiiix";
+const char SpellFocusObjectfmt[]="nxxxxxxxxxxxxxxxxx";
+const char SpellItemEnchantmentfmt[]="nxiiiiiixxxiiissssssssssssssssxiiiixx";
+const char SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX";
+const char SpellRadiusfmt[]="nfxf";
+const char SpellRangefmt[]="nffffixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char SpellRuneCostfmt[]="niiii";
+const char SpellShapeshiftfmt[]="nxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxx";
+const char StableSlotPricesfmt[] = "ni";
+const char SummonPropertiesfmt[] = "niiiii";
+const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxxxx";
+const char TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiiix";
+const char TaxiNodesEntryfmt[]="nifffssssssssssssssssxii";
+const char TaxiPathEntryfmt[]="niii";
+const char TaxiPathNodeEntryfmt[]="diiifffiixx";
+const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
+const char VehicleEntryfmt[]="niffffiiiiiiiiffffiiiiiifffffffffffssssfifi";
+const char VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiii";
+const char WorldMapAreaEntryfmt[]="xinxffffix";
+const char WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxxxx";
+const char WorldSafeLocsEntryfmt[]="nifffxxxxxxxxxxxxxxxxx";
+
+#endif
diff --git a/src/game/Debugcmds.cpp b/src/game/Debugcmds.cpp
index 3bf64188e34..fda50f8b9a6 100644
--- a/src/game/Debugcmds.cpp
+++ b/src/game/Debugcmds.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,37 +21,23 @@
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "WorldPacket.h"
-#include "WorldSession.h"
-#include "World.h"
+#include "Vehicle.h"
#include "Player.h"
#include "Opcodes.h"
#include "Chat.h"
#include "Log.h"
#include "Unit.h"
-#include "ObjectAccessor.h"
#include "GossipDef.h"
#include "Language.h"
-#include "MapManager.h"
#include "BattleGroundMgr.h"
#include <fstream>
#include "ObjectMgr.h"
+#include "Cell.h"
+#include "CellImpl.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
-bool ChatHandler::HandleDebugInArcCommand(const char* /*args*/)
-{
- Object *obj = getSelectedUnit();
-
- if(!obj)
- {
- SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
- return true;
- }
-
- SendSysMessage(LANG_NOT_IMPLEMENTED);
-
- return true;
-}
-
-bool ChatHandler::HandleDebugSpellFailCommand(const char* args)
+bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args)
{
if(!args)
return false;
@@ -61,16 +47,31 @@ bool ChatHandler::HandleDebugSpellFailCommand(const char* args)
return false;
uint8 failnum = (uint8)atoi(px);
+ if(failnum==0 && *px!='0')
+ return false;
+
+ char* p1 = strtok(NULL, " ");
+ uint8 failarg1 = p1 ? (uint8)atoi(p1) : 0;
+
+ char* p2 = strtok(NULL, " ");
+ uint8 failarg2 = p2 ? (uint8)atoi(p2) : 0;
+
WorldPacket data(SMSG_CAST_FAILED, 5);
+ data << uint8(0);
data << uint32(133);
data << uint8(failnum);
+ if(p1 || p2)
+ data << uint32(failarg1);
+ if(p2)
+ data << uint32(failarg2);
+
m_session->SendPacket(&data);
return true;
}
-bool ChatHandler::HandleSetPoiCommand(const char* args)
+bool ChatHandler::HandleDebugSendPoiCommand(const char* args)
{
Player *pPlayer = m_session->GetPlayer();
Unit* target = getSelectedUnit();
@@ -89,9 +90,6 @@ bool ChatHandler::HandleSetPoiCommand(const char* args)
return false;
uint32 icon = atol(icon_text);
- if ( icon < 0 )
- icon = 0;
-
uint32 flags = atol(flags_text);
sLog.outDetail("Command : POI, NPC = %u, icon = %u flags = %u", target->GetGUIDLow(), icon,flags);
@@ -99,7 +97,7 @@ bool ChatHandler::HandleSetPoiCommand(const char* args)
return true;
}
-bool ChatHandler::HandleEquipErrorCommand(const char* args)
+bool ChatHandler::HandleDebugSendEquipErrorCommand(const char* args)
{
if(!args)
return false;
@@ -109,7 +107,7 @@ bool ChatHandler::HandleEquipErrorCommand(const char* args)
return true;
}
-bool ChatHandler::HandleSellErrorCommand(const char* args)
+bool ChatHandler::HandleDebugSendSellErrorCommand(const char* args)
{
if(!args)
return false;
@@ -119,7 +117,7 @@ bool ChatHandler::HandleSellErrorCommand(const char* args)
return true;
}
-bool ChatHandler::HandleBuyErrorCommand(const char* args)
+bool ChatHandler::HandleDebugSendBuyErrorCommand(const char* args)
{
if(!args)
return false;
@@ -129,7 +127,7 @@ bool ChatHandler::HandleBuyErrorCommand(const char* args)
return true;
}
-bool ChatHandler::HandleSendOpcodeCommand(const char* /*args*/)
+bool ChatHandler::HandleDebugSendOpcodeCommand(const char* /*args*/)
{
Unit *unit = getSelectedUnit();
Player *player = NULL;
@@ -192,14 +190,46 @@ bool ChatHandler::HandleSendOpcodeCommand(const char* /*args*/)
ifs >> val6;
data << val6;
}
- else if(type == "pguid")
+ else if(type == "appitsguid")
{
data.append(unit->GetPackGUID());
}
- else if(type == "myguid")
+ else if(type == "appmyguid")
{
data.append(player->GetPackGUID());
}
+ else if(type == "appgoguid")
+ {
+ GameObject *obj = GetNearbyGameObject();
+ if(!obj)
+ {
+ PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, 0);
+ SetSentErrorMessage(true);
+ ifs.close();
+ return false;
+ }
+ data.append(obj->GetPackGUID());
+ }
+ else if(type == "goguid")
+ {
+ GameObject *obj = GetNearbyGameObject();
+ if(!obj)
+ {
+ PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, 0);
+ SetSentErrorMessage(true);
+ ifs.close();
+ return false;
+ }
+ data << uint64(obj->GetGUID());
+ }
+ else if(type == "myguid")
+ {
+ data << uint64(player->GetGUID());
+ }
+ else if(type == "itsguid")
+ {
+ data << uint64(unit->GetGUID());
+ }
else if(type == "pos")
{
data << unit->GetPositionX();
@@ -221,12 +251,12 @@ bool ChatHandler::HandleSendOpcodeCommand(const char* /*args*/)
ifs.close();
sLog.outDebug("Sending opcode %u", data.GetOpcode());
data.hexlike();
- ((Player*)unit)->GetSession()->SendPacket(&data);
+ player->GetSession()->SendPacket(&data);
PSendSysMessage(LANG_COMMAND_OPCODESENT, data.GetOpcode(), unit->GetName());
return true;
}
-bool ChatHandler::HandleUpdateWorldStateCommand(const char* args)
+bool ChatHandler::HandleDebugUpdateWorldStateCommand(const char* args)
{
char* w = strtok((char*)args, " ");
char* s = strtok(NULL, " ");
@@ -240,18 +270,94 @@ bool ChatHandler::HandleUpdateWorldStateCommand(const char* args)
return true;
}
-bool ChatHandler::HandlePlaySound2Command(const char* args)
+bool ChatHandler::HandleDebugPlayCinematicCommand(const char* args)
{
- if(!args)
+ // USAGE: .debug play cinematic #cinematicid
+ // #cinematicid - ID decimal number from CinemaicSequences.dbc (1st column)
+ if( !*args )
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 dwId = atoi((char*)args);
+
+ if(!sCinematicSequencesStore.LookupEntry(dwId))
+ {
+ PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, dwId);
+ SetSentErrorMessage(true);
return false;
+ }
- uint32 soundid = atoi(args);
- m_session->GetPlayer()->PlaySound(soundid, false);
+ m_session->GetPlayer()->SendCinematicStart(dwId);
+ return true;
+}
+
+bool ChatHandler::HandleDebugPlayMovieCommand(const char* args)
+{
+ // USAGE: .debug play movie #movieid
+ // #movieid - ID decimal number from Movie.dbc (1st column)
+ if( !*args )
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 dwId = atoi((char*)args);
+
+ if(!sMovieStore.LookupEntry(dwId))
+ {
+ PSendSysMessage(LANG_MOVIE_NOT_EXIST, dwId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ m_session->GetPlayer()->SendMovieStart(dwId);
+ return true;
+}
+
+//Play sound
+bool ChatHandler::HandleDebugPlaySoundCommand(const char* args)
+{
+ // USAGE: .debug playsound #soundid
+ // #soundid - ID decimal number from SoundEntries.dbc (1st column)
+ if( !*args )
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 dwSoundId = atoi((char*)args);
+
+ if(!sSoundEntriesStore.LookupEntry(dwSoundId))
+ {
+ PSendSysMessage(LANG_SOUND_NOT_EXIST, dwSoundId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Unit* unit = getSelectedUnit();
+ if(!unit)
+ {
+ SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(m_session->GetPlayer()->GetSelection())
+ unit->PlayDistanceSound(dwSoundId,m_session->GetPlayer());
+ else
+ unit->PlayDirectSound(dwSoundId,m_session->GetPlayer());
+
+ PSendSysMessage(LANG_YOU_HEAR_SOUND, dwSoundId);
return true;
}
//Send notification in channel
-bool ChatHandler::HandleSendChannelNotifyCommand(const char* args)
+bool ChatHandler::HandleDebugSendChannelNotifyCommand(const char* args)
{
if(!args)
return false;
@@ -269,7 +375,7 @@ bool ChatHandler::HandleSendChannelNotifyCommand(const char* args)
}
//Send notification in chat
-bool ChatHandler::HandleSendChatMsgCommand(const char* args)
+bool ChatHandler::HandleDebugSendChatMsgCommand(const char* args)
{
if(!args)
return false;
@@ -282,15 +388,14 @@ bool ChatHandler::HandleSendChatMsgCommand(const char* args)
return true;
}
-bool ChatHandler::HandleSendQuestPartyMsgCommand(const char* args)
+bool ChatHandler::HandleDebugSendQuestPartyMsgCommand(const char* args)
{
uint32 msg = atol((char*)args);
- if (msg >= 0)
- m_session->GetPlayer()->SendPushToPartyResponse(m_session->GetPlayer(), msg);
+ m_session->GetPlayer()->SendPushToPartyResponse(m_session->GetPlayer(), msg);
return true;
}
-bool ChatHandler::HandleGetLootRecipient(const char* /*args*/)
+bool ChatHandler::HandleDebugGetLootRecipient(const char* /*args*/)
{
Creature* target = getSelectedCreature();
if(!target)
@@ -300,15 +405,14 @@ bool ChatHandler::HandleGetLootRecipient(const char* /*args*/)
return true;
}
-bool ChatHandler::HandleSendQuestInvalidMsgCommand(const char* args)
+bool ChatHandler::HandleDebugSendQuestInvalidMsgCommand(const char* args)
{
uint32 msg = atol((char*)args);
- if (msg >= 0)
- m_session->GetPlayer()->SendCanTakeQuestResponse(msg);
+ m_session->GetPlayer()->SendCanTakeQuestResponse(msg);
return true;
}
-bool ChatHandler::HandleGetItemState(const char* args)
+bool ChatHandler::HandleDebugGetItemState(const char* args)
{
if (!args)
return false;
@@ -332,7 +436,7 @@ bool ChatHandler::HandleGetItemState(const char* args)
{
state_str = "The player has the following " + state_str + " items: ";
SendSysMessage(state_str.c_str());
- for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++)
+ for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
{
if(i >= BUYBACK_SLOT_START && i < BUYBACK_SLOT_END)
continue;
@@ -349,9 +453,9 @@ bool ChatHandler::HandleGetItemState(const char* args)
Bag *bag = (Bag*)item;
for (uint8 j = 0; j < bag->GetBagSize(); ++j)
{
- Item* item = bag->GetItemByPos(j);
- if (item && item->GetState() == state)
- PSendSysMessage("bag: 255 slot: %d guid: %d owner: %d", item->GetSlot(), item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()));
+ Item* item2 = bag->GetItemByPos(j);
+ if (item2 && item2->GetState() == state)
+ PSendSysMessage("bag: 255 slot: %d guid: %d owner: %d", item2->GetSlot(), item2->GetGUIDLow(), GUID_LOPART(item2->GetOwnerGUID()));
}
}
}
@@ -360,7 +464,7 @@ bool ChatHandler::HandleGetItemState(const char* args)
if (list_queue)
{
std::vector<Item *> &updateQueue = player->GetItemUpdateQueue();
- for(size_t i = 0; i < updateQueue.size(); i++)
+ for(size_t i = 0; i < updateQueue.size(); ++i)
{
Item *item = updateQueue[i];
if(!item) continue;
@@ -387,7 +491,7 @@ bool ChatHandler::HandleGetItemState(const char* args)
{
bool error = false;
std::vector<Item *> &updateQueue = player->GetItemUpdateQueue();
- for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++)
+ for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
{
if(i >= BUYBACK_SLOT_START && i < BUYBACK_SLOT_END)
continue;
@@ -445,65 +549,65 @@ bool ChatHandler::HandleGetItemState(const char* args)
Bag *bag = (Bag*)item;
for (uint8 j = 0; j < bag->GetBagSize(); ++j)
{
- Item* item = bag->GetItemByPos(j);
- if (!item) continue;
+ Item* item2 = bag->GetItemByPos(j);
+ if (!item2) continue;
- if (item->GetSlot() != j)
+ if (item2->GetSlot() != j)
{
- PSendSysMessage("the item in bag %d slot %d, guid %d has an incorrect slot value: %d", bag->GetSlot(), j, item->GetGUIDLow(), item->GetSlot());
+ PSendSysMessage("the item in bag %d slot %d, guid %d has an incorrect slot value: %d", bag->GetSlot(), j, item2->GetGUIDLow(), item2->GetSlot());
error = true; continue;
}
- if (item->GetOwnerGUID() != player->GetGUID())
+ if (item2->GetOwnerGUID() != player->GetGUID())
{
- PSendSysMessage("for the item in bag %d at slot %d and itemguid %d, owner's guid (%d) and player's guid (%d) don't match!", bag->GetSlot(), item->GetSlot(), item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow());
+ PSendSysMessage("for the item in bag %d at slot %d and itemguid %d, owner's guid (%d) and player's guid (%d) don't match!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), GUID_LOPART(item2->GetOwnerGUID()), player->GetGUIDLow());
error = true; continue;
}
- Bag *container = item->GetContainer();
+ Bag *container = item2->GetContainer();
if (!container)
{
- PSendSysMessage("the item in bag %d at slot %d with guid %d has no container!", bag->GetSlot(), item->GetSlot(), item->GetGUIDLow());
+ PSendSysMessage("the item in bag %d at slot %d with guid %d has no container!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow());
error = true; continue;
}
if (container != bag)
{
- PSendSysMessage("the item in bag %d at slot %d with guid %d has a different container(slot %d guid %d)!", bag->GetSlot(), item->GetSlot(), item->GetGUIDLow(), container->GetSlot(), container->GetGUIDLow());
+ PSendSysMessage("the item in bag %d at slot %d with guid %d has a different container(slot %d guid %d)!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), container->GetSlot(), container->GetGUIDLow());
error = true; continue;
}
- if (item->IsInUpdateQueue())
+ if (item2->IsInUpdateQueue())
{
- uint16 qp = item->GetQueuePos();
+ uint16 qp = item2->GetQueuePos();
if (qp > updateQueue.size())
{
- PSendSysMessage("item in bag: %d at slot: %d guid: %d has a queuepos (%d) larger than the update queue size! ", bag->GetSlot(), item->GetSlot(), item->GetGUIDLow(), qp);
+ PSendSysMessage("item in bag: %d at slot: %d guid: %d has a queuepos (%d) larger than the update queue size! ", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp);
error = true; continue;
}
if (updateQueue[qp] == NULL)
{
- PSendSysMessage("item in bag: %d at slot: %d guid: %d has a queuepos (%d) that points to NULL in the queue!", bag->GetSlot(), item->GetSlot(), item->GetGUIDLow(), qp);
+ PSendSysMessage("item in bag: %d at slot: %d guid: %d has a queuepos (%d) that points to NULL in the queue!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp);
error = true; continue;
}
- if (updateQueue[qp] != item)
+ if (updateQueue[qp] != item2)
{
- PSendSysMessage("item in bag: %d at slot: %d guid: %d has has a queuepos (%d) that points to another item in the queue (bag: %d, slot: %d, guid: %d)", bag->GetSlot(), item->GetSlot(), item->GetGUIDLow(), qp, updateQueue[qp]->GetBagSlot(), updateQueue[qp]->GetSlot(), updateQueue[qp]->GetGUIDLow());
+ PSendSysMessage("item in bag: %d at slot: %d guid: %d has has a queuepos (%d) that points to another item in the queue (bag: %d, slot: %d, guid: %d)", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp, updateQueue[qp]->GetBagSlot(), updateQueue[qp]->GetSlot(), updateQueue[qp]->GetGUIDLow());
error = true; continue;
}
}
- else if (item->GetState() != ITEM_UNCHANGED)
+ else if (item2->GetState() != ITEM_UNCHANGED)
{
- PSendSysMessage("item in bag: %d at slot: %d guid: %d is not in queue but should be (state: %d)!", bag->GetSlot(), item->GetSlot(), item->GetGUIDLow(), item->GetState());
+ PSendSysMessage("item in bag: %d at slot: %d guid: %d is not in queue but should be (state: %d)!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), item2->GetState());
error = true; continue;
}
}
}
}
- for(size_t i = 0; i < updateQueue.size(); i++)
+ for(size_t i = 0; i < updateQueue.size(); ++i)
{
Item *item = updateQueue[i];
if(!item) continue;
@@ -542,6 +646,12 @@ bool ChatHandler::HandleGetItemState(const char* args)
return true;
}
+bool ChatHandler::HandleDebugBattlegroundCommand(const char * /*args*/)
+{
+ sBattleGroundMgr.ToggleTesting();
+ return true;
+}
+
bool ChatHandler::HandleDebugArenaCommand(const char * /*args*/)
{
sBattleGroundMgr.ToggleArenaTesting();
@@ -591,3 +701,162 @@ bool ChatHandler::HandleDebugHostilRefList(const char * /*args*/)
return true;
}
+bool ChatHandler::HandleDebugSetVehicleId(const char *args)
+{
+ Unit* target = getSelectedUnit();
+ if(!target || target->GetTypeId() != TYPEID_UNIT || !((Creature*)target)->isVehicle())
+ return false;
+
+ if(!args)
+ return false;
+
+ char* i = strtok((char*)args, " ");
+ if(!i)
+ return false;
+
+ uint32 id = (uint32)atoi(i);
+ ((Vehicle*)target)->SetVehicleId(id);
+ target->SendUpdateObjectToAllExcept(NULL);
+ PSendSysMessage("Vehicle id set to %u", id);
+ return true;
+}
+
+bool ChatHandler::HandleDebugEnterVehicle(const char * args)
+{
+ Unit* target = getSelectedUnit();
+ if(!target || target->GetTypeId() != TYPEID_UNIT || !((Creature*)target)->isVehicle())
+ return false;
+
+ if(!args)
+ return false;
+
+ char* i = strtok((char*)args, " ");
+ if(!i)
+ return false;
+
+ char* j = strtok(NULL, " ");
+
+ uint32 entry = (uint32)atoi(i);
+ int8 seatId = j ? (int8)atoi(j) : -1;
+
+ if(!entry)
+ m_session->GetPlayer()->EnterVehicle((Vehicle*)target, seatId);
+ else
+ {
+ Creature *passenger = NULL;
+ Trinity::AllCreaturesOfEntryInRange check(m_session->GetPlayer(), entry, 20.0f);
+ Trinity::CreatureSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(m_session->GetPlayer(), passenger, check);
+ m_session->GetPlayer()->VisitNearbyObject(30.0f, searcher);
+ if(!passenger || passenger == target)
+ return false;
+ passenger->EnterVehicle((Vehicle*)target, seatId);
+ }
+
+ PSendSysMessage("Unit %u entered vehicle %d", entry, (int32)seatId);
+ return true;
+}
+
+bool ChatHandler::HandleDebugSpawnVehicle(const char* args)
+{
+ if(!args)
+ return false;
+
+ char* e = strtok((char*)args, " ");
+ char* i = strtok(NULL, " ");
+
+ if (!e || !i)
+ return false;
+
+ uint32 entry = (uint32)atoi(e);
+ uint32 id = (uint32)atoi(i);
+
+ CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry);
+
+ if(!ci)
+ return false;
+
+ VehicleEntry const *ve = sVehicleStore.LookupEntry(id);
+
+ if(!ve)
+ return false;
+
+ Vehicle *v = new Vehicle;
+ Map *map = m_session->GetPlayer()->GetMap();
+ if(!v->Create(objmgr.GenerateLowGuid(HIGHGUID_VEHICLE), map, m_session->GetPlayer()->GetPhaseMask(), entry, id, m_session->GetPlayer()->GetTeam()))
+ {
+ delete v;
+ return false;
+ }
+
+ float px, py, pz;
+ m_session->GetPlayer()->GetClosePoint(px, py, pz, m_session->GetPlayer()->GetObjectSize());
+
+ v->Relocate(px, py, pz, m_session->GetPlayer()->GetOrientation());
+
+ if(!v->IsPositionValid())
+ {
+ sLog.outError("Vehicle (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
+ v->GetGUIDLow(), v->GetEntry(), v->GetPositionX(), v->GetPositionY());
+ delete v;
+ return false;
+ }
+
+ map->Add((Creature*)v);
+
+ return true;
+}
+
+bool ChatHandler::HandleDebugSendLargePacketCommand(const char* /*args*/)
+{
+ const char* stuffingString = "This is a dummy string to push the packet's size beyond 128000 bytes. ";
+ std::ostringstream ss;
+ while(ss.str().size() < 128000)
+ ss << stuffingString;
+ SendSysMessage(ss.str().c_str());
+ return true;
+}
+
+bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(const char* args)
+{
+ if(!args)
+ return false;
+
+ uint32 PhaseShift = atoi(args);
+ m_session->SendSetPhaseShift(PhaseShift);
+ return true;
+}
+
+bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args)
+{
+ if(!args)
+ return false;
+
+ char* e = strtok((char*)args, " ");
+ char* f = strtok(NULL, " ");
+
+ if (!e || !f)
+ return false;
+
+ uint32 guid = (uint32)atoi(e);
+ uint32 flag = (uint32)atoi(f);
+
+ Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM));
+
+ if(!i)
+ return false;
+
+ i->SetUInt32Value(ITEM_FIELD_FLAGS, flag);
+
+ return true;
+}
+
+//show animation
+bool ChatHandler::HandleDebugAnimCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 anim_id = atoi((char*)args);
+ m_session->GetPlayer()->HandleEmoteCommand(anim_id);
+ return true;
+}
diff --git a/src/game/DestinationHolder.cpp b/src/game/DestinationHolder.cpp
index 904509aeef4..f2158e3b5be 100644
--- a/src/game/DestinationHolder.cpp
+++ b/src/game/DestinationHolder.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/DestinationHolder.h b/src/game/DestinationHolder.h
index bd1b5d5a775..c37b60e8b54 100644
--- a/src/game/DestinationHolder.h
+++ b/src/game/DestinationHolder.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h
index 7dd52b8cb16..0286851cbb7 100644
--- a/src/game/DestinationHolderImp.h
+++ b/src/game/DestinationHolderImp.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
#ifndef TRINITY_DESTINATIONHOLDERIMP_H
#define TRINITY_DESTINATIONHOLDERIMP_H
-#include "Creature.h"
#include "MapManager.h"
#include "DestinationHolder.h"
@@ -85,24 +84,7 @@ DestinationHolder<TRAVELLER>::StartTravel(TRAVELLER &traveller, bool sendMove)
i_fromY = traveller.GetPositionY();
i_fromZ = traveller.GetPositionZ();
- float dx = i_destX - i_fromX;
- float dy = i_destY - i_fromY;
- float dz = i_destZ - i_fromZ;
-
- float dist;
- //Should be for Creature Flying and Swimming.
- if(traveller.GetTraveller().hasUnitState(UNIT_STAT_IN_FLIGHT))
- dist = sqrt((dx*dx) + (dy*dy) + (dz*dz));
- else //Walking on the ground
- dist = sqrt((dx*dx) + (dy*dy));
-
- float speed;
- if(traveller.GetTraveller().hasUnitState(UNIT_STAT_CHARGING))
- speed = SPEED_CHARGE * 0.001f;
- else
- speed = traveller.Speed() * 0.001f; // speed is in seconds so convert from second to millisecond
- i_totalTravelTime = static_cast<uint32>(dist/speed);
-
+ i_totalTravelTime = traveller.GetTotalTrevelTimeTo(i_destX,i_destY,i_destZ);
i_timeElapsed = 0;
if(sendMove)
traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime);
diff --git a/src/game/DuelHandler.cpp b/src/game/DuelHandler.cpp
index 58506f949e9..aa6563a3f98 100644
--- a/src/game/DuelHandler.cpp
+++ b/src/game/DuelHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,11 +21,9 @@
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "World.h"
#include "Log.h"
#include "Opcodes.h"
#include "UpdateData.h"
-#include "MapManager.h"
#include "Player.h"
void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket)
diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp
index 82076f734f2..8969e4dfe04 100644
--- a/src/game/DynamicObject.cpp
+++ b/src/game/DynamicObject.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,16 +19,11 @@
*/
#include "Common.h"
-#include "GameObject.h"
#include "UpdateMask.h"
#include "Opcodes.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
#include "World.h"
#include "ObjectAccessor.h"
#include "Database/DatabaseEnv.h"
-#include "SpellAuras.h"
-#include "MapManager.h"
#include "GridNotifiers.h"
#include "CellImpl.h"
#include "GridNotifiersImpl.h"
@@ -38,7 +33,7 @@ DynamicObject::DynamicObject() : WorldObject()
m_objectType |= TYPEMASK_DYNAMICOBJECT;
m_objectTypeId = TYPEID_DYNAMICOBJECT;
// 2.3.2 - 0x58
- m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION);
+ m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION);
m_valuesCount = DYNAMICOBJECT_END;
}
@@ -58,8 +53,20 @@ void DynamicObject::RemoveFromWorld()
///- Remove the dynamicObject from the accessor
if(IsInWorld())
{
- ObjectAccessor::Instance().RemoveObject(this);
+ if(m_effIndex == 4)
+ {
+ if(Unit *caster = GetCaster())
+ {
+ if(caster->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)caster)->SetViewpoint(this, false);
+ }
+ else
+ {
+ sLog.outCrash("DynamicObject::RemoveFromWorld cannot find viewpoint owner");
+ }
+ }
WorldObject::RemoveFromWorld();
+ ObjectAccessor::Instance().RemoveObject(this);
}
}
@@ -67,12 +74,12 @@ bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32
{
SetInstanceId(caster->GetInstanceId());
- WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetMapId());
+ WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetMapId(), caster->GetPhaseMask());
Relocate(x,y,z,0);
if(!IsPositionValid())
{
- sLog.outError("ERROR: DynamicObject (spell %u eff %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",spellId,effIndex,GetPositionX(),GetPositionY());
+ sLog.outError("DynamicObject (spell %u eff %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",spellId,effIndex,GetPositionX(),GetPositionY());
return false;
}
@@ -139,6 +146,7 @@ void DynamicObject::Update(uint32 p_time)
void DynamicObject::Delete()
{
SendObjectDeSpawnAnim(GetGUID());
+ RemoveFromWorld();
AddObjectToRemoveList();
}
@@ -147,13 +155,12 @@ void DynamicObject::Delay(int32 delaytime)
m_aliveDuration -= delaytime;
for(AffectedSet::iterator iunit= m_affected.begin();iunit != m_affected.end();++iunit)
if (*iunit)
- (*iunit)->DelayAura(m_spellId, m_effIndex, delaytime);
+ (*iunit)->DelayAura(m_spellId, GetCaster()->GetGUID() , delaytime);
}
bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const
{
return IsInWorld() && u->IsInWorld()
- && (IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false)
- || GetCasterGUID() == u->GetGUID());
+ && (IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false));
}
diff --git a/src/game/DynamicObject.h b/src/game/DynamicObject.h
index 1bcd29998f8..714b639e552 100644
--- a/src/game/DynamicObject.h
+++ b/src/game/DynamicObject.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,14 +50,11 @@ class DynamicObject : public WorldObject
void Delay(int32 delaytime);
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
- void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); }
- void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); }
- void TextEmote(const char* text, uint64 TargetGuid) { MonsterTextEmote(text,TargetGuid); }
- void Whisper(const char* text, uint64 receiver) { MonsterWhisper(text,receiver); }
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
+ void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
GridReference<DynamicObject> &GetGridRef() { return m_gridRef; }
protected:
diff --git a/src/game/FleeingMovementGenerator.cpp b/src/game/FleeingMovementGenerator.cpp
index bd3b8ef443d..31fc350af70 100644
--- a/src/game/FleeingMovementGenerator.cpp
+++ b/src/game/FleeingMovementGenerator.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
*/
#include "Creature.h"
+#include "CreatureAI.h"
#include "MapManager.h"
#include "FleeingMovementGenerator.h"
#include "DestinationHolderImp.h"
@@ -79,7 +80,7 @@ FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
float temp_x, temp_y, angle;
const Map * _map = MapManager::Instance().GetBaseMap(owner.GetMapId());
//primitive path-finding
- for(uint8 i = 0; i < 18; i++)
+ for(uint8 i = 0; i < 18; ++i)
{
if(i_only_forward && i > 2)
break;
@@ -301,19 +302,26 @@ FleeingMovementGenerator<T>::Initialize(T &owner)
if(!&owner)
return;
- Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
- if(!fright)
- return;
-
_Init(owner);
owner.CastStop();
owner.addUnitState(UNIT_STAT_FLEEING);
owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
owner.SetUInt64Value(UNIT_FIELD_TARGET, 0);
owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
- i_caster_x = fright->GetPositionX();
- i_caster_y = fright->GetPositionY();
- i_caster_z = fright->GetPositionZ();
+
+ if(Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
+ {
+ i_caster_x = fright->GetPositionX();
+ i_caster_y = fright->GetPositionY();
+ i_caster_z = fright->GetPositionZ();
+ }
+ else
+ {
+ i_caster_x = owner.GetPositionX();
+ i_caster_y = owner.GetPositionY();
+ i_caster_z = owner.GetPositionZ();
+ }
+
i_only_forward = true;
i_cur_angle = 0.0f;
i_last_distance_from_caster = 0.0f;
@@ -403,3 +411,32 @@ template void FleeingMovementGenerator<Creature>::Reset(Creature &);
template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &);
template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &);
+void TimedFleeingMovementGenerator::Finalize(Unit &owner)
+{
+ owner.clearUnitState(UNIT_STAT_FLEEING);
+ if (Unit* victim = owner.getVictim())
+ {
+ if (owner.isAlive())
+ {
+ owner.AttackStop();
+ ((Creature*)&owner)->AI()->AttackStart(victim);
+ }
+ }
+}
+
+bool TimedFleeingMovementGenerator::Update(Unit & owner, const uint32 & time_diff)
+{
+ if( !owner.isAlive() )
+ return false;
+
+ if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
+ return true;
+
+ i_totalFleeTime.Update(time_diff);
+ if (i_totalFleeTime.Passed())
+ return false;
+
+ // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32 &) version
+ // This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
+ return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff);
+}
diff --git a/src/game/FleeingMovementGenerator.h b/src/game/FleeingMovementGenerator.h
index 6a4f3593370..0bc4bdb9757 100644
--- a/src/game/FleeingMovementGenerator.h
+++ b/src/game/FleeingMovementGenerator.h
@@ -1,7 +1,7 @@
/*
-* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
-* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
#include "MovementGenerator.h"
#include "DestinationHolder.h"
#include "Traveller.h"
-#include "MapManager.h"
template<class T>
class TRINITY_DLL_SPEC FleeingMovementGenerator
@@ -57,10 +56,27 @@ class TRINITY_DLL_SPEC FleeingMovementGenerator
float i_last_distance_from_caster;
float i_to_distance_from_caster;
float i_cur_angle;
- TimeTracker i_nextCheckTime;
uint64 i_frightGUID;
+ TimeTracker i_nextCheckTime;
DestinationHolder< Traveller<T> > i_destinationHolder;
};
+
+class MANGOS_DLL_SPEC TimedFleeingMovementGenerator
+: public FleeingMovementGenerator<Creature>
+{
+ public:
+ TimedFleeingMovementGenerator(uint64 fright, uint32 time) :
+ FleeingMovementGenerator<Creature>(fright),
+ i_totalFleeTime(time) {}
+
+ MovementGeneratorType GetMovementGeneratorType() { return TIMED_FLEEING_MOTION_TYPE; }
+ bool Update(Unit &, const uint32 &);
+ void Finalize(Unit &);
+
+ private:
+ TimeTracker i_totalFleeTime;
+};
+
#endif
diff --git a/src/game/FollowerRefManager.h b/src/game/FollowerRefManager.h
index 136fdbfeadb..093c85adcee 100644
--- a/src/game/FollowerRefManager.h
+++ b/src/game/FollowerRefManager.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/FollowerReference.cpp b/src/game/FollowerReference.cpp
index 44c8e8d55de..173f9881c54 100644
--- a/src/game/FollowerReference.cpp
+++ b/src/game/FollowerReference.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/FollowerReference.h b/src/game/FollowerReference.h
index 16fa880bcfe..3c0b3dc9e7c 100644
--- a/src/game/FollowerReference.h
+++ b/src/game/FollowerReference.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Formulas.h b/src/game/Formulas.h
index f54917be6f3..041c0621c74 100644
--- a/src/game/Formulas.h
+++ b/src/game/Formulas.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@ namespace Trinity
}
namespace XP
{
- typedef enum XPColorChar { RED, ORANGE, YELLOW, GREEN, GRAY };
+ enum XPColorChar { RED, ORANGE, YELLOW, GREEN, GRAY };
inline uint32 GetGrayLevel(uint32 pl_level)
{
@@ -80,8 +80,17 @@ namespace Trinity
inline uint32 BaseGain(uint32 pl_level, uint32 mob_level, ContentLevels content)
{
- //TODO: need modifier for CONTENT_71_80 different from CONTENT_61_70?
- const uint32 nBaseExp = content == CONTENT_1_60 ? 45 : 235;
+ uint32 nBaseExp;
+ switch(content)
+ {
+ case CONTENT_1_60: nBaseExp = 45; break;
+ case CONTENT_61_70: nBaseExp = 235; break;
+ case CONTENT_71_80: nBaseExp = 580; break;
+ default:
+ sLog.outError("BaseGain: Unsupported content level %u",content);
+ nBaseExp = 45; break;
+ }
+
if( mob_level >= pl_level )
{
uint32 nLevelDiff = mob_level - pl_level;
@@ -118,66 +127,6 @@ namespace Trinity
return (uint32)(xp_gain*sWorld.getRate(RATE_XP_KILL));
}
- inline uint32 xp_Diff(uint32 lvl)
- {
- if( lvl < 29 )
- return 0;
- if( lvl == 29 )
- return 1;
- if( lvl == 30 )
- return 3;
- if( lvl == 31 )
- return 6;
- else
- return (5*(lvl-30));
- }
-
- inline uint32 mxp(uint32 lvl)
- {
- if (lvl < 60)
- {
- return (45 + (5*lvl));
- }
- else
- {
- return (235 + (5*lvl));
- }
- }
-
- inline uint32 xp_to_level(uint32 lvl)
- {
- uint32 xp = 0;
- if (lvl < 60)
- {
- xp = (8*lvl + xp_Diff(lvl)) * mxp(lvl);
- }
- else if (lvl == 60)
- {
- xp = (155 + mxp(lvl) * (1344 - 70 - ((69 - lvl) * (7 + (69 - lvl) * 8 - 1)/2)));
- }
- else if (lvl < 70)
- {
- xp = (155 + mxp(lvl) * (1344 - ((69-lvl) * (7 + (69 - lvl) * 8 - 1)/2)));
- }else
- {
- // level higher than 70 is not supported
- xp = (uint32)(779700 * (pow(sWorld.getRate(RATE_XP_PAST_70), (int32)lvl - 69)));
- return ((xp < 0x7fffffff) ? xp : 0x7fffffff);
- }
-
- // The XP to Level is always rounded to the nearest 100 points (50 rounded to high).
- xp = ((xp + 50) / 100) * 100; // use additional () for prevent free association operations in C++
-
- if ((lvl > 10) && (lvl < 60)) // compute discount added in 2.3.x
- {
- uint32 discount = (lvl < 28) ? (lvl - 10) : 18;
- xp = (xp * (100 - discount)) / 100; // apply discount
- xp = (xp / 100) * 100; // floor to hundreds
- }
-
- return xp;
- }
-
inline float xp_in_group_rate(uint32 count, bool isRaid)
{
if(isRaid)
diff --git a/src/game/GameEvent.cpp b/src/game/GameEventMgr.cpp
index ae2dc488b86..dc86f659706 100644
--- a/src/game/GameEvent.cpp
+++ b/src/game/GameEventMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,9 +18,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "GameEvent.h"
+#include "GameEventMgr.h"
#include "World.h"
#include "ObjectMgr.h"
+#include "PoolHandler.h"
#include "ProgressBar.h"
#include "Language.h"
#include "Log.h"
@@ -30,9 +31,9 @@
#include "Player.h"
#include "BattleGroundMgr.h"
-INSTANTIATE_SINGLETON_1(GameEvent);
+INSTANTIATE_SINGLETON_1(GameEventMgr);
-bool GameEvent::CheckOneGameEvent(uint16 entry) const
+bool GameEventMgr::CheckOneGameEvent(uint16 entry) const
{
time_t currenttime = time(NULL);
// if the state is conditions or nextphase, then the event should be active
@@ -62,7 +63,7 @@ bool GameEvent::CheckOneGameEvent(uint16 entry) const
return false;
}
-uint32 GameEvent::NextCheck(uint16 entry) const
+uint32 GameEventMgr::NextCheck(uint16 entry) const
{
time_t currenttime = time(NULL);
@@ -96,7 +97,7 @@ uint32 GameEvent::NextCheck(uint16 entry) const
return delay;
}
-bool GameEvent::StartEvent( uint16 event_id, bool overwrite )
+bool GameEventMgr::StartEvent( uint16 event_id, bool overwrite )
{
if(mGameEvent[event_id].state == GAMEEVENT_NORMAL)
{
@@ -135,7 +136,7 @@ bool GameEvent::StartEvent( uint16 event_id, bool overwrite )
}
}
-void GameEvent::StopEvent( uint16 event_id, bool overwrite )
+void GameEventMgr::StopEvent( uint16 event_id, bool overwrite )
{
bool serverwide_evt = mGameEvent[event_id].state != GAMEEVENT_NORMAL;
@@ -167,7 +168,7 @@ void GameEvent::StopEvent( uint16 event_id, bool overwrite )
}
}
-void GameEvent::LoadFromDB()
+void GameEventMgr::LoadFromDB()
{
{
QueryResult *result = WorldDatabase.Query("SELECT MAX(entry) FROM game_event");
@@ -186,54 +187,68 @@ void GameEvent::LoadFromDB()
mGameEvent.resize(max_event_id+1);
}
- QueryResult *result = WorldDatabase.Query("SELECT entry,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),occurence,length,description,world_event FROM game_event");
+ QueryResult *result = WorldDatabase.Query("SELECT entry,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),occurence,length,holiday,description,world_event FROM game_event");
if( !result )
{
mGameEvent.clear();
- sLog.outString(">> Table game_event is empty:");
+ sLog.outString(">> Table game_event is empty!");
sLog.outString();
return;
}
uint32 count = 0;
- barGoLink bar( result->GetRowCount() );
- do
{
- ++count;
- Field *fields = result->Fetch();
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ ++count;
+ Field *fields = result->Fetch();
- bar.step();
+ bar.step();
- uint16 event_id = fields[0].GetUInt16();
- if(event_id==0)
- {
- sLog.outErrorDb("`game_event` game event id (%i) is reserved and can't be used.",event_id);
- continue;
- }
+ uint16 event_id = fields[0].GetUInt16();
+ if(event_id==0)
+ {
+ sLog.outErrorDb("`game_event` game event id (%i) is reserved and can't be used.",event_id);
+ continue;
+ }
- GameEventData& pGameEvent = mGameEvent[event_id];
- uint64 starttime = fields[1].GetUInt64();
- pGameEvent.start = time_t(starttime);
- uint64 endtime = fields[2].GetUInt64();
- pGameEvent.end = time_t(endtime);
- pGameEvent.occurence = fields[3].GetUInt32();
- pGameEvent.length = fields[4].GetUInt32();
- pGameEvent.description = fields[5].GetCppString();
- pGameEvent.state = (GameEventState)(fields[6].GetUInt8());
- pGameEvent.nextstart = 0;
-
- if(pGameEvent.length==0 && pGameEvent.state == GAMEEVENT_NORMAL) // length>0 is validity check
- {
- sLog.outErrorDb("`game_event` game event id (%i) isn't a world event and has length = 0, thus it can't be used.",event_id);
- continue;
- }
+ GameEventData& pGameEvent = mGameEvent[event_id];
+ uint64 starttime = fields[1].GetUInt64();
+ pGameEvent.start = time_t(starttime);
+ uint64 endtime = fields[2].GetUInt64();
+ pGameEvent.end = time_t(endtime);
+ pGameEvent.occurence = fields[3].GetUInt32();
+ pGameEvent.length = fields[4].GetUInt32();
+ pGameEvent.holiday_id = fields[5].GetUInt32();
- } while( result->NextRow() );
+ pGameEvent.state = (GameEventState)(fields[7].GetUInt8());
+ pGameEvent.nextstart = 0;
- sLog.outString();
- sLog.outString( ">> Loaded %u game events", count );
- delete result;
+ if(pGameEvent.length==0 && pGameEvent.state == GAMEEVENT_NORMAL) // length>0 is validity check
+ {
+ sLog.outErrorDb("`game_event` game event id (%i) isn't a world event and has length = 0, thus it can't be used.",event_id);
+ continue;
+ }
+
+ if(pGameEvent.holiday_id)
+ {
+ if(!sHolidaysStore.LookupEntry(pGameEvent.holiday_id))
+ {
+ sLog.outErrorDb("`game_event` game event id (%i) have not existed holiday id %u.",event_id,pGameEvent.holiday_id);
+ pGameEvent.holiday_id = 0;
+ }
+ }
+
+ pGameEvent.description = fields[6].GetCppString();
+
+ } while( result->NextRow() );
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u game events", count );
+ }
// load game event saves
// 0 1 2
@@ -346,8 +361,8 @@ void GameEvent::LoadFromDB()
count = 0;
if( !result )
{
- barGoLink bar2(1);
- bar2.step();
+ barGoLink bar(1);
+ bar.step();
sLog.outString();
sLog.outString(">> Loaded %u creatures in game events", count );
@@ -355,12 +370,12 @@ void GameEvent::LoadFromDB()
else
{
- barGoLink bar2( result->GetRowCount() );
+ barGoLink bar( result->GetRowCount() );
do
{
Field *fields = result->Fetch();
- bar2.step();
+ bar.step();
uint32 guid = fields[0].GetUInt32();
int16 event_id = fields[1].GetInt16();
@@ -378,9 +393,10 @@ void GameEvent::LoadFromDB()
crelist.push_back(guid);
} while( result->NextRow() );
+ delete result;
+
sLog.outString();
sLog.outString( ">> Loaded %u creatures in game events", count );
- delete result;
}
mGameEventGameobjectGuids.resize(mGameEvent.size()*2-1);
@@ -391,8 +407,8 @@ void GameEvent::LoadFromDB()
count = 0;
if( !result )
{
- barGoLink bar3(1);
- bar3.step();
+ barGoLink bar(1);
+ bar.step();
sLog.outString();
sLog.outString(">> Loaded %u gameobjects in game events", count );
@@ -400,12 +416,12 @@ void GameEvent::LoadFromDB()
else
{
- barGoLink bar3( result->GetRowCount() );
+ barGoLink bar( result->GetRowCount() );
do
{
Field *fields = result->Fetch();
- bar3.step();
+ bar.step();
uint32 guid = fields[0].GetUInt32();
int16 event_id = fields[1].GetInt16();
@@ -423,10 +439,10 @@ void GameEvent::LoadFromDB()
golist.push_back(guid);
} while( result->NextRow() );
+ delete result;
+
sLog.outString();
sLog.outString( ">> Loaded %u gameobjects in game events", count );
-
- delete result;
}
mGameEventModelEquip.resize(mGameEvent.size());
@@ -439,8 +455,8 @@ void GameEvent::LoadFromDB()
count = 0;
if( !result )
{
- barGoLink bar3(1);
- bar3.step();
+ barGoLink bar(1);
+ bar.step();
sLog.outString();
sLog.outString(">> Loaded %u model/equipment changes in game events", count );
@@ -448,12 +464,12 @@ void GameEvent::LoadFromDB()
else
{
- barGoLink bar3( result->GetRowCount() );
+ barGoLink bar( result->GetRowCount() );
do
{
Field *fields = result->Fetch();
- bar3.step();
+ bar.step();
uint32 guid = fields[0].GetUInt32();
uint16 event_id = fields[1].GetUInt16();
@@ -483,10 +499,10 @@ void GameEvent::LoadFromDB()
equiplist.push_back(std::pair<uint32, ModelEquip>(guid, newModelEquipSet));
} while( result->NextRow() );
+ delete result;
+
sLog.outString();
sLog.outString( ">> Loaded %u model/equipment changes in game events", count );
-
- delete result;
}
mGameEventCreatureQuests.resize(mGameEvent.size());
@@ -496,8 +512,8 @@ void GameEvent::LoadFromDB()
count = 0;
if( !result )
{
- barGoLink bar3(1);
- bar3.step();
+ barGoLink bar(1);
+ bar.step();
sLog.outString();
sLog.outString(">> Loaded %u quests additions in game events", count );
@@ -505,12 +521,12 @@ void GameEvent::LoadFromDB()
else
{
- barGoLink bar3( result->GetRowCount() );
+ barGoLink bar( result->GetRowCount() );
do
{
Field *fields = result->Fetch();
- bar3.step();
+ bar.step();
uint32 id = fields[0].GetUInt32();
uint32 quest = fields[1].GetUInt32();
uint16 event_id = fields[2].GetUInt16();
@@ -569,10 +585,10 @@ void GameEvent::LoadFromDB()
questlist.push_back(QuestRelation(id, quest));
} while( result->NextRow() );
+ delete result;
+
sLog.outString();
sLog.outString( ">> Loaded %u quests additions in game events", count );
-
- delete result;
}
// Load quest to (event,condition) mapping
@@ -913,9 +929,64 @@ void GameEvent::LoadFromDB()
delete result;
}
+
+ ////////////////////////
+ // GameEventPool
+ ////////////////////////
+
+ mGameEventPoolIds.resize(mGameEvent.size()*2-1);
+ // 1 2
+ result = WorldDatabase.Query("SELECT pool_template.entry, game_event_pool.event "
+ "FROM pool_template JOIN game_event_pool ON pool_template.entry = game_event_pool.pool_entry");
+
+ count = 0;
+ if( !result )
+ {
+ barGoLink bar2(1);
+ bar2.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u pools in game events", count );
+ }
+ else
+ {
+
+ barGoLink bar2( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar2.step();
+
+ uint32 entry = fields[0].GetUInt16();
+ int16 event_id = fields[1].GetInt16();
+
+ int32 internal_event_id = mGameEvent.size() + event_id - 1;
+
+ if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size())
+ {
+ sLog.outErrorDb("`game_event_pool` game event id (%i) is out of range compared to max event id in `game_event`",event_id);
+ continue;
+ }
+
+ if (!poolhandler.CheckPool(entry))
+ {
+ sLog.outErrorDb("Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", entry);
+ continue;
+ }
+
+ ++count;
+ IdList& poollist = mGameEventPoolIds[internal_event_id];
+ poollist.push_back(entry);
+
+ } while( result->NextRow() );
+ sLog.outString();
+ sLog.outString( ">> Loaded %u pools in game events", count );
+ delete result;
+ }
}
-uint32 GameEvent::GetNPCFlag(Creature * cr)
+uint32 GameEventMgr::GetNPCFlag(Creature * cr)
{
uint32 mask = 0;
uint32 guid = cr->GetDBTableGUIDLow();
@@ -932,7 +1003,7 @@ uint32 GameEvent::GetNPCFlag(Creature * cr)
return mask;
}
-uint32 GameEvent::GetNpcTextId(uint32 guid)
+uint32 GameEventMgr::GetNpcTextId(uint32 guid)
{
GuidEventNpcGossipIdMap::iterator itr = mNPCGossipIds.find(guid);
if(itr != mNPCGossipIds.end())
@@ -941,7 +1012,7 @@ uint32 GameEvent::GetNpcTextId(uint32 guid)
return 0;
}
-uint32 GameEvent::Initialize() // return the next event delay in ms
+uint32 GameEventMgr::Initialize() // return the next event delay in ms
{
m_ActiveEvents.clear();
uint32 delay = Update();
@@ -950,7 +1021,7 @@ uint32 GameEvent::Initialize() // return the next e
return delay;
}
-uint32 GameEvent::Update() // return the next event delay in ms
+uint32 GameEventMgr::Update() // return the next event delay in ms
{
time_t currenttime = time(NULL);
uint32 nextEventDelay = max_ge_check_delay; // 1 day
@@ -1017,10 +1088,10 @@ uint32 GameEvent::Update() // return the next e
for(std::set<uint16>::iterator itr = deactivate.begin(); itr != deactivate.end(); ++itr)
StopEvent(*itr);
sLog.outDetail("Next game event check in %u seconds.", nextEventDelay + 1);
- return (nextEventDelay + 1) * 1000; // Add 1 second to be sure event has started/stopped at next call
+ return (nextEventDelay + 1) * IN_MILISECONDS; // Add 1 second to be sure event has started/stopped at next call
}
-void GameEvent::UnApplyEvent(uint16 event_id)
+void GameEventMgr::UnApplyEvent(uint16 event_id)
{
sLog.outString("GameEvent %u \"%s\" removed.", event_id, mGameEvent[event_id].description.c_str());
// un-spawn positive event tagged objects
@@ -1040,7 +1111,7 @@ void GameEvent::UnApplyEvent(uint16 event_id)
UpdateBattleGroundSettings();
}
-void GameEvent::ApplyNewEvent(uint16 event_id)
+void GameEventMgr::ApplyNewEvent(uint16 event_id)
{
switch(sWorld.getConfig(CONFIG_EVENT_ANNOUNCE))
{
@@ -1070,7 +1141,7 @@ void GameEvent::ApplyNewEvent(uint16 event_id)
UpdateBattleGroundSettings();
}
-void GameEvent::UpdateEventNPCFlags(uint16 event_id)
+void GameEventMgr::UpdateEventNPCFlags(uint16 event_id)
{
// go through the creatures whose npcflags are changed in the event
for(NPCFlagList::iterator itr = mGameEventNPCFlags[event_id].begin(); itr != mGameEventNPCFlags[event_id].end(); ++itr)
@@ -1096,7 +1167,7 @@ void GameEvent::UpdateEventNPCFlags(uint16 event_id)
}
}
-void GameEvent::UpdateBattleGroundSettings()
+void GameEventMgr::UpdateBattleGroundSettings()
{
uint32 mask = 0;
for(ActiveEvents::const_iterator itr = m_ActiveEvents.begin(); itr != m_ActiveEvents.end(); ++itr )
@@ -1104,7 +1175,7 @@ void GameEvent::UpdateBattleGroundSettings()
sBattleGroundMgr.SetHolidayWeekends(mask);
}
-void GameEvent::UpdateEventNPCVendor(uint16 event_id, bool activate)
+void GameEventMgr::UpdateEventNPCVendor(uint16 event_id, bool activate)
{
for(NPCVendorList::iterator itr = mGameEventVendors[event_id].begin(); itr != mGameEventVendors[event_id].end(); ++itr)
{
@@ -1115,13 +1186,13 @@ void GameEvent::UpdateEventNPCVendor(uint16 event_id, bool activate)
}
}
-void GameEvent::GameEventSpawn(int16 event_id)
+void GameEventMgr::GameEventSpawn(int16 event_id)
{
int32 internal_event_id = mGameEvent.size() + event_id - 1;
if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
{
- sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
+ sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
return;
}
@@ -1154,7 +1225,7 @@ void GameEvent::GameEventSpawn(int16 event_id)
if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
{
- sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
+ sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
return;
}
@@ -1185,15 +1256,26 @@ void GameEvent::GameEventSpawn(int16 event_id)
}
}
}
+
+ if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size())
+ {
+ sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size());
+ return;
+ }
+
+ for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin();itr != mGameEventPoolIds[internal_event_id].end();++itr)
+ {
+ poolhandler.SpawnPool(*itr);
+ }
}
-void GameEvent::GameEventUnspawn(int16 event_id)
+void GameEventMgr::GameEventUnspawn(int16 event_id)
{
int32 internal_event_id = mGameEvent.size() + event_id - 1;
if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
{
- sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
+ sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
return;
}
@@ -1217,7 +1299,7 @@ void GameEvent::GameEventUnspawn(int16 event_id)
if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
{
- sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
+ sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
return;
}
@@ -1235,9 +1317,19 @@ void GameEvent::GameEventUnspawn(int16 event_id)
pGameobject->AddObjectToRemoveList();
}
}
+ if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size())
+ {
+ sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size());
+ return;
+ }
+
+ for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin();itr != mGameEventPoolIds[internal_event_id].end();++itr)
+ {
+ poolhandler.DespawnPool(*itr);
+ }
}
-void GameEvent::ChangeEquipOrModel(int16 event_id, bool activate)
+void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
{
for(ModelEquipList::iterator itr = mGameEventModelEquip[event_id].begin();itr != mGameEventModelEquip[event_id].end();++itr)
{
@@ -1285,17 +1377,17 @@ void GameEvent::ChangeEquipOrModel(int16 event_id, bool activate)
}
else // If not spawned
{
- CreatureData const* data = objmgr.GetCreatureData(itr->first);
- if (data && activate)
+ CreatureData const* data2 = objmgr.GetCreatureData(itr->first);
+ if (data2 && activate)
{
- CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(data->id);
- uint32 display_id = objmgr.ChooseDisplayId(0,cinfo,data);
+ CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(data2->id);
+ uint32 display_id = objmgr.ChooseDisplayId(0,cinfo,data2);
CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
if (minfo)
display_id = minfo->modelid;
- if (data->equipmentId == 0)
+ if (data2->equipmentId == 0)
itr->second.equipement_id_prev = cinfo->equipmentId;
- else if (data->equipmentId != -1)
+ else if (data2->equipmentId != -1)
itr->second.equipement_id_prev = data->equipmentId;
itr->second.modelid_prev = display_id;
}
@@ -1316,7 +1408,7 @@ void GameEvent::ChangeEquipOrModel(int16 event_id, bool activate)
}
}
-bool GameEvent::hasCreatureQuestActiveEventExcept(uint32 quest_id, uint16 event_id)
+bool GameEventMgr::hasCreatureQuestActiveEventExcept(uint32 quest_id, uint16 event_id)
{
for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
{
@@ -1330,7 +1422,7 @@ bool GameEvent::hasCreatureQuestActiveEventExcept(uint32 quest_id, uint16 event_
return false;
}
-bool GameEvent::hasGameObjectQuestActiveEventExcept(uint32 quest_id, uint16 event_id)
+bool GameEventMgr::hasGameObjectQuestActiveEventExcept(uint32 quest_id, uint16 event_id)
{
for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
{
@@ -1343,7 +1435,7 @@ bool GameEvent::hasGameObjectQuestActiveEventExcept(uint32 quest_id, uint16 even
}
return false;
}
-bool GameEvent::hasCreatureActiveEventExcept(uint32 creature_id, uint16 event_id)
+bool GameEventMgr::hasCreatureActiveEventExcept(uint32 creature_id, uint16 event_id)
{
for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
{
@@ -1359,7 +1451,7 @@ bool GameEvent::hasCreatureActiveEventExcept(uint32 creature_id, uint16 event_id
}
return false;
}
-bool GameEvent::hasGameObjectActiveEventExcept(uint32 go_id, uint16 event_id)
+bool GameEventMgr::hasGameObjectActiveEventExcept(uint32 go_id, uint16 event_id)
{
for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
{
@@ -1376,7 +1468,7 @@ bool GameEvent::hasGameObjectActiveEventExcept(uint32 go_id, uint16 event_id)
return false;
}
-void GameEvent::UpdateEventQuests(uint16 event_id, bool Activate)
+void GameEventMgr::UpdateEventQuests(uint16 event_id, bool Activate)
{
QuestRelList::iterator itr;
for (itr = mGameEventCreatureQuests[event_id].begin();itr != mGameEventCreatureQuests[event_id].end();++itr)
@@ -1430,12 +1522,12 @@ void GameEvent::UpdateEventQuests(uint16 event_id, bool Activate)
}
}}
-GameEvent::GameEvent()
+GameEventMgr::GameEventMgr()
{
isSystemInit = false;
}
-void GameEvent::HandleQuestComplete(uint32 quest_id)
+void GameEventMgr::HandleQuestComplete(uint32 quest_id)
{
// translate the quest to event and condition
QuestIdToEventConditionMap::iterator itr = mQuestToEventConditions.find(quest_id);
@@ -1481,7 +1573,7 @@ void GameEvent::HandleQuestComplete(uint32 quest_id)
}
}
-bool GameEvent::CheckOneGameEventConditions(uint16 event_id)
+bool GameEventMgr::CheckOneGameEventConditions(uint16 event_id)
{
for(std::map<uint32,GameEventFinishCondition>::iterator itr = mGameEvent[event_id].conditions.begin(); itr != mGameEvent[event_id].conditions.end(); ++itr)
if(itr->second.done < itr->second.reqNum)
@@ -1498,7 +1590,7 @@ bool GameEvent::CheckOneGameEventConditions(uint16 event_id)
return true;
}
-void GameEvent::SaveWorldEventStateToDB(uint16 event_id)
+void GameEventMgr::SaveWorldEventStateToDB(uint16 event_id)
{
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM game_event_save WHERE event_id = '%u'",event_id);
@@ -1509,7 +1601,7 @@ void GameEvent::SaveWorldEventStateToDB(uint16 event_id)
CharacterDatabase.CommitTransaction();
}
-void GameEvent::HandleWorldEventGossip(Player *plr, Creature *c)
+void GameEventMgr::HandleWorldEventGossip(Player *plr, Creature *c)
{
// this function is used to send world state update before sending gossip menu
// find the npc's gossip id (if set) in an active game event
@@ -1521,7 +1613,7 @@ void GameEvent::HandleWorldEventGossip(Player *plr, Creature *c)
SendWorldStateUpdate(plr, itr->second.first);
}
-void GameEvent::SendWorldStateUpdate(Player * plr, uint16 event_id)
+void GameEventMgr::SendWorldStateUpdate(Player * plr, uint16 event_id)
{
std::map<uint32,GameEventFinishCondition>::iterator itr;
for(itr = mGameEvent[event_id].conditions.begin(); itr !=mGameEvent[event_id].conditions.end(); ++itr)
@@ -1533,3 +1625,14 @@ void GameEvent::SendWorldStateUpdate(Player * plr, uint16 event_id)
}
}
+TRINITY_DLL_SPEC bool IsHolidayActive( HolidayIds id )
+{
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEventMgr::ActiveEvents const& ae = gameeventmgr.GetActiveEventList();
+
+ for(GameEventMgr::ActiveEvents::const_iterator itr = ae.begin(); itr != ae.end(); ++itr)
+ if(events[*itr].holiday_id==id)
+ return true;
+
+ return false;
+}
diff --git a/src/game/GameEvent.h b/src/game/GameEventMgr.h
index 9f69aa9e6ea..a7b52f0ab72 100644
--- a/src/game/GameEvent.h
+++ b/src/game/GameEventMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,12 +18,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef TRINITY_GAMEEVENT_H
-#define TRINITY_GAMEEVENT_H
+#ifndef TRINITY_GAMEEVENT_MGR_H
+#define TRINITY_GAMEEVENT_MGR_H
+#include "Common.h"
+#include "SharedDefines.h"
#include "Platform/Define.h"
-#include "Creature.h"
-#include "GameObject.h"
+#include "Policies/Singleton.h"
#define max_ge_check_delay 86400 // 1 day in seconds
@@ -54,11 +55,12 @@ struct GameEventQuestToEventConditionNum
struct GameEventData
{
GameEventData() : start(1),end(0),nextstart(0),occurence(0),length(0),state(GAMEEVENT_NORMAL) {}
- time_t start; // occurs after this time
- time_t end; // occurs before this time
- time_t nextstart; // after this time the follow-up events count this phase completed
- uint32 occurence; // time between end and start
- uint32 length; // length of the event (minutes) after finishing all conditions
+ time_t start; // occurs after this time
+ time_t end; // occurs before this time
+ time_t nextstart; // after this time the follow-up events count this phase completed
+ uint32 occurence; // time between end and start
+ uint32 length; // length of the event (minutes) after finishing all conditions
+ uint32 holiday_id;
GameEventState state; // state of the game event, these are saved into the game_event table on change!
std::map<uint32 /*condition id*/, GameEventFinishCondition> conditions; // conditions to finish
std::set<uint16 /*gameevent id*/> prerequisite_events; // events that must be completed before starting this event
@@ -85,11 +87,13 @@ struct NPCVendorEntry
};
class Player;
-class GameEvent
+class Creature;
+
+class GameEventMgr
{
public:
- GameEvent();
- ~GameEvent() {};
+ GameEventMgr();
+ ~GameEventMgr() {};
typedef std::set<uint16> ActiveEvents;
typedef std::vector<GameEventData> GameEventDataMap;
ActiveEvents const& GetActiveEventList() const { return m_ActiveEvents; }
@@ -127,7 +131,9 @@ class GameEvent
bool hasGameObjectActiveEventExcept(uint32 go_guid, uint16 event_id);
protected:
typedef std::list<uint32> GuidList;
+ typedef std::list<uint16> IdList;
typedef std::vector<GuidList> GameEventGuidMap;
+ typedef std::vector<IdList> GameEventIdMap;
typedef std::pair<uint32, ModelEquip> ModelEquipPair;
typedef std::list<ModelEquipPair> ModelEquipList;
typedef std::vector<ModelEquipList> GameEventModelEquipMap;
@@ -149,6 +155,7 @@ class GameEvent
GameEventModelEquipMap mGameEventModelEquip;
GameEventGuidMap mGameEventCreatureGuids;
GameEventGuidMap mGameEventGameobjectGuids;
+ GameEventIdMap mGameEventPoolIds;
GameEventDataMap mGameEvent;
GameEventBitmask mGameEventBattleGroundHolidays;
QuestIdToEventConditionMap mQuestToEventConditions;
@@ -158,6 +165,9 @@ class GameEvent
bool isSystemInit;
};
-#define gameeventmgr Trinity::Singleton<GameEvent>::Instance()
+#define gameeventmgr Trinity::Singleton<GameEventMgr>::Instance()
+
+TRINITY_DLL_SPEC bool IsHolidayActive(HolidayIds id);
+
#endif
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
index 744b6679862..9a415f8c991 100644
--- a/src/game/GameObject.cpp
+++ b/src/game/GameObject.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,15 +22,14 @@
#include "QuestDef.h"
#include "GameObject.h"
#include "ObjectMgr.h"
+#include "PoolHandler.h"
#include "SpellMgr.h"
#include "Spell.h"
#include "UpdateMask.h"
#include "Opcodes.h"
#include "WorldPacket.h"
-#include "WorldSession.h"
#include "World.h"
#include "Database/DatabaseEnv.h"
-#include "MapManager.h"
#include "LootMgr.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
@@ -46,7 +45,7 @@ GameObject::GameObject() : WorldObject()
m_objectType |= TYPEMASK_GAMEOBJECT;
m_objectTypeId = TYPEID_GAMEOBJECT;
// 2.3.2 - 0x58
- m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION);
+ m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION);
m_valuesCount = GAMEOBJECT_END;
m_respawnTime = 0;
@@ -64,9 +63,9 @@ GameObject::GameObject() : WorldObject()
GameObject::~GameObject()
{
- if(m_uint32Values) // field array can be not exist if GameOBject not loaded
+ /*if(m_uint32Values) // field array can be not exist if GameOBject not loaded
{
- // crash possible at access to deleted GO in Unit::m_gameobj
+ // Possible crash at access to deleted GO in Unit::m_gameobj
uint64 owner_guid = GetOwnerGUID();
if(owner_guid)
{
@@ -76,7 +75,7 @@ GameObject::~GameObject()
else if(!IS_PLAYER_GUID(owner_guid))
sLog.outError("Delete GameObject (GUID: %u Entry: %u ) that have references in not found creature %u GO list. Crash possible later.",GetGUIDLow(),GetGOInfo()->id,GUID_LOPART(owner_guid));
}
- }
+ }*/
}
void GameObject::AddToWorld()
@@ -96,21 +95,31 @@ void GameObject::RemoveFromWorld()
{
if(Map *map = FindMap())
if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
- ((InstanceMap*)map)->GetInstanceData()->OnObjectRemove(this);
- ObjectAccessor::Instance().RemoveObject(this);
+ ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this, false);
+ // Possible crash at access to deleted GO in Unit::m_gameobj
+ if(uint64 owner_guid = GetOwnerGUID())
+ {
+ Unit* owner = ObjectAccessor::GetUnit(*this,owner_guid);
+ if(owner)
+ owner->RemoveGameObject(this,false);
+ else if(!IS_PLAYER_GUID(owner_guid))
+ sLog.outError("Delete GameObject (GUID: %u Entry: %u ) that have references in not found creature %u GO list. Crash possible later.",GetGUIDLow(),GetGOInfo()->id,GUID_LOPART(owner_guid));
+ }
WorldObject::RemoveFromWorld();
+ ObjectAccessor::Instance().RemoveObject(this);
}
}
-bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, uint32 go_state, uint32 ArtKit)
+bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 ArtKit)
{
Relocate(x,y,z,ang);
SetMapId(map->GetId());
SetInstanceId(map->GetInstanceId());
+ SetPhaseMask(phaseMask,false);
if(!IsPositionValid())
{
- sLog.outError("ERROR: Gameobject (GUID: %u Entry: %u ) not created. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,name_id,x,y);
+ sLog.outError("Gameobject (GUID: %u Entry: %u ) not created. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,name_id,x,y);
return false;
}
@@ -134,19 +143,18 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float
SetFloatValue(GAMEOBJECT_POS_X, x);
SetFloatValue(GAMEOBJECT_POS_Y, y);
SetFloatValue(GAMEOBJECT_POS_Z, z);
- SetFloatValue(GAMEOBJECT_FACING, ang); //this is not facing angle
- SetFloatValue (GAMEOBJECT_ROTATION, rotation0);
- SetFloatValue (GAMEOBJECT_ROTATION+1, rotation1);
- SetFloatValue (GAMEOBJECT_ROTATION+2, rotation2);
- SetFloatValue (GAMEOBJECT_ROTATION+3, rotation3);
+ SetFloatValue(GAMEOBJECT_PARENTROTATION+0, rotation0);
+ SetFloatValue(GAMEOBJECT_PARENTROTATION+1, rotation1);
+
+ UpdateRotationFields(rotation2,rotation3); // GAMEOBJECT_FACING, GAMEOBJECT_ROTATION, GAMEOBJECT_PARENTROTATION+2/3
SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size);
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
- SetUInt32Value(OBJECT_FIELD_ENTRY, goinfo->id);
+ SetEntry(goinfo->id);
SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId);
@@ -155,18 +163,20 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float
SetGoAnimProgress(animprogress);
- SetUInt32Value (GAMEOBJECT_ARTKIT, ArtKit);
+ SetByteValue(GAMEOBJECT_BYTES_1, 2, ArtKit);
// Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22)
if (goinfo->type == GAMEOBJECT_TYPE_SPELLCASTER)
m_charges = goinfo->spellcaster.charges;
+ else if(goinfo->type == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
+ m_health = goinfo->destructibleBuilding.damagedHealth;
//Notify the map's instance data.
//Only works if you create the object in it, not if it is moves to that map.
//Normally non-players do not teleport to other maps.
if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
{
- ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this);
+ ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this, true);
}
return true;
@@ -190,7 +200,7 @@ void GameObject::Update(uint32 /*p_time*/)
{
// Arming Time for GAMEOBJECT_TYPE_TRAP (6)
Unit* owner = GetOwner();
- if (owner && ((Player*)owner)->isInCombat())
+ if (owner && owner->isInCombat())
m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay;
m_lootState = GO_READY;
break;
@@ -204,7 +214,7 @@ void GameObject::Update(uint32 /*p_time*/)
Unit* caster = GetOwner();
if(caster && caster->GetTypeId()==TYPEID_PLAYER)
{
- SetGoState(0);
+ SetGoState(GO_STATE_ACTIVE);
SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN);
UpdateData udata;
@@ -213,10 +223,7 @@ void GameObject::Update(uint32 /*p_time*/)
udata.BuildPacket(&packet);
((Player*)caster)->GetSession()->SendPacket(&packet);
- WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4);
- data << GetGUID();
- data << (uint32)(0);
- ((Player*)caster)->SendMessageToSet(&data,true);
+ SendCustomAnim();
}
m_lootState = GO_READY; // can be successfully open with some chance
@@ -262,18 +269,22 @@ void GameObject::Update(uint32 /*p_time*/)
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
//we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds)
- if( !GetGoState() )
- SwitchDoorOrButton(false);
+ if (GetGoState() != GO_STATE_READY)
+ ResetDoorOrButton();
//flags in AB are type_button and we need to add them here so no break!
default:
- if(!m_spawnedByDefault) // despawn timer
+ if (!m_spawnedByDefault) // despawn timer
{
// can be despawned or destroyed
SetLootState(GO_JUST_DEACTIVATED);
return;
}
// respawn timer
- MapManager::Instance().GetMap(GetMapId(), this)->Add(this);
+ uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), TYPEID_GAMEOBJECT);
+ if (poolid)
+ poolhandler.UpdatePool(poolid, GetGUIDLow(), TYPEID_GAMEOBJECT);
+ else
+ GetMap()->Add(this);
break;
}
}
@@ -296,7 +307,7 @@ void GameObject::Update(uint32 /*p_time*/)
float radius = 0.0f;
const SpellEntry *spellEntry = sSpellStore.LookupEntry(m_spellId);
if(spellEntry)
- radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEntry->EffectRadiusIndex[0]));
+ radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(spellEntry->EffectRadiusIndex[0]));
else
radius = goInfo->trap.radius;
if(!radius)
@@ -315,51 +326,32 @@ void GameObject::Update(uint32 /*p_time*/)
bool NeedDespawn = (goInfo->trap.charges != 0);
- CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY()));
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
-
// Note: this hack with search required until GO casting not implemented
// search unfriendly creature
if(owner && NeedDespawn) // hunter trap
{
- Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck u_check(this, owner, radius);
- Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> checker(ok, u_check);
-
- CellLock<GridReadGuard> cell_lock(cell, p);
-
- TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck>, GridTypeMapContainer > grid_object_checker(checker);
- cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
-
- // or unfriendly player/pet
- if(!ok)
- {
- TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker);
- cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
- }
+ Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius);
+ Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, ok, checker);
+ VisitNearbyGridObject(radius, searcher);
+ if(!ok) VisitNearbyWorldObject(radius, searcher);
}
else // environmental trap
{
// environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support
-
// affect only players
- Player* p_ok = NULL;
- Trinity::AnyPlayerInObjectRangeCheck p_check(this, radius);
- Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> checker(p_ok, p_check);
-
- CellLock<GridReadGuard> cell_lock(cell, p);
-
- TypeContainerVisitor<Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker);
- cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
- ok = p_ok;
+ Player* player = NULL;
+ MaNGOS::AnyPlayerInObjectRangeCheck checker(this, radius);
+ MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> searcher(this, player, checker);
+ VisitNearbyWorldObject(radius, searcher);
+ ok = player;
}
if (ok)
{
//Unit *caster = owner ? owner : ok;
- //caster->CastSpell(ok, goInfo->trap.spellId, true);
CastSpell(ok, goInfo->trap.spellId);
+ //caster->CastSpell(ok, goInfo->trap.spellId, true, 0, 0, GetGUID());
m_cooldownTime = time(NULL) + 4; // 4 seconds
if(NeedDespawn)
@@ -386,11 +378,8 @@ void GameObject::Update(uint32 /*p_time*/)
{
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
- if(GetAutoCloseTime() && (m_cooldownTime < time(NULL)))
- {
- SwitchDoorOrButton(false);
- SetLootState(GO_JUST_DEACTIVATED);
- }
+ if (GetAutoCloseTime() && (m_cooldownTime < time(NULL)))
+ ResetDoorOrButton();
break;
}
break;
@@ -404,12 +393,12 @@ void GameObject::Update(uint32 /*p_time*/)
if(spellId)
{
- std::set<uint32>::iterator it = m_unique_users.begin();
- std::set<uint32>::iterator end = m_unique_users.end();
+ std::set<uint32>::const_iterator it = m_unique_users.begin();
+ std::set<uint32>::const_iterator end = m_unique_users.end();
for (; it != end; it++)
{
Unit* owner = Unit::GetUnit(*this, uint64(*it));
- if (owner) owner->CastSpell(owner, spellId, false);
+ if (owner) owner->CastSpell(owner, spellId, false, 0, 0, GetGUID());
}
m_unique_users.clear();
@@ -428,7 +417,7 @@ void GameObject::Update(uint32 /*p_time*/)
//burning flags in some battlegrounds, if you find better condition, just add it
if (GetGoAnimProgress() > 0)
{
- SendObjectDeSpawnAnim(this->GetGUID());
+ SendObjectDeSpawnAnim(GetGUID());
//reset flags
SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags);
}
@@ -465,7 +454,7 @@ void GameObject::Refresh()
return;
if(isSpawned())
- MapManager::Instance().GetMap(GetMapId(), this)->Add(this);
+ GetMap()->Add(this);
}
void GameObject::AddUniqueUse(Player* player)
@@ -478,24 +467,29 @@ void GameObject::Delete()
{
SendObjectDeSpawnAnim(GetGUID());
- SetGoState(1);
+ SetGoState(GO_STATE_READY);
SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags);
- AddObjectToRemoveList();
+ uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), TYPEID_GAMEOBJECT);
+ if (poolid)
+ poolhandler.UpdatePool(poolid, GetGUIDLow(), TYPEID_GAMEOBJECT);
+ else
+ AddObjectToRemoveList();
}
-void GameObject::getFishLoot(Loot *fishloot)
+void GameObject::getFishLoot(Loot *fishloot, Player* loot_owner)
{
fishloot->clear();
- uint32 subzone = GetAreaId();
+ uint32 zone, subzone;
+ GetZoneAndAreaId(zone,subzone);
// if subzone loot exist use it
if(LootTemplates_Fishing.HaveLootFor(subzone))
- fishloot->FillLoot(subzone, LootTemplates_Fishing, NULL);
+ fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner,true);
// else use zone loot
else
- fishloot->FillLoot(GetZoneId(), LootTemplates_Fishing, NULL);
+ fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner,true);
}
void GameObject::SaveToDB()
@@ -509,10 +503,10 @@ void GameObject::SaveToDB()
return;
}
- SaveToDB(GetMapId(), data->spawnMask);
+ SaveToDB(GetMapId(), data->spawnMask, data->phaseMask);
}
-void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask)
+void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
{
const GameObjectInfo *goI = GetGOInfo();
@@ -527,38 +521,40 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask)
// data->guid = guid don't must be update at save
data.id = GetEntry();
data.mapid = mapid;
+ data.phaseMask = phaseMask;
data.posX = GetFloatValue(GAMEOBJECT_POS_X);
data.posY = GetFloatValue(GAMEOBJECT_POS_Y);
data.posZ = GetFloatValue(GAMEOBJECT_POS_Z);
data.orientation = GetFloatValue(GAMEOBJECT_FACING);
- data.rotation0 = GetFloatValue(GAMEOBJECT_ROTATION+0);
- data.rotation1 = GetFloatValue(GAMEOBJECT_ROTATION+1);
- data.rotation2 = GetFloatValue(GAMEOBJECT_ROTATION+2);
- data.rotation3 = GetFloatValue(GAMEOBJECT_ROTATION+3);
+ data.rotation0 = GetFloatValue(GAMEOBJECT_PARENTROTATION+0);
+ data.rotation1 = GetFloatValue(GAMEOBJECT_PARENTROTATION+1);
+ data.rotation2 = GetFloatValue(GAMEOBJECT_PARENTROTATION+2);
+ data.rotation3 = GetFloatValue(GAMEOBJECT_PARENTROTATION+3);
data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime;
data.animprogress = GetGoAnimProgress();
data.go_state = GetGoState();
data.spawnMask = spawnMask;
- data.ArtKit = GetUInt32Value (GAMEOBJECT_ARTKIT);
+ data.ArtKit = GetGoArtKit();
// updated in DB
std::ostringstream ss;
ss << "INSERT INTO gameobject VALUES ( "
<< m_DBTableGuid << ", "
- << GetUInt32Value (OBJECT_FIELD_ENTRY) << ", "
+ << GetEntry() << ", "
<< mapid << ", "
- << (uint32)spawnMask << ", "
+ << uint32(spawnMask) << "," // cast to prevent save as symbol
+ << uint16(GetPhaseMask()) << "," // prevent out of range error
<< GetFloatValue(GAMEOBJECT_POS_X) << ", "
<< GetFloatValue(GAMEOBJECT_POS_Y) << ", "
<< GetFloatValue(GAMEOBJECT_POS_Z) << ", "
<< GetFloatValue(GAMEOBJECT_FACING) << ", "
- << GetFloatValue(GAMEOBJECT_ROTATION) << ", "
- << GetFloatValue(GAMEOBJECT_ROTATION+1) << ", "
- << GetFloatValue(GAMEOBJECT_ROTATION+2) << ", "
- << GetFloatValue(GAMEOBJECT_ROTATION+3) << ", "
+ << GetFloatValue(GAMEOBJECT_PARENTROTATION) << ", "
+ << GetFloatValue(GAMEOBJECT_PARENTROTATION+1) << ", "
+ << GetFloatValue(GAMEOBJECT_PARENTROTATION+2) << ", "
+ << GetFloatValue(GAMEOBJECT_PARENTROTATION+3) << ", "
<< m_respawnDelayTime << ", "
- << GetGoAnimProgress() << ", "
- << GetGoState() << ")";
+ << uint32(GetGoAnimProgress()) << ", "
+ << uint32(GetGoState()) << ")";
WorldDatabase.BeginTransaction();
WorldDatabase.PExecuteLog("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid);
@@ -572,12 +568,13 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map)
if( !data )
{
- sLog.outErrorDb("ERROR: Gameobject (GUID: %u) not found in table `gameobject`, can't load. ",guid);
+ sLog.outErrorDb("Gameobject (GUID: %u) not found in table `gameobject`, can't load. ",guid);
return false;
}
uint32 entry = data->id;
- uint32 map_id = data->mapid;
+ //uint32 map_id = data->mapid; // already used before call
+ uint32 phaseMask = data->phaseMask;
float x = data->posX;
float y = data->posY;
float z = data->posZ;
@@ -589,46 +586,43 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map)
float rotation3 = data->rotation3;
uint32 animprogress = data->animprogress;
- uint32 go_state = data->go_state;
+ GOState go_state = data->go_state;
uint32 ArtKit = data->ArtKit;
m_DBTableGuid = guid;
if (map->GetInstanceId() != 0) guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
- if (!Create(guid,entry, map, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, ArtKit) )
+ if (!Create(guid,entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, ArtKit) )
return false;
- switch(GetGOInfo()->type)
+ if(!GetDespawnPossibility())
{
- case GAMEOBJECT_TYPE_DOOR:
- case GAMEOBJECT_TYPE_BUTTON:
- /* this code (in comment) isn't correct because in battlegrounds we need despawnable doors and buttons, pls remove
- SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN);
+ SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN);
+ m_spawnedByDefault = true;
+ m_respawnDelayTime = 0;
+ m_respawnTime = 0;
+ }
+ else
+ {
+ if(data->spawntimesecs >= 0)
+ {
m_spawnedByDefault = true;
- m_respawnDelayTime = 0;
- m_respawnTime = 0;
- break;*/
- default:
- if(data->spawntimesecs >= 0)
- {
- m_spawnedByDefault = true;
- m_respawnDelayTime = data->spawntimesecs;
- m_respawnTime = objmgr.GetGORespawnTime(m_DBTableGuid, map->GetInstanceId());
+ m_respawnDelayTime = data->spawntimesecs;
+ m_respawnTime = objmgr.GetGORespawnTime(m_DBTableGuid, map->GetInstanceId());
- // ready to respawn
- if(m_respawnTime && m_respawnTime <= time(NULL))
- {
- m_respawnTime = 0;
- objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0);
- }
- }
- else
+ // ready to respawn
+ if(m_respawnTime && m_respawnTime <= time(NULL))
{
- m_spawnedByDefault = false;
- m_respawnDelayTime = -data->spawntimesecs;
m_respawnTime = 0;
+ objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0);
}
- break;
+ }
+ else
+ {
+ m_spawnedByDefault = false;
+ m_respawnDelayTime = -data->spawntimesecs;
+ m_respawnTime = 0;
+ }
}
return true;
@@ -644,7 +638,7 @@ void GameObject::DeleteFromDB()
GameObject* GameObject::GetGameObject(WorldObject& object, uint64 guid)
{
- return ObjectAccessor::GetGameObject(object,guid);
+ return object.GetMap()->GetGameObject(guid);
}
GameObjectInfo const *GameObject::GetGOInfo() const
@@ -738,14 +732,10 @@ bool GameObject::isVisibleForInState(Player const* u, bool inVisibleList) const
if(owner && u->IsHostileTo(owner) && !canDetectTrap(u, GetDistance(u)))
return false;
}
-
- // Smuggled Mana Cell required 10 invisibility type detection/state
- if(GetEntry()==187039 && ((u->m_detectInvisibilityMask | u->m_invisibilityMask) & (1<<10))==0)
- return false;
}
// check distance
- return IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject() +
+ return IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject() +
(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
}
@@ -824,7 +814,20 @@ void GameObject::TriggeringLinkedGameObject( uint32 trapEntry, Unit* target)
if(!trapSpell) // checked at load already
return;
- float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(trapSpell->rangeIndex));
+ float range;
+ SpellRangeEntry const * srentry = sSpellRangeStore.LookupEntry(trapSpell->rangeIndex);
+ //get owner to check hostility of GameObject
+ if (GetSpellMaxRangeForHostile(srentry) == GetSpellMaxRangeForHostile(srentry))
+ range = GetSpellMaxRangeForHostile(srentry);
+ else
+ {
+ Unit * owner=GetOwner();
+ if (owner)
+ range = owner->GetSpellMaxRangeForTarget(target, srentry);
+ else
+ //if no owner assume that object is hostile to target
+ range = GetSpellMaxRangeForHostile(srentry);
+ }
// search nearest linked GO
GameObject* trapGO = NULL;
@@ -834,18 +837,18 @@ void GameObject::TriggeringLinkedGameObject( uint32 trapEntry, Unit* target)
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
- Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*target,trapEntry,range);
- Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(trapGO,go_check);
+ MaNGOS::NearestGameObjectEntryInObjectRangeCheck go_check(*target,trapEntry,range);
+ MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> checker(this, trapGO,go_check);
TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
+ cell_lock->Visit(cell_lock, object_checker, *GetMap());
}
// found correct GO
// FIXME: when GO casting will be implemented trap must cast spell to target
if(trapGO)
- target->CastSpell(target,trapSpell,true);
+ target->CastSpell(target,trapSpell,true, 0, 0, GetGUID());
}
GameObject* GameObject::LookupFishingHoleAround(float range)
@@ -855,18 +858,28 @@ GameObject* GameObject::LookupFishingHoleAround(float range)
CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY()));
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
- Trinity::NearestGameObjectFishingHole u_check(*this, range);
- Trinity::GameObjectSearcher<Trinity::NearestGameObjectFishingHole> checker(ok, u_check);
+ MaNGOS::NearestGameObjectFishingHole u_check(*this, range);
+ MaNGOS::GameObjectSearcher<MaNGOS::NearestGameObjectFishingHole> checker(this, ok, u_check);
CellLock<GridReadGuard> cell_lock(cell, p);
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::NearestGameObjectFishingHole>, GridTypeMapContainer > grid_object_checker(checker);
- cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
+ cell_lock->Visit(cell_lock, grid_object_checker, *GetMap());
return ok;
}
-void GameObject::UseDoorOrButton(uint32 time_to_restore)
+void GameObject::ResetDoorOrButton()
+{
+ if (m_lootState == GO_READY || m_lootState == GO_JUST_DEACTIVATED)
+ return;
+
+ SwitchDoorOrButton(false);
+ SetLootState(GO_JUST_DEACTIVATED);
+ m_cooldownTime = 0;
+}
+
+void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */)
{
if(m_lootState != GO_READY)
return;
@@ -874,32 +887,31 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore)
if(!time_to_restore)
time_to_restore = GetAutoCloseTime();
- SwitchDoorOrButton(true);
+ SwitchDoorOrButton(true,alternative);
SetLootState(GO_ACTIVATED);
m_cooldownTime = time(NULL) + time_to_restore;
-
}
-void GameObject::SetGoArtKit(uint32 kit)
+void GameObject::SetGoArtKit(uint8 kit)
{
- SetUInt32Value(GAMEOBJECT_ARTKIT, kit);
+ SetByteValue(GAMEOBJECT_BYTES_1, 2, kit);
GameObjectData *data = const_cast<GameObjectData*>(objmgr.GetGOData(m_DBTableGuid));
if(data)
data->ArtKit = kit;
}
-void GameObject::SwitchDoorOrButton(bool activate)
+void GameObject::SwitchDoorOrButton(bool activate, bool alternative /* = false */)
{
if(activate)
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
else
RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
- if(GetGoState()) //if closed -> open
- SetGoState(0);
+ if(GetGoState() == GO_STATE_READY) //if closed -> open
+ SetGoState(alternative ? GO_STATE_ACTIVE_ALTERNATIVE : GO_STATE_ACTIVE);
else //if open -> close
- SetGoState(1);
+ SetGoState(GO_STATE_READY);
}
void GameObject::Use(Unit* user)
@@ -907,6 +919,7 @@ void GameObject::Use(Unit* user)
// by default spell caster is user
Unit* spellCaster = user;
uint32 spellId = 0;
+ bool triggered = false;
switch(GetGoType())
{
@@ -956,7 +969,7 @@ void GameObject::Use(Unit* user)
// every slot will be on that straight line
float orthogonalOrientation = GetOrientation()+M_PI*0.5f;
// find nearest slot
- for(uint32 i=0; i<info->chair.slots; i++)
+ for(uint32 i=0; i<info->chair.slots; ++i)
{
// the distance between this slot and the center of the go - imagine a 1D space
float relativeDistance = (info->size*i)-(info->size*(info->chair.slots-1)/2.0f);
@@ -988,7 +1001,7 @@ void GameObject::Use(Unit* user)
// fallback, will always work
player->TeleportTo(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(),TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET);
}
- player->SetStandState(PLAYER_STATE_SIT_LOW_CHAIR+info->chair.height);
+ player->SetStandState(UNIT_STAND_STATE_SIT_LOW_CHAIR+info->chair.height);
return;
}
//big gun, its a spell/aura
@@ -1028,12 +1041,9 @@ void GameObject::Use(Unit* user)
Player* player = (Player*)user;
- if(info->camera.cinematicId)
- {
- WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4);
- data << info->camera.cinematicId;
- player->GetSession()->SendPacket(&data);
- }
+ if (info->camera.cinematicId)
+ player->SendCinematicStart(info->camera.cinematicId);
+
return;
}
//fishing bobber
@@ -1055,11 +1065,12 @@ void GameObject::Use(Unit* user)
// 2) if skill == base_zone_skill => 5% chance
// 3) chance is linear dependence from (base_zone_skill-skill)
- uint32 subzone = GetAreaId();
+ uint32 zone, subzone;
+ GetZoneAndAreaId(zone,subzone);
int32 zone_skill = objmgr.GetFishingBaseSkillLevel( subzone );
if(!zone_skill)
- zone_skill = objmgr.GetFishingBaseSkillLevel( GetZoneId() );
+ zone_skill = objmgr.GetFishingBaseSkillLevel( zone );
//provide error, no fishable zone or area should be 0
if(!zone_skill)
@@ -1084,6 +1095,7 @@ void GameObject::Use(Unit* user)
if (ok)
{
player->SendLoot(ok->GetGUID(),LOOT_FISHINGHOLE);
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT, ok->GetGOInfo()->id);
SetLootState(GO_JUST_DEACTIVATED);
}
else
@@ -1150,6 +1162,13 @@ void GameObject::Use(Unit* user)
return;
spellId = info->summoningRitual.spellId;
+ if(spellId==62330) // GO store not existed spell, replace by expected
+ {
+ // spell have reagent and mana cost but it not expected use its
+ // it triggered spell in fact casted at currently channeled GO
+ spellId = 61993;
+ triggered = true;
+ }
// finish spell
caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0);
@@ -1207,7 +1226,10 @@ void GameObject::Use(Unit* user)
if (level < info->meetingstone.minLevel || level > info->meetingstone.maxLevel)
return;
- spellId = 23598;
+ if(info->id==194097)
+ spellId = 61994; // Ritual of Summoning
+ else
+ spellId = 59782; // Summoning Stone Effect
break;
}
@@ -1219,7 +1241,7 @@ void GameObject::Use(Unit* user)
Player* player = (Player*)user;
- if( player->isAllowUseBattleGroundObject() )
+ if( player->CanUseBattleGroundObject() )
{
// in battleground check
BattleGround *bg = player->GetBattleGround();
@@ -1244,7 +1266,7 @@ void GameObject::Use(Unit* user)
Player* player = (Player*)user;
- if( player->isAllowUseBattleGroundObject() )
+ if( player->CanUseBattleGroundObject() )
{
// in battleground check
BattleGround *bg = player->GetBattleGround();
@@ -1282,6 +1304,26 @@ void GameObject::Use(Unit* user)
}
break;
}
+ case GAMEOBJECT_TYPE_BARBER_CHAIR: //32
+ {
+ GameObjectInfo const* info = GetGOInfo();
+ if(!info)
+ return;
+
+ if(user->GetTypeId()!=TYPEID_PLAYER)
+ return;
+
+ Player* player = (Player*)user;
+
+ // fallback, will always work
+ player->TeleportTo(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(),TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET);
+
+ WorldPacket data(SMSG_ENABLE_BARBER_SHOP, 0);
+ player->GetSession()->SendPacket(&data);
+
+ player->SetStandState(UNIT_STAND_STATE_SIT_LOW_CHAIR+info->barberChair.chairheight);
+ return;
+ }
default:
sLog.outDebug("Unknown Object Type %u", GetGoType());
break;
@@ -1300,7 +1342,7 @@ void GameObject::Use(Unit* user)
return;
}
- Spell *spell = new Spell(spellCaster, spellInfo, false);
+ Spell *spell = new Spell(spellCaster, spellInfo, triggered);
// spell target is user of GO
SpellCastTargets targets;
@@ -1309,8 +1351,29 @@ void GameObject::Use(Unit* user)
spell->prepare(&targets);
}
-void GameObject::CastSpell(Unit* target, uint32 spell)
+void GameObject::CastSpell(Unit* target, uint32 spellId)
{
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
+ if(!spellInfo)
+ return;
+
+ bool self = false;
+ for(int i = 0; i < 3; ++i)
+ {
+ if(spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_CASTER)
+ {
+ self = true;
+ break;
+ }
+ }
+
+ if(self)
+ {
+ if(target)
+ target->CastSpell(target, spellInfo, true);
+ return;
+ }
+
//summon world trigger
Creature *trigger = SummonTrigger(GetPositionX(), GetPositionY(), GetPositionZ(), 0, 1);
if(!trigger) return;
@@ -1319,17 +1382,88 @@ void GameObject::CastSpell(Unit* target, uint32 spell)
if(Unit *owner = GetOwner())
{
trigger->setFaction(owner->getFaction());
- trigger->CastSpell(target, spell, true, 0, 0, owner->GetGUID());
+ trigger->CastSpell(target, spellInfo, true, 0, 0, owner->GetGUID());
}
else
{
trigger->setFaction(14);
- trigger->CastSpell(target, spell, true, 0, 0, target->GetGUID());
+ trigger->CastSpell(target, spellInfo, true);
}
//trigger->setDeathState(JUST_DIED);
//trigger->RemoveCorpse();
}
+void GameObject::SendCustomAnim()
+{
+ WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4);
+ data << GetGUID();
+ data << (uint32)0;
+ SendMessageToSet(&data, true);
+}
+
+bool GameObject::IsInRange(float x, float y, float z, float radius) const
+{
+ GameObjectDisplayInfoEntry const * info = sGameObjectDisplayInfoStore.LookupEntry(GetUInt32Value(GAMEOBJECT_DISPLAYID));
+ if(!info)
+ return IsWithinDist3d(x, y, z, radius);
+
+ float sinA = sin(GetOrientation());
+ float cosA = cos(GetOrientation());
+ float dx = x - GetPositionX();
+ float dy = y - GetPositionY();
+ float dz = z - GetPositionZ();
+ float dist = sqrt(dx*dx + dy*dy);
+ float sinB = dx / dist;
+ float cosB = dy / dist;
+ dx = dist * (cosA * cosB + sinA * sinB);
+ dy = dist * (cosA * sinB - sinA * cosB);
+ return dx < info->maxX + radius && dx > info->minX - radius
+ && dy < info->maxY + radius && dy > info->minY - radius
+ && dz < info->maxZ + radius && dz > info->minZ - radius;
+}
+
+void GameObject::TakenDamage(uint32 damage)
+{
+ if(!m_health)
+ return;
+
+ if(m_health > damage)
+ {
+ m_health -= damage;
+ return;
+ }
+
+ m_health = 0;
+
+ if(HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED)) // from damaged to destroyed
+ {
+ RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED);
+ SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED);
+ SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->destructibleBuilding.destroyedDisplayId);
+ m_health = 0;
+ }
+ else // from undamaged to damaged
+ {
+ SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED);
+ SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->destructibleBuilding.damagedDisplayId);
+ if(m_goInfo->destructibleBuilding.destroyedDisplayId)
+ {
+ m_health = m_goInfo->destructibleBuilding.destroyedHealth;
+ if(!m_health)
+ m_health = 1;
+ }
+ else
+ m_health = 0;
+ }
+}
+
+void GameObject::Rebuild()
+{
+ RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED + GO_FLAG_DESTROYED);
+ SetUInt32Value(GAMEOBJECT_DISPLAYID, m_goInfo->displayId);
+ m_health = m_goInfo->destructibleBuilding.damagedHealth;
+}
+
// overwrite WorldObject function for proper name localization
const char* GameObject::GetNameForLocaleIdx(int32 loc_idx) const
{
@@ -1346,3 +1480,25 @@ const char* GameObject::GetNameForLocaleIdx(int32 loc_idx) const
return GetName();
}
+void GameObject::UpdateRotationFields(float rotation2 /*=0.0f*/, float rotation3 /*=0.0f*/)
+{
+ static double const atan_pow = atan(pow(2.0f, -20.0f));
+
+ SetFloatValue(GAMEOBJECT_FACING, GetOrientation());
+
+ double f_rot1 = sin(GetOrientation() / 2.0f);
+ double f_rot2 = cos(GetOrientation() / 2.0f);
+
+ int64 i_rot1 = int64(f_rot1 / atan_pow *(f_rot2 >= 0 ? 1.0f : -1.0f));
+ int64 rotation = (i_rot1 << 43 >> 43) & 0x00000000001FFFFF;
+ SetUInt64Value(GAMEOBJECT_ROTATION, rotation);
+
+ if(rotation2==0.0f && rotation3==0.0f)
+ {
+ rotation2 = f_rot1;
+ rotation3 = f_rot2;
+ }
+
+ SetFloatValue(GAMEOBJECT_PARENTROTATION+2, rotation2);
+ SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rotation3);
+}
diff --git a/src/game/GameObject.h b/src/game/GameObject.h
index 2eb51a6fbe4..befe9c23a8b 100644
--- a/src/game/GameObject.h
+++ b/src/game/GameObject.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,6 +41,7 @@ struct GameObjectInfo
uint32 type;
uint32 displayId;
char *name;
+ char *IconName;
char *castBarCaption;
uint32 faction;
uint32 flags;
@@ -336,20 +337,34 @@ struct GameObjectInfo
uint32 mapID; //0
uint32 difficulty; //1
} dungeonDifficulty;
- //32 GAMEOBJECT_TYPE_DO_NOT_USE_YET
+ //32 GAMEOBJECT_TYPE_BARBER_CHAIR
struct
{
- uint32 mapID; //0
- uint32 difficulty; //1
- } doNotUseYet;
+ uint32 chairheight; //0
+ uint32 heightOffset; //1
+ } barberChair;
//33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
struct
{
- uint32 dmgPctState1; //0
+ uint32 damagedHealth; //0
uint32 dmgPctState2; //1
uint32 state1Name; //2
uint32 state2Name; //3
+ uint32 damagedDisplayId; //4
+ uint32 destroyedHealth; //5
+ uint32 unk6;
+ uint32 unk7;
+ uint32 unk8;
+ uint32 unk9;
+ uint32 destroyedDisplayId; //10
} destructibleBuilding;
+ //34 GAMEOBJECT_TYPE_TRAPDOOR
+ struct
+ {
+ uint32 whenToPause; // 0
+ uint32 startOpen; // 1
+ uint32 autoClose; // 2
+ } trapDoor;
// not use for specific field access (only for output with loop by all filed), also this determinate max union size
struct // GAMEOBJECT_TYPE_SPELLCASTER
@@ -360,17 +375,35 @@ struct GameObjectInfo
uint32 ScriptId;
};
+// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
+#if defined( __GNUC__ )
+#pragma pack()
+#else
+#pragma pack(pop)
+#endif
+
struct GameObjectLocale
{
std::vector<std::string> Name;
std::vector<std::string> CastBarCaption;
};
+// client side GO show states
+enum GOState
+{
+ GO_STATE_ACTIVE = 0, // show in world as used and not reset (closed door open)
+ GO_STATE_READY = 1, // show in world as ready (closed door close)
+ GO_STATE_ACTIVE_ALTERNATIVE = 2 // show in world as used in alt way and not reset (closed door open by cannon fire)
+};
+
+#define MAX_GO_STATE 3
+
// from `gameobject`
struct GameObjectData
{
uint32 id; // entry in gamobject_template
- uint32 mapid;
+ uint16 mapid;
+ uint16 phaseMask;
float posX;
float posY;
float posZ;
@@ -381,18 +414,11 @@ struct GameObjectData
float rotation3;
int32 spawntimesecs;
uint32 animprogress;
- uint32 go_state;
+ GOState go_state;
uint8 spawnMask;
uint32 ArtKit;
};
-// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
-#if defined( __GNUC__ )
-#pragma pack()
-#else
-#pragma pack(pop)
-#endif
-
// For containers: [GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY -> ...
// For bobber: GO_NOT_READY ->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED-><deleted>
// For door(closed):[GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY(close) -> ...
@@ -419,7 +445,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
void AddToWorld();
void RemoveFromWorld();
- bool Create(uint32 guidlow, uint32 name_id, Map *map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, uint32 go_state, uint32 ArtKit = 0);
+ bool Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 ArtKit = 0);
void Update(uint32 p_time);
static GameObject* GetGameObject(WorldObject& object, uint64 guid);
GameObjectInfo const* GetGOInfo() const;
@@ -436,23 +462,21 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
- void Say(const char* text, uint32 language, uint64 TargetGuid) { MonsterSay(text,language,TargetGuid); }
- void Yell(const char* text, uint32 language, uint64 TargetGuid) { MonsterYell(text,language,TargetGuid); }
- void TextEmote(const char* text, uint64 TargetGuid) { MonsterTextEmote(text,TargetGuid); }
- void Whisper(const char* text,uint64 receiver) { MonsterWhisper(text,receiver); }
+ void UpdateRotationFields(float rotation2 = 0.0f, float rotation3 = 0.0f);
+
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
void Whisper(int32 textId, uint64 receiver) { MonsterWhisper(textId,receiver); }
+ void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
// overwrite WorldObject function for proper name localization
const char* GetNameForLocaleIdx(int32 locale_idx) const;
void SaveToDB();
- void SaveToDB(uint32 mapid, uint8 spawnMask);
+ void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
bool LoadFromDB(uint32 guid, Map *map);
void DeleteFromDB();
- void SetLootState(LootState s) { m_lootState = s; }
static uint32 GetLootId(GameObjectInfo const* info);
uint32 GetLootId() const { return GetLootId(GetGOInfo()); }
uint32 GetLockId() const
@@ -474,6 +498,20 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
}
}
+ bool GetDespawnPossibility() const
+ {
+ switch(GetGoType())
+ {
+ case GAMEOBJECT_TYPE_DOOR: return GetGOInfo()->door.noDamageImmune;
+ case GAMEOBJECT_TYPE_BUTTON: return GetGOInfo()->button.noDamageImmune;
+ case GAMEOBJECT_TYPE_QUESTGIVER: return GetGOInfo()->questgiver.noDamageImmune;
+ case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.noDamageImmune;
+ case GAMEOBJECT_TYPE_FLAGSTAND: return GetGOInfo()->flagstand.noDamageImmune;
+ case GAMEOBJECT_TYPE_FLAGDROP: return GetGOInfo()->flagdrop.noDamageImmune;
+ default: return true;
+ }
+ }
+
time_t GetRespawnTime() const { return m_respawnTime; }
time_t GetRespawnTimeEx() const
{
@@ -503,19 +541,20 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
void Delete();
void SetSpellId(uint32 id) { m_spellId = id;}
uint32 GetSpellId() const { return m_spellId;}
- void getFishLoot(Loot *loot);
- GameobjectTypes GetGoType() const { return GameobjectTypes(GetUInt32Value(GAMEOBJECT_TYPE_ID)); }
- void SetGoType(GameobjectTypes type) { SetUInt32Value(GAMEOBJECT_TYPE_ID, type); }
- uint32 GetGoState() const { return GetUInt32Value(GAMEOBJECT_STATE); }
- void SetGoState(uint32 state) { SetUInt32Value(GAMEOBJECT_STATE, state); }
- uint32 GetGoArtKit() const { return GetUInt32Value(GAMEOBJECT_ARTKIT); }
- void SetGoArtKit(uint32 artkit);
- uint32 GetGoAnimProgress() const { return GetUInt32Value(GAMEOBJECT_ANIMPROGRESS); }
- void SetGoAnimProgress(uint32 animprogress) { SetUInt32Value(GAMEOBJECT_ANIMPROGRESS, animprogress); }
+ void getFishLoot(Loot *loot, Player* loot_owner);
+ GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
+ void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
+ GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
+ void SetGoState(GOState state) { SetByteValue(GAMEOBJECT_BYTES_1, 0, state); }
+ uint8 GetGoArtKit() const { return GetByteValue(GAMEOBJECT_BYTES_1, 2); }
+ void SetGoArtKit(uint8 artkit);
+ uint8 GetGoAnimProgress() const { return GetByteValue(GAMEOBJECT_BYTES_1, 3); }
+ void SetGoAnimProgress(uint8 animprogress) { SetByteValue(GAMEOBJECT_BYTES_1, 3, animprogress); }
void Use(Unit* user);
LootState getLootState() const { return m_lootState; }
+ void SetLootState(LootState s) { m_lootState = s; }
void AddToSkillupList(uint32 PlayerGuidLow) { m_SkillupList.push_back(PlayerGuidLow); }
bool IsInSkillupList(uint32 PlayerGuidLow) const
@@ -539,7 +578,10 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
bool hasQuest(uint32 quest_id) const;
bool hasInvolvedQuest(uint32 quest_id) const;
bool ActivateToQuest(Player *pTarget) const;
- void UseDoorOrButton(uint32 time_to_restore = 0); // 0 = use `gameobject`.`spawntimesecs`
+ void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false);
+ // 0 = use `gameobject`.`spawntimesecs`
+ void ResetDoorOrButton();
+ // 0 = use `gameobject`.`spawntimesecs`
uint32 GetLinkedGameObjectEntry() const
{
@@ -578,6 +620,10 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
GridReference<GameObject> &GetGridRef() { return m_gridRef; }
void CastSpell(Unit *target, uint32 spell);
+ void SendCustomAnim();
+ bool IsInRange(float x, float y, float z, float radius) const;
+ void TakenDamage(uint32 damage);
+ void Rebuild();
protected:
uint32 m_charges; // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22)
uint32 m_spellId;
@@ -586,6 +632,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
LootState m_lootState;
bool m_spawnedByDefault;
time_t m_cooldownTime; // used as internal reaction delay time store (not state change reaction).
+ uint32 m_health;
// For traps this: spell casting cooldown, for doors/buttons: reset time.
std::list<uint32> m_SkillupList;
@@ -595,7 +642,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
uint32 m_DBTableGuid; ///< For new or temporary gameobjects is 0 for saved it is lowguid
GameObjectInfo const* m_goInfo;
private:
- void SwitchDoorOrButton(bool activate);
+ void SwitchDoorOrButton(bool activate, bool alternative = false);
GridReference<GameObject> m_gridRef;
};
diff --git a/src/game/GlobalEvents.cpp b/src/game/GlobalEvents.cpp
index 957462b9e22..a544113f5c8 100644
--- a/src/game/GlobalEvents.cpp
+++ b/src/game/GlobalEvents.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/GlobalEvents.h b/src/game/GlobalEvents.h
index 6ec6e6b60b1..aa99c47985e 100644
--- a/src/game/GlobalEvents.h
+++ b/src/game/GlobalEvents.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/GossipDef.cpp b/src/game/GossipDef.cpp
index b0f717eea9e..42c4c66ef01 100644
--- a/src/game/GossipDef.cpp
+++ b/src/game/GossipDef.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -127,12 +127,12 @@ bool PlayerMenu::GossipOptionCoded( unsigned int Selection )
void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID )
{
WorldPacket data( SMSG_GOSSIP_MESSAGE, (100) ); // guess size
- data << npcGUID;
+ data << uint64(npcGUID);
data << uint32(0); // new 2.4.0
data << uint32( TitleTextId );
data << uint32( mGossipMenu.MenuItemCount() ); // max count 0x0F
- for ( unsigned int iI = 0; iI < mGossipMenu.MenuItemCount(); iI++ )
+ for (uint32 iI = 0; iI < mGossipMenu.MenuItemCount(); ++iI )
{
GossipMenuItem const& gItem = mGossipMenu.GetItem(iI);
data << uint32( iI );
@@ -145,7 +145,7 @@ void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID )
data << uint32( mQuestMenu.MenuItemCount() ); // max count 0x20
- for ( uint16 iI = 0; iI < mQuestMenu.MenuItemCount(); iI++ )
+ for (uint32 iI = 0; iI < mQuestMenu.MenuItemCount(); ++iI )
{
QuestMenuItem const& qItem = mQuestMenu.GetItem(iI);
uint32 questID = qItem.m_qId;
@@ -153,7 +153,7 @@ void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID )
data << uint32(questID);
data << uint32( qItem.m_qIcon );
- data << uint32( pQuest ? pQuest->GetQuestLevel() : 0 );
+ data << uint32(pSession->GetPlayer()->GetQuestLevel(pQuest));
std::string Title = pQuest->GetTitle();
int loc_idx = pSession->GetSessionDbLocaleIndex();
@@ -181,6 +181,7 @@ void PlayerMenu::CloseGossip()
//sLog.outDebug( "WORLD: Sent SMSG_GOSSIP_COMPLETE" );
}
+// Outdated
void PlayerMenu::SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, char const * locName )
{
WorldPacket data( SMSG_GOSSIP_POI, (4+4+4+4+4+10) ); // guess size
@@ -194,12 +195,43 @@ void PlayerMenu::SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flag
//sLog.outDebug("WORLD: Sent SMSG_GOSSIP_POI");
}
-void PlayerMenu::SendTalking( uint32 textID )
+void PlayerMenu::SendPointOfInterest( uint32 poi_id )
{
- GossipText *pGossip;
- std::string GossipStr;
+ PointOfInterest const* poi = objmgr.GetPointOfInterest(poi_id);
+ if(!poi)
+ {
+ sLog.outErrorDb("Requested send not existed POI (Id: %u), ignore.",poi_id);
+ return;
+ }
+
+ std::string icon_name = poi->icon_name;
+
+ int loc_idx = pSession->GetSessionDbLocaleIndex();
+ if (loc_idx >= 0)
+ {
+ PointOfInterestLocale const *pl = objmgr.GetPointOfInterestLocale(poi_id);
+ if (pl)
+ {
+ if (pl->IconName.size() > size_t(loc_idx) && !pl->IconName[loc_idx].empty())
+ icon_name = pl->IconName[loc_idx];
+ }
+ }
+
+ WorldPacket data( SMSG_GOSSIP_POI, (4+4+4+4+4+10) ); // guess size
+ data << uint32(poi->flags);
+ data << float(poi->x);
+ data << float(poi->y);
+ data << uint32(poi->icon);
+ data << uint32(poi->data);
+ data << icon_name;
+
+ pSession->SendPacket( &data );
+ //sLog.outDebug("WORLD: Sent SMSG_GOSSIP_POI");
+}
- pGossip = objmgr.GetGossipText(textID);
+void PlayerMenu::SendTalking( uint32 textID )
+{
+ GossipText const* pGossip = objmgr.GetGossipText(textID);
WorldPacket data( SMSG_NPC_TEXT_UPDATE, 100 ); // guess size
data << textID; // can be < 0
@@ -223,7 +255,7 @@ void PlayerMenu::SendTalking( uint32 textID )
else
{
std::string Text_0[8],Text_1[8];
- for (int i=0;i<8;i++)
+ for (int i=0;i<8;++i)
{
Text_0[i]=pGossip->Options[i].Text_0;
Text_1[i]=pGossip->Options[i].Text_1;
@@ -234,7 +266,7 @@ void PlayerMenu::SendTalking( uint32 textID )
NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID);
if (nl)
{
- for (int i=0;i<8;i++)
+ for (int i=0;i<8;++i)
{
if (nl->Text_0[i].size() > loc_idx && !nl->Text_0[i][loc_idx].empty())
Text_0[i]=nl->Text_0[i][loc_idx];
@@ -243,7 +275,7 @@ void PlayerMenu::SendTalking( uint32 textID )
}
}
}
- for (int i=0; i<8; i++)
+ for (int i=0; i<8; ++i)
{
data << pGossip->Options[i].Probability;
@@ -259,14 +291,11 @@ void PlayerMenu::SendTalking( uint32 textID )
data << pGossip->Options[i].Language;
- data << pGossip->Options[i].Emotes[0]._Delay;
- data << pGossip->Options[i].Emotes[0]._Emote;
-
- data << pGossip->Options[i].Emotes[1]._Delay;
- data << pGossip->Options[i].Emotes[1]._Emote;
-
- data << pGossip->Options[i].Emotes[2]._Delay;
- data << pGossip->Options[i].Emotes[2]._Emote;
+ for(int j = 0; j < 3; ++j)
+ {
+ data << pGossip->Options[i].Emotes[j]._Delay;
+ data << pGossip->Options[i].Emotes[j]._Emote;
+ }
}
}
pSession->SendPacket( &data );
@@ -328,7 +357,7 @@ void QuestMenu::AddMenuItem( uint32 QuestId, uint8 Icon)
bool QuestMenu::HasItem( uint32 questid )
{
- for (QuestMenuItemList::iterator i = m_qItems.begin(); i != m_qItems.end(); ++i)
+ for (QuestMenuItemList::const_iterator i = m_qItems.begin(); i != m_qItems.end(); ++i)
{
if(i->m_qId==questid)
{
@@ -352,7 +381,7 @@ void PlayerMenu::SendQuestGiverQuestList( QEmote eEmote, const std::string& Titl
data << uint32(eEmote._Emote ); // NPC emote
data << uint8 ( mQuestMenu.MenuItemCount() );
- for ( uint16 iI = 0; iI < mQuestMenu.MenuItemCount(); iI++ )
+ for (uint32 iI = 0; iI < mQuestMenu.MenuItemCount(); ++iI )
{
QuestMenuItem const& qmi = mQuestMenu.GetItem(iI);
@@ -373,7 +402,7 @@ void PlayerMenu::SendQuestGiverQuestList( QEmote eEmote, const std::string& Titl
data << uint32(questID);
data << uint32(qmi.m_qIcon);
- data << uint32(pQuest ? pQuest->GetQuestLevel() : 0);
+ data << uint32(pSession->GetPlayer()->GetQuestLevel(pQuest));
data << title;
}
pSession->SendPacket( &data );
@@ -417,10 +446,14 @@ void PlayerMenu::SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID
}
data << uint64(npcGUID);
+ data << uint64(0); // wotlk, something todo with quest sharing?
data << uint32(pQuest->GetQuestId());
- data << Title << Details << Objectives;
+ data << Title;
+ data << Details;
+ data << Objectives;
data << uint32(ActivateAccept);
data << uint32(pQuest->GetSuggestedPlayers());
+ data << uint8(0); // new wotlk
if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
{
@@ -433,7 +466,7 @@ void PlayerMenu::SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID
ItemPrototype const* IProto;
data << uint32(pQuest->GetRewChoiceItemsCount());
- for (uint32 i=0; i < QUEST_REWARD_CHOICES_COUNT; i++)
+ for (uint32 i=0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
{
if ( !pQuest->RewChoiceItemId[i] ) continue;
data << uint32(pQuest->RewChoiceItemId[i]);
@@ -446,7 +479,7 @@ void PlayerMenu::SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID
}
data << uint32(pQuest->GetRewItemsCount());
- for (uint32 i=0; i < QUEST_REWARDS_COUNT; i++)
+ for (uint32 i=0; i < QUEST_REWARDS_COUNT; ++i)
{
if ( !pQuest->RewItemId[i] ) continue;
data << uint32(pQuest->RewItemId[i]);
@@ -466,9 +499,10 @@ void PlayerMenu::SendQuestGiverQuestDetails( Quest const *pQuest, uint64 npcGUID
data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0)
data << uint32(pQuest->GetRewSpellCast()); // casted spell
data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
+ data << uint32(pQuest->GetBonusTalents()); // bonus talents
data << uint32(QUEST_EMOTE_COUNT);
- for (uint32 i=0; i < QUEST_EMOTE_COUNT; i++)
+ for (uint32 i=0; i < QUEST_EMOTE_COUNT; ++i)
{
data << uint32(pQuest->DetailsEmote[i]);
data << uint32(0); // DetailsEmoteDelay
@@ -486,7 +520,7 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest )
Details = pQuest->GetDetails();
Objectives = pQuest->GetObjectives();
EndText = pQuest->GetEndText();
- for (int i=0;i<QUEST_OBJECTIVES_COUNT;i++)
+ for (int i=0;i<QUEST_OBJECTIVES_COUNT;++i)
ObjectiveText[i]=pQuest->ObjectiveText[i];
int loc_idx = pSession->GetSessionDbLocaleIndex();
@@ -504,7 +538,7 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest )
if (ql->EndText.size() > loc_idx && !ql->EndText[loc_idx].empty())
EndText=ql->EndText[loc_idx];
- for (int i=0;i<QUEST_OBJECTIVES_COUNT;i++)
+ for (int i=0;i<QUEST_OBJECTIVES_COUNT;++i)
if (ql->ObjectiveText[i].size() > loc_idx && !ql->ObjectiveText[i][loc_idx].empty())
ObjectiveText[i]=ql->ObjectiveText[i][loc_idx];
}
@@ -514,7 +548,7 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest )
data << uint32(pQuest->GetQuestId());
data << uint32(pQuest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0==IsAutoComplete() (skip objectives/details)
- data << uint32(pQuest->GetQuestLevel()); // may be 0
+ data << uint32(pQuest->GetQuestLevel()); // may be 0, static data, in other cases must be used dynamic level: Player::GetQuestLevel
data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log
data << uint32(pQuest->GetType());
@@ -542,24 +576,26 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest )
data << uint32(pQuest->GetSrcItemId());
data << uint32(pQuest->GetFlags() & 0xFFFF);
data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
+ data << uint32(pQuest->GetPlayersSlain()); // players slain
+ data << uint32(pQuest->GetBonusTalents()); // bonus talents
int iI;
if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
{
- for (iI = 0; iI < QUEST_REWARDS_COUNT; iI++)
+ for (iI = 0; iI < QUEST_REWARDS_COUNT; ++iI)
data << uint32(0) << uint32(0);
- for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; iI++)
+ for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; ++iI)
data << uint32(0) << uint32(0);
}
else
{
- for (iI = 0; iI < QUEST_REWARDS_COUNT; iI++)
+ for (iI = 0; iI < QUEST_REWARDS_COUNT; ++iI)
{
data << uint32(pQuest->RewItemId[iI]);
data << uint32(pQuest->RewItemCount[iI]);
}
- for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; iI++)
+ for (iI = 0; iI < QUEST_REWARD_CHOICES_COUNT; ++iI)
{
data << uint32(pQuest->RewChoiceItemId[iI]);
data << uint32(pQuest->RewChoiceItemCount[iI]);
@@ -576,7 +612,7 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest )
data << Details;
data << EndText;
- for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++)
+ for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; ++iI)
{
if (pQuest->ReqCreatureOrGOId[iI] < 0)
{
@@ -588,15 +624,23 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest )
data << uint32(pQuest->ReqCreatureOrGOId[iI]);
}
data << uint32(pQuest->ReqCreatureOrGOCount[iI]);
+ data << uint32(pQuest->ReqSourceId[iI]);
+ }
+
+ for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; ++iI)
+ {
data << uint32(pQuest->ReqItemId[iI]);
data << uint32(pQuest->ReqItemCount[iI]);
}
- for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++)
+ data << uint32(0); // TODO: 5 item objective
+ data << uint32(0);
+
+ for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; ++iI)
data << ObjectiveText[iI];
pSession->SendPacket( &data );
- sLog.outDebug( "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u",pQuest->GetQuestId() );
+ sLog.outDebug( "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u", pQuest->GetQuestId() );
}
void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID, bool EnbleNext )
@@ -628,7 +672,7 @@ void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID,
data << uint32(0); // unk
uint32 EmoteCount = 0;
- for (uint32 i = 0; i < QUEST_EMOTE_COUNT; i++)
+ for (uint32 i = 0; i < QUEST_EMOTE_COUNT; ++i)
{
if(pQuest->OfferRewardEmote[i] <= 0)
break;
@@ -636,7 +680,7 @@ void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID,
}
data << EmoteCount; // Emote Count
- for (uint32 i = 0; i < EmoteCount; i++)
+ for (uint32 i = 0; i < EmoteCount; ++i)
{
data << uint32(0); // Delay Emote
data << pQuest->OfferRewardEmote[i];
@@ -645,7 +689,7 @@ void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID,
ItemPrototype const *pItem;
data << uint32(pQuest->GetRewChoiceItemsCount());
- for (uint32 i=0; i < pQuest->GetRewChoiceItemsCount(); i++)
+ for (uint32 i=0; i < pQuest->GetRewChoiceItemsCount(); ++i)
{
pItem = objmgr.GetItemPrototype( pQuest->RewChoiceItemId[i] );
@@ -659,7 +703,7 @@ void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID,
}
data << uint32(pQuest->GetRewItemsCount());
- for (uint16 i=0; i < pQuest->GetRewItemsCount(); i++)
+ for (uint16 i=0; i < pQuest->GetRewItemsCount(); ++i)
{
pItem = objmgr.GetItemPrototype(pQuest->RewItemId[i]);
data << uint32(pQuest->RewItemId[i]);
@@ -678,9 +722,10 @@ void PlayerMenu::SendQuestGiverOfferReward( Quest const* pQuest, uint64 npcGUID,
data << uint32(0x08); // unused by client?
data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0)
data << uint32(pQuest->GetRewSpellCast()); // casted spell
- data << uint32(0x00); // unk, NOT honor
+ data << uint32(0); // unknown
+ data << uint32(pQuest->GetBonusTalents()); // bonus talents
pSession->SendPacket( &data );
- sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPCGuid=%u, questid=%u",GUID_LOPART(npcGUID),pQuest->GetQuestId() );
+ sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), pQuest->GetQuestId() );
}
void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel )
@@ -688,16 +733,8 @@ void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID
// We can always call to RequestItems, but this packet only goes out if there are actually
// items. Otherwise, we'll skip straight to the OfferReward
- // We may wish a better check, perhaps checking the real quest requirements
- if (pQuest->GetRequestItemsText().empty())
- {
- SendQuestGiverOfferReward(pQuest, npcGUID, true);
- return;
- }
-
- std::string Title,RequestItemsText;
- Title = pQuest->GetTitle();
- RequestItemsText = pQuest->GetRequestItemsText();
+ std::string Title = pQuest->GetTitle();
+ std::string RequestItemsText = pQuest->GetRequestItemsText();
int loc_idx = pSession->GetSessionDbLocaleIndex();
if (loc_idx >= 0)
@@ -712,6 +749,13 @@ void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID
}
}
+ // We may wish a better check, perhaps checking the real quest requirements
+ if (RequestItemsText.empty())
+ {
+ SendQuestGiverOfferReward(pQuest, npcGUID, true);
+ return;
+ }
+
WorldPacket data( SMSG_QUESTGIVER_REQUEST_ITEMS, 50 ); // guess size
data << npcGUID;
data << pQuest->GetQuestId();
@@ -738,7 +782,7 @@ void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID
data << uint32( pQuest->GetReqItemsCount() );
ItemPrototype const *pItem;
- for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
+ for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
{
if ( !pQuest->ReqItemId[i] ) continue;
pItem = objmgr.GetItemPrototype(pQuest->ReqItemId[i]);
diff --git a/src/game/GossipDef.h b/src/game/GossipDef.h
index e2279550528..102a34b5913 100644
--- a/src/game/GossipDef.h
+++ b/src/game/GossipDef.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,27 +30,27 @@ class WorldSession;
#define GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough
#define DEFAULT_GOSSIP_MESSAGE 0xffffff
-//POI defines
+//POI icons. Many more exist, list not complete.
enum Poi_Icon
{
- ICON_POI_0 = 0, // Grey ?
- ICON_POI_1 = 1, // Red ?
- ICON_POI_2 = 2, // Blue ?
- ICON_POI_BWTOMB = 3, // Blue and White Tomb Stone
- ICON_POI_HOUSE = 4, // House
- ICON_POI_TOWER = 5, // Tower
- ICON_POI_REDFLAG = 6, // Red Flag with Yellow !
- ICON_POI_TOMB = 7, // Tomb Stone
- ICON_POI_BWTOWER = 8, // Blue and White Tower
- ICON_POI_REDTOWER = 9, // Red Tower
- ICON_POI_BLUETOWER = 10, // Blue Tower
- ICON_POI_RWTOWER = 11, // Red and White Tower
- ICON_POI_REDTOMB = 12, // Red Tomb Stone
- ICON_POI_RWTOMB = 13, // Red and White Tomb Stone
- ICON_POI_BLUETOMB = 14, // Blue Tomb Stone
- ICON_POI_NOTHING = 15, // NOTHING
- ICON_POI_16 = 16, // Red ?
- ICON_POI_17 = 17, // Grey ?
+ ICON_POI_BLANK = 0, // Blank (not visible)
+ ICON_POI_GREY_AV_MINE = 1, // Grey mine lorry
+ ICON_POI_RED_AV_MINE = 2, // Red mine lorry
+ ICON_POI_BLUE_AV_MINE = 3, // Blue mine lorry
+ ICON_POI_BWTOMB = 4, // Blue and White Tomb Stone
+ ICON_POI_SMALL_HOUSE = 5, // Small house
+ ICON_POI_GREYTOWER = 6, // Grey Tower
+ ICON_POI_REDFLAG = 7, // Red Flag w/Yellow !
+ ICON_POI_TOMBSTONE = 8, // Normal tomb stone (brown)
+ ICON_POI_BWTOWER = 9, // Blue and White Tower
+ ICON_POI_REDTOWER = 10, // Red Tower
+ ICON_POI_BLUETOWER = 11, // Blue Tower
+ ICON_POI_RWTOWER = 12, // Red and White Tower
+ ICON_POI_REDTOMB = 13, // Red Tomb Stone
+ ICON_POI_RWTOMB = 14, // Red and White Tomb Stone
+ ICON_POI_BLUETOMB = 15, // Blue Tomb Stone
+ ICON_POI_16 = 16, // Grey ?
+ ICON_POI_17 = 17, // Blue/White ?
ICON_POI_18 = 18, // Blue ?
ICON_POI_19 = 19, // Red and White ?
ICON_POI_20 = 20, // Red ?
@@ -189,6 +189,7 @@ class TRINITY_DLL_SPEC PlayerMenu
void SendGossipMenu( uint32 TitleTextId, uint64 npcGUID );
void CloseGossip();
void SendPointOfInterest( float X, float Y, uint32 Icon, uint32 Flags, uint32 Data, const char * locName );
+ void SendPointOfInterest( uint32 poi_id );
void SendTalking( uint32 textID );
void SendTalking( char const * title, char const * text );
diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h
index cb67897329f..a3fe011f402 100644
--- a/src/game/GridDefines.h
+++ b/src/game/GridDefines.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,7 +48,7 @@ class Player;
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
-#define MIN_GRID_DELAY MINUTE*1000
+#define MIN_GRID_DELAY (MINUTE*IN_MILISECONDS)
#define MIN_MAP_UPDATE_DELAY 50
#define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS)
@@ -57,7 +57,7 @@ class Player;
#define TOTAL_NUMBER_OF_CELLS_PER_MAP (MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_CELLS)
-#define MAP_RESOLUTION 256
+#define MAP_RESOLUTION 128
#define MAP_SIZE (SIZE_OF_GRIDS*MAX_NUMBER_OF_GRIDS)
#define MAP_HALFSIZE (MAP_SIZE/2)
diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp
index fe1a072cf20..091fb1c293a 100644
--- a/src/game/GridNotifiers.cpp
+++ b/src/game/GridNotifiers.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
#include "UpdateData.h"
#include "Item.h"
#include "Map.h"
-#include "MapManager.h"
#include "Transports.h"
#include "ObjectAccessor.h"
@@ -94,9 +93,9 @@ PlayerVisibilityNotifier::Notify()
// Now do operations that required done at object visibility change to visible
- // target aura duration for caster show only if target exist at caster client
// send data at target visibility change (adding to client)
for(std::set<WorldObject*>::const_iterator vItr = i_visibleNow.begin(); vItr != i_visibleNow.end(); ++vItr)
+ // target aura duration for caster show only if target exist at caster client
if((*vItr)!=&i_player && (*vItr)->isType(TYPEMASK_UNIT))
i_player.SendInitialVisiblePackets((Unit*)(*vItr));
@@ -109,14 +108,20 @@ Deliverer::Visit(PlayerMapType &m)
{
for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
- if (!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist)
+ //if (!i_source.InSamePhase(iter->getSource()))
+ // continue;
+ if(!iter->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (!i_dist || iter->getSource()->GetDistance(&i_source) < i_dist)
{
// Send packet to all who are sharing the player's vision
if (!iter->getSource()->GetSharedVisionList().empty())
{
- SharedVisionList::const_iterator it = iter->getSource()->GetSharedVisionList().begin();
- for ( ; it != iter->getSource()->GetSharedVisionList().end(); ++it)
- SendPacket(*it);
+ SharedVisionList::const_iterator i = iter->getSource()->GetSharedVisionList().begin();
+ for ( ; i != iter->getSource()->GetSharedVisionList().end(); ++i)
+ if((*i)->m_seer == iter->getSource())
+ SendPacket(*i);
}
VisitObject(iter->getSource());
@@ -129,14 +134,18 @@ Deliverer::Visit(CreatureMapType &m)
{
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
- if (!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist)
+ if(!iter->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (!i_dist || iter->getSource()->GetDistance(&i_source) < i_dist)
{
// Send packet to all who are sharing the creature's vision
if (!iter->getSource()->GetSharedVisionList().empty())
{
- SharedVisionList::const_iterator it = iter->getSource()->GetSharedVisionList().begin();
- for ( ; it != iter->getSource()->GetSharedVisionList().end(); ++it)
- SendPacket(*it);
+ SharedVisionList::const_iterator i = iter->getSource()->GetSharedVisionList().begin();
+ for ( ; i != iter->getSource()->GetSharedVisionList().end(); ++i)
+ if((*i)->m_seer == iter->getSource())
+ SendPacket(*i);
}
}
}
@@ -147,13 +156,18 @@ Deliverer::Visit(DynamicObjectMapType &m)
{
for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
- if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID()))
+ if(!iter->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (!i_dist || iter->getSource()->GetDistance(&i_source) < i_dist)
{
- // Send packet back to the caster if the caster has vision of dynamic object
- Player* caster = (Player*)iter->getSource()->GetCaster();
- if (caster && caster->GetUInt64Value(PLAYER_FARSIGHT) == iter->getSource()->GetGUID() &&
- (!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist))
- SendPacket(caster);
+ if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID()))
+ {
+ // Send packet back to the caster if the caster has vision of dynamic object
+ Player* caster = (Player*)iter->getSource()->GetCaster();
+ if (caster && caster->m_seer == iter->getSource())
+ SendPacket(caster);
+ }
}
}
}
@@ -205,9 +219,6 @@ ObjectUpdater::Visit(GridRefManager<T> &m)
}
}
-template void ObjectUpdater::Visit<GameObject>(GameObjectMapType &);
-template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType &);
-
bool CannibalizeObjectCheck::operator()(Corpse* u)
{
// ignore bones
@@ -225,3 +236,5 @@ bool CannibalizeObjectCheck::operator()(Corpse* u)
return false;
}
+template void ObjectUpdater::Visit<GameObject>(GameObjectMapType &);
+template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType &);
diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h
index b34eee36e7b..138807674ae 100644
--- a/src/game/GridNotifiers.h
+++ b/src/game/GridNotifiers.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -108,8 +108,10 @@ namespace Trinity
std::set<uint64> plr_list;
bool i_toPossessor;
bool i_toSelf;
+ uint32 i_phaseMask;
float i_dist;
- Deliverer(WorldObject &src, WorldPacket *msg, bool to_possessor, bool to_self, float dist = 0.0f) : i_source(src), i_message(msg), i_toPossessor(to_possessor), i_toSelf(to_self), i_dist(dist) {}
+ Deliverer(WorldObject &src, WorldPacket *msg, bool to_possessor, bool to_self, float dist = 0.0f)
+ : i_source(src), i_message(msg), i_toPossessor(to_possessor), i_toSelf(to_self), i_dist(dist), i_phaseMask(src.GetPhaseMask()) {}
void Visit(PlayerMapType &m);
void Visit(CreatureMapType &m);
void Visit(DynamicObjectMapType &m);
@@ -208,10 +210,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL WorldObjectSearcher
{
+ uint32 i_phaseMask;
WorldObject* &i_object;
Check &i_check;
- WorldObjectSearcher(WorldObject* & result, Check& check) : i_object(result),i_check(check) {}
+ WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {}
void Visit(GameObjectMapType &m);
void Visit(PlayerMapType &m);
@@ -225,10 +229,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL WorldObjectListSearcher
{
+ uint32 i_phaseMask;
std::list<WorldObject*> &i_objects;
Check& i_check;
- WorldObjectListSearcher(std::list<WorldObject*> &objects, Check & check) : i_objects(objects),i_check(check) {}
+ WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*> &objects, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {}
void Visit(PlayerMapType &m);
void Visit(CreatureMapType &m);
@@ -242,37 +248,44 @@ namespace Trinity
template<class Do>
struct TRINITY_DLL_DECL WorldObjectWorker
{
+ uint32 i_phaseMask;
Do const& i_do;
- explicit WorldObjectWorker(Do const& _do) : i_do(_do) {}
+ WorldObjectWorker(WorldObject const* searcher, Do const& _do)
+ : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {}
void Visit(GameObjectMapType &m)
{
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- i_do(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ i_do(itr->getSource());
}
void Visit(PlayerMapType &m)
{
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- i_do(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ i_do(itr->getSource());
}
void Visit(CreatureMapType &m)
{
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- i_do(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ i_do(itr->getSource());
}
void Visit(CorpseMapType &m)
{
for(CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- i_do(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ i_do(itr->getSource());
}
void Visit(DynamicObjectMapType &m)
{
for(DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- i_do(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ i_do(itr->getSource());
}
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
@@ -283,10 +296,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL GameObjectSearcher
{
+ uint32 i_phaseMask;
GameObject* &i_object;
Check &i_check;
- GameObjectSearcher(GameObject* & result, Check& check) : i_object(result),i_check(check) {}
+ GameObjectSearcher(WorldObject const* searcher, GameObject* & result, Check& check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {}
void Visit(GameObjectMapType &m);
@@ -297,10 +312,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL GameObjectLastSearcher
{
+ uint32 i_phaseMask;
GameObject* &i_object;
Check& i_check;
- GameObjectLastSearcher(GameObject* & result, Check& check) : i_object(result),i_check(check) {}
+ GameObjectLastSearcher(WorldObject const* searcher, GameObject* & result, Check& check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) {}
void Visit(GameObjectMapType &m);
@@ -310,10 +327,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL GameObjectListSearcher
{
+ uint32 i_phaseMask;
std::list<GameObject*> &i_objects;
Check& i_check;
- GameObjectListSearcher(std::list<GameObject*> &objects, Check & check) : i_objects(objects),i_check(check) {}
+ GameObjectListSearcher(WorldObject const* searcher, std::list<GameObject*> &objects, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
void Visit(GameObjectMapType &m);
@@ -326,10 +345,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL UnitSearcher
{
+ uint32 i_phaseMask;
Unit* &i_object;
Check & i_check;
- UnitSearcher(Unit* & result, Check & check) : i_object(result),i_check(check) {}
+ UnitSearcher(WorldObject const* searcher, Unit* & result, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {}
void Visit(CreatureMapType &m);
void Visit(PlayerMapType &m);
@@ -341,10 +362,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL UnitLastSearcher
{
+ uint32 i_phaseMask;
Unit* &i_object;
Check & i_check;
- UnitLastSearcher(Unit* & result, Check & check) : i_object(result),i_check(check) {}
+ UnitLastSearcher(WorldObject const* searcher, Unit* & result, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {}
void Visit(CreatureMapType &m);
void Visit(PlayerMapType &m);
@@ -356,10 +379,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL UnitListSearcher
{
+ uint32 i_phaseMask;
std::list<Unit*> &i_objects;
Check& i_check;
- UnitListSearcher(std::list<Unit*> &objects, Check & check) : i_objects(objects),i_check(check) {}
+ UnitListSearcher(WorldObject const* searcher, std::list<Unit*> &objects, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {}
void Visit(PlayerMapType &m);
void Visit(CreatureMapType &m);
@@ -372,10 +397,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL CreatureSearcher
{
+ uint32 i_phaseMask;
Creature* &i_object;
Check & i_check;
- CreatureSearcher(Creature* & result, Check & check) : i_object(result),i_check(check) {}
+ CreatureSearcher(WorldObject const* searcher, Creature* & result, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {}
void Visit(CreatureMapType &m);
@@ -386,10 +413,12 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL CreatureLastSearcher
{
+ uint32 i_phaseMask;
Creature* &i_object;
Check & i_check;
- CreatureLastSearcher(Creature* & result, Check & check) : i_object(result),i_check(check) {}
+ CreatureLastSearcher(WorldObject const* searcher, Creature* & result, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {}
void Visit(CreatureMapType &m);
@@ -399,25 +428,48 @@ namespace Trinity
template<class Check>
struct TRINITY_DLL_DECL CreatureListSearcher
{
+ uint32 i_phaseMask;
std::list<Creature*> &i_objects;
Check& i_check;
- CreatureListSearcher(std::list<Creature*> &objects, Check & check) : i_objects(objects),i_check(check) {}
+ CreatureListSearcher(WorldObject const* searcher, std::list<Creature*> &objects, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {}
void Visit(CreatureMapType &m);
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
};
+ template<class Do>
+ struct MANGOS_DLL_DECL CreatureWorker
+ {
+ uint32 i_phaseMask;
+ Do& i_do;
+
+ CreatureWorker(WorldObject const* searcher, Do& _do)
+ : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {}
+
+ void Visit(CreatureMapType &m)
+ {
+ for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ i_do(itr->getSource());
+ }
+
+ template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
+ };
+
// Player searchers
template<class Check>
struct TRINITY_DLL_DECL PlayerSearcher
{
+ uint32 i_phaseMask;
Player* &i_object;
Check & i_check;
- PlayerSearcher(Player* & result, Check & check) : i_object(result),i_check(check) {}
+ PlayerSearcher(WorldObject const* searcher, Player* & result, Check & check)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {}
void Visit(PlayerMapType &m);
@@ -427,14 +479,37 @@ namespace Trinity
template<class Do>
struct TRINITY_DLL_DECL PlayerWorker
{
+ uint32 i_phaseMask;
+ Do& i_do;
+
+ PlayerWorker(WorldObject const* searcher, Do& _do)
+ : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {}
+
+ void Visit(PlayerMapType &m)
+ {
+ for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ i_do(itr->getSource());
+ }
+
+ template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
+ };
+
+ template<class Do>
+ struct TRINITY_DLL_DECL PlayerDistWorker
+ {
+ WorldObject const* i_searcher;
+ float i_dist;
Do& i_do;
- explicit PlayerWorker(Do& _do) : i_do(_do) {}
+ PlayerDistWorker(WorldObject const* searcher, float _dist, Do& _do)
+ : i_searcher(searcher), i_dist(_dist), i_do(_do) {}
void Visit(PlayerMapType &m)
{
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- i_do(itr->getSource());
+ if (itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->IsWithinDist(i_searcher,i_dist))
+ i_do(itr->getSource());
}
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
@@ -443,6 +518,53 @@ namespace Trinity
// CHECKS && DO classes
// WorldObject check classes
+ class RaiseDeadObjectCheck
+ {
+ public:
+ RaiseDeadObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {}
+ bool operator()(Creature* u)
+ {
+ if (i_funit->GetTypeId()!=TYPEID_PLAYER || !((Player*)i_funit)->isHonorOrXPTarget(u) ||
+ u->getDeathState() != CORPSE || u->isDeadByDefault() || u->isInFlight() ||
+ ( u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1)) )==0 ||
+ (u->GetDisplayId() != u->GetNativeDisplayId()))
+ return false;
+
+ return i_funit->IsWithinDistInMap(u, i_range);
+ }
+ template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
+ private:
+ Unit* const i_funit;
+ float i_range;
+ };
+
+ class ExplodeCorpseObjectCheck
+ {
+ public:
+ ExplodeCorpseObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {}
+ bool operator()(Player* u)
+ {
+ if (u->getDeathState()!=CORPSE || u->isInFlight() ||
+ u->HasAuraType(SPELL_AURA_GHOST) || (u->GetDisplayId() != u->GetNativeDisplayId()))
+ return false;
+
+ return i_funit->IsWithinDistInMap(u, i_range);
+ }
+ bool operator()(Creature* u)
+ {
+ if (u->getDeathState()!=CORPSE || u->isInFlight() || u->isDeadByDefault() ||
+ (u->GetDisplayId() != u->GetNativeDisplayId()) ||
+ (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL)!=0)
+ return false;
+
+ return i_funit->IsWithinDistInMap(u, i_range);
+ }
+ template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
+ private:
+ Unit* const i_funit;
+ float i_range;
+ };
+
class CannibalizeObjectCheck
{
public:
@@ -452,22 +574,16 @@ namespace Trinity
if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() )
return false;
- if(i_funit->IsWithinDistInMap(u, i_range) )
- return true;
-
- return false;
+ return i_funit->IsWithinDistInMap(u, i_range);
}
bool operator()(Corpse* u);
bool operator()(Creature* u)
{
- if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() ||
+ if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() ||
(u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD)==0)
return false;
- if(i_funit->IsWithinDistInMap(u, i_range) )
- return true;
-
- return false;
+ return i_funit->IsWithinDistInMap(u, i_range);
}
template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
private:
@@ -533,6 +649,28 @@ namespace Trinity
NearestGameObjectFishingHole(NearestGameObjectFishingHole const&);
};
+ class NearestGameObjectCheck
+ {
+ public:
+ NearestGameObjectCheck(WorldObject const& obj) : i_obj(obj), i_range(999) {}
+ bool operator()(GameObject* go)
+ {
+ if(i_obj.IsWithinDistInMap(go, i_range))
+ {
+ i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check
+ return true;
+ }
+ return false;
+ }
+ float GetLastRange() const { return i_range; }
+ private:
+ WorldObject const& i_obj;
+ float i_range;
+
+ // prevent clone this object
+ NearestGameObjectCheck(NearestGameObjectCheck const&);
+ };
+
// Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO)
class NearestGameObjectEntryInObjectRangeCheck
{
@@ -572,6 +710,62 @@ namespace Trinity
// Unit checks
+ class MostHPMissingInRange
+ {
+ public:
+ MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) {}
+ bool operator()(Unit* u)
+ {
+ if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp)
+ {
+ i_hp = u->GetMaxHealth() - u->GetHealth();
+ return true;
+ }
+ return false;
+ }
+ private:
+ Unit const* i_obj;
+ float i_range;
+ uint32 i_hp;
+ };
+
+ class FriendlyCCedInRange
+ {
+ public:
+ FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) {}
+ bool operator()(Unit* u)
+ {
+ if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
+ (u->isFeared() || u->isCharmed() || u->isFrozen() || u->hasUnitState(UNIT_STAT_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED)))
+ {
+ return true;
+ }
+ return false;
+ }
+ private:
+ Unit const* i_obj;
+ float i_range;
+ };
+
+ class FriendlyMissingBuffInRange
+ {
+ public:
+ FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {}
+ bool operator()(Unit* u)
+ {
+ if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
+ !(u->HasAura(i_spell)))
+ {
+ return true;
+ }
+ return false;
+ }
+ private:
+ Unit const* i_obj;
+ float i_range;
+ uint32 i_spell;
+ };
+
class AnyUnfriendlyUnitInObjectRangeCheck
{
public:
@@ -760,31 +954,6 @@ namespace Trinity
NearestHostileUnitInAttackDistanceCheck(NearestHostileUnitInAttackDistanceCheck const&);
};
- class NearestAssistCreatureInCreatureRangeCheck
- {
- public:
- NearestAssistCreatureInCreatureRangeCheck(Creature* obj,Unit* enemy, float range)
- : i_obj(obj), i_enemy(enemy), i_range(range) {}
-
- bool operator()(Creature* u)
- {
- if(u->getFaction() == i_obj->getFaction() && !u->isInCombat() && !u->GetCharmerOrOwnerGUID() && u->IsHostileTo(i_enemy) && u->isAlive()&& i_obj->IsWithinDistInMap(u, i_range) && i_obj->IsWithinLOSInMap(u))
- {
- i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check
- return true;
- }
- return false;
- }
- float GetLastRange() const { return i_range; }
- private:
- Creature* const i_obj;
- Unit* const i_enemy;
- float i_range;
-
- // prevent clone this object
- NearestAssistCreatureInCreatureRangeCheck(NearestAssistCreatureInCreatureRangeCheck const&);
- };
-
class AnyAssistCreatureInRangeCheck
{
public:
@@ -816,6 +985,38 @@ namespace Trinity
float i_range;
};
+ class NearestAssistCreatureInCreatureRangeCheck
+ {
+ public:
+ NearestAssistCreatureInCreatureRangeCheck(Creature* obj, Unit* enemy, float range)
+ : i_obj(obj), i_enemy(enemy), i_range(range) {}
+
+ bool operator()(Creature* u)
+ {
+ if(u == i_obj)
+ return false;
+ if(!u->CanAssistTo(i_obj,i_enemy))
+ return false;
+
+ if(!i_obj->IsWithinDistInMap(u, i_range))
+ return false;
+
+ if(!i_obj->IsWithinLOSInMap(u))
+ return false;
+
+ i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check
+ return true;
+ }
+ float GetLastRange() const { return i_range; }
+ private:
+ Creature* const i_obj;
+ Unit* const i_enemy;
+ float i_range;
+
+ // prevent clone this object
+ NearestAssistCreatureInCreatureRangeCheck(NearestAssistCreatureInCreatureRangeCheck const&);
+ };
+
// Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature)
class NearestCreatureEntryWithLiveStateInObjectRangeCheck
{
@@ -859,63 +1060,6 @@ namespace Trinity
float i_range;
};
- // Searchers used by ScriptedAI
- class MostHPMissingInRange
- {
- public:
- MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) {}
- bool operator()(Unit* u)
- {
- if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp)
- {
- i_hp = u->GetMaxHealth() - u->GetHealth();
- return true;
- }
- return false;
- }
- private:
- Unit const* i_obj;
- float i_range;
- uint32 i_hp;
- };
-
- class FriendlyCCedInRange
- {
- public:
- FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) {}
- bool operator()(Unit* u)
- {
- if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
- (u->isFeared() || u->isCharmed() || u->isFrozen() || u->hasUnitState(UNIT_STAT_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED)))
- {
- return true;
- }
- return false;
- }
- private:
- Unit const* i_obj;
- float i_range;
- };
-
- class FriendlyMissingBuffInRange
- {
- public:
- FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {}
- bool operator()(Unit* u)
- {
- if(u->isAlive() && u->isInCombat() && /*!i_obj->IsHostileTo(u)*/ i_obj->IsFriendlyTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
- !(u->HasAura(i_spell, 0) || u->HasAura(i_spell, 1) || u->HasAura(i_spell, 2)))
- {
- return true;
- }
- return false;
- }
- private:
- Unit const* i_obj;
- float i_range;
- uint32 i_spell;
- };
-
class AllFriendlyCreaturesInGrid
{
public:
@@ -946,6 +1090,18 @@ namespace Trinity
uint32 entry;
};
+ class GameObjectInRangeCheck
+ {
+ public:
+ GameObjectInRangeCheck(float _x, float _y, float _z, float _range) : x(_x), y(_y), z(_z), range(_range) {}
+ bool operator() (GameObject* go)
+ {
+ return go->IsInRange(x, y, z, range);
+ }
+ private:
+ float x, y, z, range;
+ };
+
class AllCreaturesOfEntryInRange
{
public:
@@ -963,6 +1119,49 @@ namespace Trinity
float range;
};
+ // Player checks and do
+
+ // Prepare using Builder localized packets with caching and send to player
+ template<class Builder>
+ class LocalizedPacketDo
+ {
+ public:
+ explicit LocalizedPacketDo(Builder& builder) : i_builder(builder) {}
+
+ ~LocalizedPacketDo()
+ {
+ for(size_t i = 0; i < i_data_cache.size(); ++i)
+ delete i_data_cache[i];
+ }
+ void operator()( Player* p );
+
+ private:
+ Builder& i_builder;
+ std::vector<WorldPacket*> i_data_cache; // 0 = default, i => i-1 locale index
+ };
+
+ // Prepare using Builder localized packets with caching and send to player
+ template<class Builder>
+ class LocalizedPacketListDo
+ {
+ public:
+ typedef std::vector<WorldPacket*> WorldPacketList;
+ explicit LocalizedPacketListDo(Builder& builder) : i_builder(builder) {}
+
+ ~LocalizedPacketListDo()
+ {
+ for(size_t i = 0; i < i_data_cache.size(); ++i)
+ for(int j = 0; j < i_data_cache[i].size(); ++j)
+ delete i_data_cache[i][j];
+ }
+ void operator()( Player* p );
+
+ private:
+ Builder& i_builder;
+ std::vector<WorldPacketList> i_data_cache;
+ // 0 = default, i => i-1 locale index
+ };
+
#ifndef WIN32
template<> inline void PlayerRelocationNotifier::Visit<Creature>(CreatureMapType &);
template<> inline void PlayerRelocationNotifier::Visit<Player>(PlayerMapType &);
diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h
index 70f77b95ae8..d4413b9f777 100644
--- a/src/game/GridNotifiersImpl.h
+++ b/src/game/GridNotifiersImpl.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -128,7 +128,7 @@ Trinity::CreatureRelocationNotifier::Visit(PlayerMapType &m)
continue;
iter->getSource()->UpdateVisibilityOf(&i_creature);
-
+
PlayerCreatureRelocationWorker(iter->getSource(), &i_creature);
}
}
@@ -144,7 +144,7 @@ Trinity::CreatureRelocationNotifier::Visit(CreatureMapType &m)
{
if(iter->getSource()->m_Notified)
continue;
-
+
if(!iter->getSource()->isAlive())
continue;
@@ -178,8 +178,11 @@ inline void Trinity::DynamicObjectUpdater::VisitHelper(Unit* target)
if (i_dynobject.IsAffecting(target))
return;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_dynobject.GetSpellId());
uint32 eff_index = i_dynobject.GetEffIndex();
+ if(target->HasAuraEffect(i_dynobject.GetSpellId(), eff_index, i_check->GetGUID()))
+ return;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_dynobject.GetSpellId());
if(spellInfo->EffectImplicitTargetB[eff_index] == TARGET_DEST_DYNOBJ_ALLY
|| spellInfo->EffectImplicitTargetB[eff_index] == TARGET_UNIT_AREA_ALLY_DST)
{
@@ -202,11 +205,12 @@ inline void Trinity::DynamicObjectUpdater::VisitHelper(Unit* target)
}
// Check target immune to spell or aura
- if (target->IsImmunedToSpell(spellInfo) || target->IsImmunedToSpellEffect(spellInfo->Effect[eff_index], spellInfo->EffectMechanic[eff_index]))
+ if (target->IsImmunedToSpell(spellInfo) || target->IsImmunedToSpellEffect(spellInfo, eff_index))
return;
// Apply PersistentAreaAura on target
- PersistentAreaAura* Aur = new PersistentAreaAura(spellInfo, eff_index, NULL, target, i_dynobject.GetCaster());
- target->AddAura(Aur);
+ if(Aura *aur = target->AddAuraEffect(spellInfo, eff_index, i_dynobject.GetCaster()))
+ aur->SetAuraDuration(i_dynobject.GetDuration());
+
i_dynobject.AddAffected(target);
}
@@ -239,7 +243,10 @@ void Trinity::WorldObjectSearcher<Check>::Visit(GameObjectMapType &m)
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
- if(i_check(itr->getSource()))
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (i_check(itr->getSource()))
{
i_object = itr->getSource();
return;
@@ -256,6 +263,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(PlayerMapType &m)
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -273,6 +283,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(CreatureMapType &m)
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -290,6 +303,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(CorpseMapType &m)
for(CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -307,6 +323,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(DynamicObjectMapType &m)
for(DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -319,40 +338,45 @@ template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m)
{
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if(i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(CreatureMapType &m)
{
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if(i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(CorpseMapType &m)
{
for(CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if(i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(GameObjectMapType &m)
{
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if(i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType &m)
{
for(DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if(i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
// Gameobject searchers
@@ -366,6 +390,9 @@ void Trinity::GameObjectSearcher<Check>::Visit(GameObjectMapType &m)
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -379,6 +406,9 @@ void Trinity::GameObjectLastSearcher<Check>::Visit(GameObjectMapType &m)
{
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
i_object = itr->getSource();
}
@@ -388,8 +418,9 @@ template<class Check>
void Trinity::GameObjectListSearcher<Check>::Visit(GameObjectMapType &m)
{
for(GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if(i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
// Unit searchers
@@ -403,6 +434,9 @@ void Trinity::UnitSearcher<Check>::Visit(CreatureMapType &m)
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -420,6 +454,9 @@ void Trinity::UnitSearcher<Check>::Visit(PlayerMapType &m)
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -433,6 +470,9 @@ void Trinity::UnitLastSearcher<Check>::Visit(CreatureMapType &m)
{
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
i_object = itr->getSource();
}
@@ -443,6 +483,9 @@ void Trinity::UnitLastSearcher<Check>::Visit(PlayerMapType &m)
{
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
i_object = itr->getSource();
}
@@ -452,16 +495,18 @@ template<class Check>
void Trinity::UnitListSearcher<Check>::Visit(PlayerMapType &m)
{
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if(i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
template<class Check>
void Trinity::UnitListSearcher<Check>::Visit(CreatureMapType &m)
{
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if(i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
// Creature searchers
@@ -475,6 +520,9 @@ void Trinity::CreatureSearcher<Check>::Visit(CreatureMapType &m)
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -488,6 +536,9 @@ void Trinity::CreatureLastSearcher<Check>::Visit(CreatureMapType &m)
{
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
i_object = itr->getSource();
}
@@ -497,8 +548,9 @@ template<class Check>
void Trinity::CreatureListSearcher<Check>::Visit(CreatureMapType &m)
{
for(CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
- if(i_check(itr->getSource()))
- i_objects.push_back(itr->getSource());
+ if(itr->getSource()->InSamePhase(i_phaseMask))
+ if( i_check(itr->getSource()))
+ i_objects.push_back(itr->getSource());
}
template<class Check>
@@ -510,6 +562,9 @@ void Trinity::PlayerSearcher<Check>::Visit(PlayerMapType &m)
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
{
+ if(!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
if(i_check(itr->getSource()))
{
i_object = itr->getSource();
@@ -518,5 +573,53 @@ void Trinity::PlayerSearcher<Check>::Visit(PlayerMapType &m)
}
}
-#endif // TRINITY_GRIDNOTIFIERSIMPL_H
+template<class Builder>
+void MaNGOS::LocalizedPacketDo<Builder>::operator()( Player* p )
+{
+ int32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
+ uint32 cache_idx = loc_idx+1;
+ WorldPacket* data;
+
+ // create if not cached yet
+ if(i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx])
+ {
+ if(i_data_cache.size() < cache_idx+1)
+ i_data_cache.resize(cache_idx+1);
+
+ data = new WorldPacket(SMSG_MESSAGECHAT, 200);
+
+ i_builder(*data,loc_idx);
+
+ i_data_cache[cache_idx] = data;
+ }
+ else
+ data = i_data_cache[cache_idx];
+
+ p->SendDirectMessage(data);
+}
+
+template<class Builder>
+void MaNGOS::LocalizedPacketListDo<Builder>::operator()( Player* p )
+{
+ int32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
+ uint32 cache_idx = loc_idx+1;
+ WorldPacketList* data_list;
+
+ // create if not cached yet
+ if(i_data_cache.size() < cache_idx+1 || i_data_cache[cache_idx].empty())
+ {
+ if(i_data_cache.size() < cache_idx+1)
+ i_data_cache.resize(cache_idx+1);
+
+ data_list = &i_data_cache[cache_idx];
+
+ i_builder(*data_list,loc_idx);
+ }
+ else
+ data_list = &i_data_cache[cache_idx];
+
+ for(size_t i = 0; i < data_list->size(); ++i)
+ p->SendDirectMessage((*data_list)[i]);
+}
+#endif // MANGOS_GRIDNOTIFIERSIMPL_H
diff --git a/src/game/GridStates.h b/src/game/GridStates.h
index 167f30b8371..12d64ad58ca 100644
--- a/src/game/GridStates.h
+++ b/src/game/GridStates.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Group.cpp b/src/game/Group.cpp
index 535a3d4392c..d2c17680e52 100644
--- a/src/game/Group.cpp
+++ b/src/game/Group.cpp
@@ -46,7 +46,7 @@ Group::Group()
m_lootThreshold = ITEM_QUALITY_UNCOMMON;
m_subGroupsCounts = NULL;
- for(int i=0; i<TARGETICONCOUNT; i++)
+ for (int i=0; i<TARGETICONCOUNT; ++i)
m_targetIcons[i] = 0;
}
@@ -71,9 +71,9 @@ Group::~Group()
// it is undefined whether objectmgr (which stores the groups) or instancesavemgr
// will be unloaded first so we must be prepared for both cases
// this may unload some instance saves
- for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
- for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
- itr->second.save->RemoveGroup(this);
+ for(uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i)
+ for(BoundInstancesMap::iterator itr2 = m_boundInstances[i].begin(); itr2 != m_boundInstances[i].end(); ++itr2)
+ itr2->second.save->RemoveGroup(this);
// Sub group counters clean up
if (m_subGroupsCounts)
@@ -156,7 +156,7 @@ bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool
m_looterGuid = MAKE_NEW_GUID((*result)[3].GetUInt32(), 0, HIGHGUID_PLAYER);
m_lootThreshold = (ItemQualities)(*result)[4].GetUInt16();
- for(int i=0; i<TARGETICONCOUNT; i++)
+ for(int i=0; i<TARGETICONCOUNT; ++i)
m_targetIcons[i] = (*result)[5+i].GetUInt64();
if(!external) delete result;
@@ -203,13 +203,24 @@ void Group::ConvertToRaid()
_initRaidSubGroupsCounter();
- if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
+ if(!isBGGroup())
+ CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
SendUpdate();
+
+ // update quest related GO states (quest activity dependent from raid membership)
+ for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
+ if(Player* player = objmgr.GetPlayer(citr->guid))
+ player->UpdateForQuestWorldObjects();
}
bool Group::AddInvite(Player *player)
{
- if(!player || player->GetGroupInvite() || player->GetGroup())
+ if( !player || player->GetGroupInvite() )
+ return false;
+ Group* group = player->GetGroup();
+ if( group && group->isBGGroup() )
+ group = player->GetOriginalGroup();
+ if( group )
return false;
RemoveInvite(player);
@@ -290,6 +301,10 @@ bool Group::AddMember(const uint64 &guid, const char* name)
}
player->SetGroupUpdateFlag(GROUP_UPDATE_FULL);
UpdatePlayerOutOfRange(player);
+
+ // quest related GO state dependent from raid memebership
+ if(isRaidGroup())
+ player->UpdateForQuestWorldObjects();
}
return true;
@@ -306,6 +321,10 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
if(Player *player = objmgr.GetPlayer( guid ))
{
+ // quest related GO state dependent from raid membership
+ if(isRaidGroup())
+ player->UpdateForQuestWorldObjects();
+
WorldPacket data;
if(method == 1)
@@ -314,9 +333,17 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
player->GetSession()->SendPacket( &data );
}
- data.Initialize(SMSG_GROUP_LIST, 24);
- data << uint64(0) << uint64(0) << uint64(0);
- player->GetSession()->SendPacket(&data);
+ //we already removed player from group and in player->GetGroup() is his original group!
+ if( Group* group = player->GetGroup() )
+ {
+ group->SendUpdate();
+ }
+ else
+ {
+ data.Initialize(SMSG_GROUP_LIST, 24);
+ data << uint64(0) << uint64(0) << uint64(0);
+ player->GetSession()->SendPacket(&data);
+ }
_homebindIfInstance(player);
}
@@ -325,7 +352,7 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
{
WorldPacket data(SMSG_GROUP_SET_LEADER, (m_memberSlots.front().name.size()+1));
data << m_memberSlots.front().name;
- BroadcastPacket(&data);
+ BroadcastPacket(&data, true);
}
SendUpdate();
@@ -348,7 +375,7 @@ void Group::ChangeLeader(const uint64 &guid)
WorldPacket data(SMSG_GROUP_SET_LEADER, slot->name.size()+1);
data << slot->name;
- BroadcastPacket(&data);
+ BroadcastPacket(&data, true);
SendUpdate();
}
@@ -362,7 +389,22 @@ void Group::Disband(bool hideDestroy)
if(!player)
continue;
- player->SetGroup(NULL);
+ //we cannot call _removeMember because it would invalidate member iterator
+ //if we are removing player from battleground raid
+ if( isBGGroup() )
+ player->RemoveFromBattleGroundRaid();
+ else
+ {
+ //we can remove player who is in battleground from his original group
+ if( player->GetOriginalGroup() == this )
+ player->SetOriginalGroup(NULL);
+ else
+ player->SetGroup(NULL);
+ }
+
+ // quest related GO state dependent from raid membership
+ if(isRaidGroup())
+ player->UpdateForQuestWorldObjects();
if(!player->GetSession())
continue;
@@ -374,9 +416,17 @@ void Group::Disband(bool hideDestroy)
player->GetSession()->SendPacket(&data);
}
- data.Initialize(SMSG_GROUP_LIST, 24);
- data << uint64(0) << uint64(0) << uint64(0);
- player->GetSession()->SendPacket(&data);
+ //we already removed player from group and in player->GetGroup() is his original group, send update
+ if( Group* group = player->GetGroup() )
+ {
+ group->SendUpdate();
+ }
+ else
+ {
+ data.Initialize(SMSG_GROUP_LIST, 24);
+ data << uint64(0) << uint64(0) << uint64(0);
+ player->GetSession()->SendPacket(&data);
+ }
_homebindIfInstance(player);
}
@@ -521,7 +571,7 @@ void Group::GroupLoot(const uint64& playerGUID, Loot *loot, Creature *creature)
continue;
if ( i->AllowedForPlayer(member) )
{
- if (member->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if (member->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
r->playerVote[member->GetGUID()] = NOT_EMITED_YET;
++r->totalPlayersRolling;
@@ -571,7 +621,7 @@ void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *crea
if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll) )
{
- if (playerToRoll->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if (playerToRoll->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
++r->totalPlayersRolling;
@@ -619,7 +669,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat
if (!looter->IsInWorld())
continue;
- if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
data << looter->GetGUID();
++real_count;
@@ -631,7 +681,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *looter = itr->getSource();
- if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
looter->GetSession()->SendPacket(&data);
}
}
@@ -730,6 +780,8 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
if(player && player->GetSession())
{
+ player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT, roll->itemid, maxresul);
+
ItemPosCountVec dest;
LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count );
@@ -775,6 +827,8 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
if(player && player->GetSession())
{
+ player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT, roll->itemid, maxresul);
+
ItemPosCountVec dest;
LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count );
@@ -810,7 +864,7 @@ void Group::SetTargetIcon(uint8 id, uint64 guid)
// clean other icons
if( guid != 0 )
- for(int i=0; i<TARGETICONCOUNT; i++)
+ for(int i=0; i<TARGETICONCOUNT; ++i)
if( m_targetIcons[i] == guid )
SetTargetIcon(i, 0);
@@ -820,7 +874,7 @@ void Group::SetTargetIcon(uint8 id, uint64 guid)
data << (uint8)0;
data << id;
data << guid;
- BroadcastPacket(&data);
+ BroadcastPacket(&data, true);
}
void Group::GetDataForXPAtKill(Unit const* victim, uint32& count,uint32& sum_level, Player* & member_with_max_level, Player* & not_gray_member_with_max_level)
@@ -836,13 +890,10 @@ void Group::GetDataForXPAtKill(Unit const* victim, uint32& count,uint32& sum_lev
++count;
sum_level += member->getLevel();
- // store maximum member level
if(!member_with_max_level || member_with_max_level->getLevel() < member->getLevel())
member_with_max_level = member;
- uint32 gray_level = Trinity::XP::GetGrayLevel(member->getLevel());
- // if the victim is higher level than the gray level of the currently examined group member,
- // then set not_gray_member_with_max_level if needed.
+ uint32 gray_level = MaNGOS::XP::GetGrayLevel(member->getLevel());
if( victim->getLevel() > gray_level && (!not_gray_member_with_max_level
|| not_gray_member_with_max_level->getLevel() < member->getLevel()))
not_gray_member_with_max_level = member;
@@ -857,7 +908,7 @@ void Group::SendTargetIconList(WorldSession *session)
WorldPacket data(MSG_RAID_TARGET_UPDATE, (1+TARGETICONCOUNT*9));
data << (uint8)1;
- for(int i=0; i<TARGETICONCOUNT; i++)
+ for(int i=0; i<TARGETICONCOUNT; ++i)
{
if(m_targetIcons[i] == 0)
continue;
@@ -876,7 +927,7 @@ void Group::SendUpdate()
for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
{
player = objmgr.GetPlayer(citr->guid);
- if(!player || !player->GetSession())
+ if(!player || !player->GetSession() || player->GetGroup() != this )
continue;
// guess size
WorldPacket data(SMSG_GROUP_LIST, (1+1+1+1+8+4+GetMembersCount()*20));
@@ -890,11 +941,14 @@ void Group::SendUpdate()
{
if(citr->guid == citr2->guid)
continue;
+ Player* member = objmgr.GetPlayer(citr2->guid);
+ uint8 onlineState = (member) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE;
+ onlineState = onlineState | ((isBGGroup()) ? MEMBER_STATUS_PVP : 0);
data << citr2->name;
data << (uint64)citr2->guid;
// online-state
- data << (uint8)(objmgr.GetPlayer(citr2->guid) ? 1 : 0);
+ data << (uint8)(onlineState);
data << (uint8)(citr2->group); // groupid
data << (uint8)(citr2->assistant?0x01:0); // 0x2 main assist, 0x4 main tank
}
@@ -906,7 +960,6 @@ void Group::SendUpdate()
data << (uint64)m_looterGuid; // looter guid
data << (uint8)m_lootThreshold; // loot threshold
data << (uint8)m_difficulty; // Heroic Mod Group
-
}
player->GetSession()->SendPacket( &data );
}
@@ -929,12 +982,12 @@ void Group::UpdatePlayerOutOfRange(Player* pPlayer)
}
}
-void Group::BroadcastPacket(WorldPacket *packet, int group, uint64 ignore)
+void Group::BroadcastPacket(WorldPacket *packet, bool ignorePlayersInBGRaid, int group, uint64 ignore)
{
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *pl = itr->getSource();
- if(!pl || (ignore != 0 && pl->GetGUID() == ignore))
+ if(!pl || (ignore != 0 && pl->GetGUID() == ignore) || (ignorePlayersInBGRaid && pl->GetGroup() != this) )
continue;
if (pl->GetSession() && (group==-1 || itr->getSubGroup()==group))
@@ -985,7 +1038,7 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant)
}
// We are raid group and no one slot is free
if (!groupFound)
- return false;
+ return false;
}
return _addMember(guid, name, isAssistant, groupid);
@@ -1013,7 +1066,15 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u
if(player)
{
player->SetGroupInvite(NULL);
- player->SetGroup(this, group);
+ //if player is in group and he is being added to BG raid group, then call SetBattleGroundRaid()
+ if( player->GetGroup() && isBGGroup() )
+ player->SetBattleGroundRaid(this, group);
+ //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup()
+ else if ( player->GetGroup() )
+ player->SetOriginalGroup(this, group);
+ //if player is not in group, then call set group
+ else
+ player->SetGroup(this, group);
// if the same group invites the player back, cancel the homebind timer
InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDifficulty());
if(bind && bind->save->GetInstanceId() == player->GetInstanceId())
@@ -1022,7 +1083,7 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u
if(!isRaidGroup()) // reset targetIcons for non-raid-groups
{
- for(int i=0; i<TARGETICONCOUNT; i++)
+ for(int i=0; i<TARGETICONCOUNT; ++i)
m_targetIcons[i] = 0;
}
@@ -1040,7 +1101,17 @@ bool Group::_removeMember(const uint64 &guid)
Player *player = objmgr.GetPlayer(guid);
if (player)
{
- player->SetGroup(NULL);
+ //if we are removing player from battleground raid
+ if( isBGGroup() )
+ player->RemoveFromBattleGroundRaid();
+ else
+ {
+ //we can remove player who is in battleground from his original group
+ if( player->GetOriginalGroup() == this )
+ player->SetOriginalGroup(NULL);
+ else
+ player->SetGroup(NULL);
+ }
}
_removeRolls(guid);
@@ -1091,7 +1162,7 @@ void Group::_setLeader(const uint64 &guid)
Player *player = objmgr.GetPlayer(slot->guid);
if(player)
{
- for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+ for(uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i)
{
for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();)
{
@@ -1232,12 +1303,17 @@ void Group::ChangeMembersGroup(Player *player, const uint8 &group)
return;
if(_setMembersGroup(player->GetGUID(), group))
{
- uint8 prevSubGroup;
- prevSubGroup = player->GetSubGroup();
-
+ uint8 prevSubGroup = player->GetSubGroup();
+ if( player->GetGroup() == this )
+ player->GetGroupRef().setSubGroup(group);
+ //if player is in BG raid, it is possible that he is also in normal raid - and that normal raid is stored in m_originalGroup reference
+ else
+ {
+ prevSubGroup = player->GetOriginalSubGroup();
+ player->GetOriginalGroupRef().setSubGroup(group);
+ }
SubGroupCounterDecrease(prevSubGroup);
- player->GetGroupRef().setSubGroup(group);
SendUpdate();
}
}
@@ -1262,7 +1338,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
{
// not update if only update if need and ok
Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid);
- if(looter && looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if(looter && looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
return;
}
++guid_itr;
@@ -1275,7 +1351,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
{
if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
{
- if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
bool refresh = pl->GetLootGUID()==creature->GetGUID();
@@ -1296,7 +1372,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
{
if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
{
- if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
bool refresh = pl->GetLootGUID()==creature->GetGUID();
@@ -1315,7 +1391,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
SendUpdate();
}
-uint32 Group::CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot)
+uint32 Group::CanJoinBattleGroundQueue(BattleGroundTypeId bgTypeId, BattleGroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot)
{
// check for min / max count
uint32 memberscount = GetMembersCount();
@@ -1330,7 +1406,7 @@ uint32 Group::CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint
if(!reference)
return BG_JOIN_ERR_OFFLINE_MEMBER;
- uint32 bgQueueId = reference->GetBattleGroundQueueIdFromLevel();
+ BGQueueIdBasedOnLevel queue_id = reference->GetBattleGroundQueueIdFromLevel(bgTypeId);
uint32 arenaTeamId = reference->GetArenaTeamId(arenaSlot);
uint32 team = reference->GetTeam();
@@ -1345,13 +1421,13 @@ uint32 Group::CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint
if(member->GetTeam() != team)
return BG_JOIN_ERR_MIXED_FACTION;
// not in the same battleground level braket, don't let join
- if(member->GetBattleGroundQueueIdFromLevel() != bgQueueId)
+ if(member->GetBattleGroundQueueIdFromLevel(bgTypeId) != queue_id)
return BG_JOIN_ERR_MIXED_LEVELS;
// don't let join rated matches if the arena team id doesn't match
if(isRated && member->GetArenaTeamId(arenaSlot) != arenaTeamId)
return BG_JOIN_ERR_MIXED_ARENATEAM;
// don't let join if someone from the group is already in that bg queue
- if(member->InBattleGroundQueueForBattleGroundQueueType(bgQueueType))
+ if(member->InBattleGroundQueueForBattleGroundQueueType(bgQueueTypeId))
return BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE;
// check for deserter debuff in case not arena queue
if(bgTypeId != BATTLEGROUND_AA && !member->CanJoinToBattleground())
@@ -1480,7 +1556,7 @@ InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, boo
InstanceGroupBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()];
if(bind.save)
{
- // when a boss is killed or when copying the player's binds to the group
+ // when a boss is killed or when copying the players's binds to the group
if(permanent != bind.perm || save != bind.save)
if(!load) CharacterDatabase.PExecute("UPDATE group_instance SET instance = '%u', permanent = '%u' WHERE leaderGuid = '%u' AND instance = '%u'", save->GetInstanceId(), permanent, GUID_LOPART(GetLeaderGUID()), bind.save->GetInstanceId());
}
diff --git a/src/game/Group.h b/src/game/Group.h
index 76543dd4873..d09ef616897 100644
--- a/src/game/Group.h
+++ b/src/game/Group.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include "GroupReference.h"
#include "GroupRefManager.h"
+#include "BattleGround.h"
#include "LootMgr.h"
#include <map>
@@ -66,24 +67,25 @@ enum GroupUpdateFlags
{
GROUP_UPDATE_FLAG_NONE = 0x00000000, // nothing
GROUP_UPDATE_FLAG_STATUS = 0x00000001, // uint16, flags
- GROUP_UPDATE_FLAG_CUR_HP = 0x00000002, // uint16
- GROUP_UPDATE_FLAG_MAX_HP = 0x00000004, // uint16
+ GROUP_UPDATE_FLAG_CUR_HP = 0x00000002, // uint32
+ GROUP_UPDATE_FLAG_MAX_HP = 0x00000004, // uint32
GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000008, // uint8
GROUP_UPDATE_FLAG_CUR_POWER = 0x00000010, // uint16
GROUP_UPDATE_FLAG_MAX_POWER = 0x00000020, // uint16
GROUP_UPDATE_FLAG_LEVEL = 0x00000040, // uint16
GROUP_UPDATE_FLAG_ZONE = 0x00000080, // uint16
GROUP_UPDATE_FLAG_POSITION = 0x00000100, // uint16, uint16
- GROUP_UPDATE_FLAG_AURAS = 0x00000200, // uint64 mask, for each bit set uint16 spellid + uint8 unk
+ GROUP_UPDATE_FLAG_AURAS = 0x00000200, // uint64 mask, for each bit set uint32 spellid + uint8 unk
GROUP_UPDATE_FLAG_PET_GUID = 0x00000400, // uint64 pet guid
GROUP_UPDATE_FLAG_PET_NAME = 0x00000800, // pet name, NULL terminated string
GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00001000, // uint16, model id
- GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00002000, // uint16 pet cur health
- GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00004000, // uint16 pet max health
+ GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00002000, // uint32 pet cur health
+ GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00004000, // uint32 pet max health
GROUP_UPDATE_FLAG_PET_POWER_TYPE = 0x00008000, // uint8 pet power type
GROUP_UPDATE_FLAG_PET_CUR_POWER = 0x00010000, // uint16 pet cur power
GROUP_UPDATE_FLAG_PET_MAX_POWER = 0x00020000, // uint16 pet max power
- GROUP_UPDATE_FLAG_PET_AURAS = 0x00040000, // uint64 mask, for each bit set uint16 spellid + uint8 unk, pet auras...
+ GROUP_UPDATE_FLAG_PET_AURAS = 0x00040000, // uint64 mask, for each bit set uint32 spellid + uint8 unk, pet auras...
+ GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00080000, // uint32 vehicle_seat_id (index from VehicleSeat.dbc)
GROUP_UPDATE_PET = 0x0007FC00, // all pet flags
GROUP_UPDATE_FULL = 0x0007FFFF, // all known flags
};
@@ -249,7 +251,7 @@ class TRINITY_DLL_SPEC Group
void ConvertToRaid();
void SetBattlegroundGroup(BattleGround *bg) { m_bgGroup = bg; }
- uint32 CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot);
+ uint32 CanJoinBattleGroundQueue(BattleGroundTypeId bgTypeId, BattleGroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot);
void ChangeMembersGroup(const uint64 &guid, const uint8 &group);
void ChangeMembersGroup(Player *player, const uint8 &group);
@@ -291,7 +293,7 @@ class TRINITY_DLL_SPEC Group
void SendUpdate();
void UpdatePlayerOutOfRange(Player* pPlayer);
// ignore: GUID of player that will be ignored
- void BroadcastPacket(WorldPacket *packet, int group=-1, uint64 ignore=0);
+ void BroadcastPacket(WorldPacket *packet, bool ignorePlayersInBGRaid, int group=-1, uint64 ignore=0);
void BroadcastReadyCheck(WorldPacket *packet);
void OfflineReadyCheck();
diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp
index f63505ae24a..cd7004f5a07 100644
--- a/src/game/GroupHandler.cpp
+++ b/src/game/GroupHandler.cpp
@@ -28,10 +28,11 @@
#include "ObjectMgr.h"
#include "Player.h"
#include "Group.h"
-#include "ObjectAccessor.h"
-#include "MapManager.h"
#include "SocialMgr.h"
#include "Util.h"
+#include "SpellAuras.h"
+
+class Aura;
/* differeces from off:
-you can uninvite yourself - is is useful
@@ -59,12 +60,6 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
std::string membername;
recv_data >> membername;
- if(_player->InBattleGround())
- {
- SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_INVITE_RESTRICTED);
- return;
- }
-
// attempt add selected player
// cheating
@@ -83,6 +78,12 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
return;
}
+ // restrict invite to GMs
+ if (!sWorld.getConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->isGameMaster() && player->isGameMaster())
+ {
+ SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_CANT_FIND_TARGET);
+ return;
+ }
// can't group with
if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam())
{
@@ -107,15 +108,20 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
return;
}
+ Group *group = GetPlayer()->GetGroup();
+ if( group && group->isBGGroup() )
+ group = GetPlayer()->GetOriginalGroup();
+
+ Group *group2 = player->GetGroup();
+ if( group2 && group2->isBGGroup() )
+ group2 = player->GetOriginalGroup();
// player already in another group or invited
- if(player->GetGroup() || player->GetGroupInvite() )
+ if( group2 || player->GetGroupInvite() )
{
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_ALREADY_IN_GROUP);
return;
}
- Group *group = GetPlayer()->GetGroup();
-
if(group)
{
// not have permissions for invite
@@ -161,6 +167,7 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
// ok, we do it
WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size
+ data << uint8(1); // ok
data << GetPlayer()->GetName();
player->GetSession()->SendPacket(&data);
@@ -193,12 +200,6 @@ void WorldSession::HandleGroupAcceptOpcode( WorldPacket & /*recv_data*/ )
Player* leader = objmgr.GetPlayer(group->GetLeaderGUID());
- if(leader && leader->InBattleGround())
- {
- SendPartyResult(PARTY_OP_INVITE, "", PARTY_RESULT_INVITE_RESTRICTED);
- return;
- }
-
// forming a new group, create it
if(!group->IsCreated())
{
@@ -208,14 +209,10 @@ void WorldSession::HandleGroupAcceptOpcode( WorldPacket & /*recv_data*/ )
objmgr.AddGroup(group);
}
- // everything's fine, do it
+ // everything's fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!!
if(!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName()))
return;
- uint8 subgroup = group->GetMemberGroup(GetPlayer()->GetGUID());
-
- GetPlayer()->SetGroup(group, subgroup);
-
group->BroadcastGroupUpdate();
}
@@ -224,26 +221,16 @@ void WorldSession::HandleGroupDeclineOpcode( WorldPacket & /*recv_data*/ )
Group *group = GetPlayer()->GetGroupInvite();
if (!group) return;
+ // remember leader if online
Player *leader = objmgr.GetPlayer(group->GetLeaderGUID());
- /** error handling **/
+ // uninvite, group can be deleted
+ GetPlayer()->UninviteFromGroup();
+
if(!leader || !leader->GetSession())
return;
- /********************/
-
- // everything's fine, do it
- if(!group->IsCreated())
- {
- // note: this means that if you invite more than one person
- // and one of them declines before the first one accepts
- // all invites will be cleared
- // fixme: is that ok ?
- group->RemoveAllInvites();
- delete group;
- }
-
- GetPlayer()->SetGroupInvite(NULL);
+ // report
WorldPacket data( SMSG_GROUP_DECLINE, 10 ); // guess size
data << GetPlayer()->GetName();
leader->GetSession()->SendPacket( &data );
@@ -445,7 +432,7 @@ void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data)
data << GetPlayer()->GetGUID();
data << x;
data << y;
- GetPlayer()->GetGroup()->BroadcastPacket(&data, -1, GetPlayer()->GetGUID());
+ GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID());
}
void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data)
@@ -472,7 +459,7 @@ void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data)
data << roll;
data << GetPlayer()->GetGUID();
if(GetPlayer()->GetGroup())
- GetPlayer()->GetGroup()->BroadcastPacket(&data);
+ GetPlayer()->GetGroup()->BroadcastPacket(&data, false);
else
SendPacket(&data);
}
@@ -555,8 +542,20 @@ void WorldSession::HandleGroupChangeSubGroupOpcode( WorldPacket & recv_data )
return;
/********************/
+ Player *movedPlayer=objmgr.GetPlayer(name.c_str());
+ if(!movedPlayer)
+ return;
+
+ //Do not allow leader to change group of player in combat
+ if (movedPlayer->isInCombat())
+ {
+ WorldPacket data(SMSG_GROUP_SWAP_FAILED, (0));
+ SendPacket(&data);
+ return;
+ }
+
// everything's fine, do it
- group->ChangeMembersGroup(objmgr.GetPlayer(name.c_str()), groupNr);
+ group->ChangeMembersGroup(movedPlayer, groupNr);
}
void WorldSession::HandleGroupAssistantOpcode( WorldPacket & recv_data )
@@ -626,7 +625,7 @@ void WorldSession::HandleRaidReadyCheckOpcode( WorldPacket & recv_data )
// everything's fine, do it
WorldPacket data(MSG_RAID_READY_CHECK, 8);
data << GetPlayer()->GetGUID();
- group->BroadcastPacket(&data, -1);
+ group->BroadcastPacket(&data, false, -1);
group->OfflineReadyCheck();
}
@@ -691,10 +690,10 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacke
}
if (mask & GROUP_UPDATE_FLAG_CUR_HP)
- *data << (uint16) player->GetHealth();
+ *data << (uint32) player->GetHealth();
if (mask & GROUP_UPDATE_FLAG_MAX_HP)
- *data << (uint16) player->GetMaxHealth();
+ *data << (uint32) player->GetMaxHealth();
Powers powerType = player->getPowerType();
if (mask & GROUP_UPDATE_FLAG_POWER_TYPE)
@@ -717,14 +716,14 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacke
if (mask & GROUP_UPDATE_FLAG_AURAS)
{
- uint64 auramask = player->GetAuraUpdateMask();
+ const uint64& auramask = player->GetAuraUpdateMaskForRaid();
*data << uint64(auramask);
for(uint32 i = 0; i < MAX_AURAS; ++i)
{
if(auramask & (uint64(1) << i))
{
- uint32 updatedAura=player->GetUInt32Value(uint16(UNIT_FIELD_AURA + i));
- *data << uint16(updatedAura);
+ Aura * pAura = player->GetVisibleAura(i);
+ *data << uint32(pAura ? pAura->GetId() : 0);
*data << uint8(1);
}
}
@@ -758,17 +757,17 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacke
if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP)
{
if(pet)
- *data << (uint16) pet->GetHealth();
+ *data << (uint32) pet->GetHealth();
else
- *data << (uint16) 0;
+ *data << (uint32) 0;
}
if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP)
{
if(pet)
- *data << (uint16) pet->GetMaxHealth();
+ *data << (uint32) pet->GetMaxHealth();
else
- *data << (uint16) 0;
+ *data << (uint32) 0;
}
if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE)
@@ -799,14 +798,14 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacke
{
if(pet)
{
- uint64 auramask = pet->GetAuraUpdateMask();
+ const uint64& auramask = pet->GetAuraUpdateMaskForRaid();
*data << uint64(auramask);
for(uint32 i = 0; i < MAX_AURAS; ++i)
{
if(auramask & (uint64(1) << i))
{
- uint32 updatedAura=pet->GetUInt32Value(uint16(UNIT_FIELD_AURA + i));
- *data << uint16(updatedAura);
+ Aura * pAura = pet->GetVisibleAura(i);
+ *data << uint32(pAura ? pAura->GetId() : 0);
*data << uint8(1);
}
}
@@ -829,6 +828,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
if(!player)
{
WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2);
+ data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related
data.appendPackGUID(Guid);
data << (uint32) GROUP_UPDATE_FLAG_STATUS;
data << (uint16) MEMBER_STATUS_OFFLINE;
@@ -839,6 +839,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
Pet *pet = player->GetPet();
WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8);
+ data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related
data.append(player->GetPackGUID());
uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF
@@ -848,8 +849,8 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
Powers powerType = player->getPowerType();
data << (uint32) mask1; // group update mask
data << (uint16) MEMBER_STATUS_ONLINE; // member's online status
- data << (uint16) player->GetHealth(); // GROUP_UPDATE_FLAG_CUR_HP
- data << (uint16) player->GetMaxHealth(); // GROUP_UPDATE_FLAG_MAX_HP
+ data << (uint32) player->GetHealth(); // GROUP_UPDATE_FLAG_CUR_HP
+ data << (uint32) player->GetMaxHealth(); // GROUP_UPDATE_FLAG_MAX_HP
data << (uint8) powerType; // GROUP_UPDATE_FLAG_POWER_TYPE
data << (uint16) player->GetPower(powerType); // GROUP_UPDATE_FLAG_CUR_POWER
data << (uint16) player->GetMaxPower(powerType); // GROUP_UPDATE_FLAG_MAX_POWER
@@ -863,11 +864,11 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
data << (uint64) auramask; // placeholder
for(uint8 i = 0; i < MAX_AURAS; ++i)
{
- if(uint32 aura = player->GetUInt32Value(UNIT_FIELD_AURA + i))
+ if(Aura * pAura = player->GetVisibleAura(i))
{
auramask |= (uint64(1) << i);
- data << uint16(aura);
- data << uint8(1);
+ data << (uint32) pAura->GetId();
+ data << (uint8) 1;
}
}
data.put<uint64>(maskPos,auramask); // GROUP_UPDATE_FLAG_AURAS
@@ -878,8 +879,8 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
data << (uint64) pet->GetGUID(); // GROUP_UPDATE_FLAG_PET_GUID
data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME
data << (uint16) pet->GetDisplayId(); // GROUP_UPDATE_FLAG_PET_MODEL_ID
- data << (uint16) pet->GetHealth(); // GROUP_UPDATE_FLAG_PET_CUR_HP
- data << (uint16) pet->GetMaxHealth(); // GROUP_UPDATE_FLAG_PET_MAX_HP
+ data << (uint32) pet->GetHealth(); // GROUP_UPDATE_FLAG_PET_CUR_HP
+ data << (uint32) pet->GetMaxHealth(); // GROUP_UPDATE_FLAG_PET_MAX_HP
data << (uint8) petpowertype; // GROUP_UPDATE_FLAG_PET_POWER_TYPE
data << (uint16) pet->GetPower(petpowertype); // GROUP_UPDATE_FLAG_PET_CUR_POWER
data << (uint16) pet->GetMaxPower(petpowertype); // GROUP_UPDATE_FLAG_PET_MAX_POWER
@@ -889,10 +890,10 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
data << (uint64) petauramask; // placeholder
for(uint8 i = 0; i < MAX_AURAS; ++i)
{
- if(uint32 petaura = pet->GetUInt32Value(UNIT_FIELD_AURA + i))
+ if(Aura * pAura = pet->GetVisibleAura(i))
{
petauramask |= (uint64(1) << i);
- data << (uint16) petaura;
+ data << (uint32) pAura->GetId();
data << (uint8) 1;
}
}
diff --git a/src/game/GroupRefManager.h b/src/game/GroupRefManager.h
index 94741c30279..ab3b6417611 100644
--- a/src/game/GroupRefManager.h
+++ b/src/game/GroupRefManager.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/GroupReference.cpp b/src/game/GroupReference.cpp
index 24646e3059a..a09fc769dad 100644
--- a/src/game/GroupReference.cpp
+++ b/src/game/GroupReference.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/GroupReference.h b/src/game/GroupReference.h
index 0b338991109..da896cf02dd 100644
--- a/src/game/GroupReference.h
+++ b/src/game/GroupReference.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/GuardAI.cpp b/src/game/GuardAI.cpp
index 07a5bd9f819..b7268758583 100644
--- a/src/game/GuardAI.cpp
+++ b/src/game/GuardAI.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,107 +33,107 @@ int GuardAI::Permissible(const Creature *creature)
return PERMIT_BASE_NO;
}
-GuardAI::GuardAI(Creature *c) : CreatureAI(c), i_creature(*c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
+GuardAI::GuardAI(Creature *c) : CreatureAI(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
{
}
void GuardAI::MoveInLineOfSight(Unit *u)
{
// Ignore Z for flying creatures
- if ( !i_creature.canFly() && i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE )
+ if ( !m_creature->canFly() && m_creature->GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE )
return;
- if( !i_creature.getVictim() && i_creature.canAttack(u) &&
- ( u->IsHostileToPlayers() || i_creature.IsHostileTo(u) /*|| u->getVictim() && i_creature.IsFriendlyTo(u->getVictim())*/ ) &&
- u->isInAccessiblePlaceFor(&i_creature))
+ if( !m_creature->getVictim() && m_creature->canAttack(u) &&
+ ( u->IsHostileToPlayers() || m_creature->IsHostileTo(u) /*|| u->getVictim() && m_creature->IsFriendlyTo(u->getVictim())*/ ) &&
+ u->isInAccessiblePlaceFor(m_creature))
{
- float attackRadius = i_creature.GetAttackDistance(u);
- if(i_creature.IsWithinDistInMap(u,attackRadius))
+ float attackRadius = m_creature->GetAttackDistance(u);
+ if(m_creature->IsWithinDistInMap(u,attackRadius))
{
//Need add code to let guard support player
AttackStart(u);
- //u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //u->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
}
}
}
void GuardAI::EnterEvadeMode()
{
- if( !i_creature.isAlive() )
+ if( !m_creature->isAlive() )
{
- DEBUG_LOG("Creature stopped attacking because he's dead [guid=%u]", i_creature.GetGUIDLow());
- i_creature.GetMotionMaster()->MoveIdle();
+ DEBUG_LOG("Creature stopped attacking because he's dead [guid=%u]", m_creature->GetGUIDLow());
+ m_creature->GetMotionMaster()->MoveIdle();
i_state = STATE_NORMAL;
i_victimGuid = 0;
- i_creature.CombatStop();
- i_creature.DeleteThreatList();
+ m_creature->CombatStop(true);
+ m_creature->DeleteThreatList();
return;
}
- Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid );
+ Unit* victim = ObjectAccessor::GetUnit(*m_creature, i_victimGuid );
if( !victim )
{
- DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow());
+ DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", m_creature->GetGUIDLow());
}
else if( !victim ->isAlive() )
{
- DEBUG_LOG("Creature stopped attacking because victim is dead [guid=%u]", i_creature.GetGUIDLow());
+ DEBUG_LOG("Creature stopped attacking because victim is dead [guid=%u]", m_creature->GetGUIDLow());
}
else if( victim ->HasStealthAura() )
{
- DEBUG_LOG("Creature stopped attacking because victim is using stealth [guid=%u]", i_creature.GetGUIDLow());
+ DEBUG_LOG("Creature stopped attacking because victim is using stealth [guid=%u]", m_creature->GetGUIDLow());
}
else if( victim ->isInFlight() )
{
- DEBUG_LOG("Creature stopped attacking because victim is flying away [guid=%u]", i_creature.GetGUIDLow());
+ DEBUG_LOG("Creature stopped attacking because victim is flying away [guid=%u]", m_creature->GetGUIDLow());
}
else
{
- DEBUG_LOG("Creature stopped attacking because victim outran him [guid=%u]", i_creature.GetGUIDLow());
+ DEBUG_LOG("Creature stopped attacking because victim outran him [guid=%u]", m_creature->GetGUIDLow());
}
- i_creature.RemoveAllAuras();
- i_creature.DeleteThreatList();
+ m_creature->RemoveAllAuras();
+ m_creature->DeleteThreatList();
i_victimGuid = 0;
- i_creature.CombatStop();
+ m_creature->CombatStop(true);
i_state = STATE_NORMAL;
// Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
- if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
- i_creature.GetMotionMaster()->MoveTargetedHome();
+ if( m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
+ m_creature->GetMotionMaster()->MoveTargetedHome();
}
void GuardAI::UpdateAI(const uint32 /*diff*/)
{
- // update i_victimGuid if i_creature.getVictim() !=0 and changed
+ // update i_victimGuid if m_creature->getVictim() !=0 and changed
if(!UpdateVictim())
return;
- i_victimGuid = i_creature.getVictim()->GetGUID();
+ i_victimGuid = m_creature->getVictim()->GetGUID();
- if( i_creature.isAttackReady() )
+ if( m_creature->isAttackReady() )
{
- if( i_creature.IsWithinMeleeRange(i_creature.getVictim()))
+ if( m_creature->IsWithinMeleeRange(m_creature->getVictim()))
{
- i_creature.AttackerStateUpdate(i_creature.getVictim());
- i_creature.resetAttackTimer();
+ m_creature->AttackerStateUpdate(m_creature->getVictim());
+ m_creature->resetAttackTimer();
}
}
}
bool GuardAI::IsVisible(Unit *pl) const
{
- return i_creature.GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_GUARDER)
- && pl->isVisibleForOrDetect(&i_creature,true);
+ return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_GUARDER))
+ && pl->isVisibleForOrDetect(m_creature,true);
}
void GuardAI::JustDied(Unit *killer)
{
if(Player* pkiller = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
- i_creature.SendZoneUnderAttackMessage(pkiller);
+ m_creature->SendZoneUnderAttackMessage(pkiller);
}
diff --git a/src/game/GuardAI.h b/src/game/GuardAI.h
index b7b3c79607b..db1bfe0229d 100644
--- a/src/game/GuardAI.h
+++ b/src/game/GuardAI.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@ class TRINITY_DLL_DECL GuardAI : public CreatureAI
public:
- GuardAI(Creature *c);
+ explicit GuardAI(Creature *c);
void MoveInLineOfSight(Unit *);
void EnterEvadeMode();
@@ -47,7 +47,6 @@ class TRINITY_DLL_DECL GuardAI : public CreatureAI
static int Permissible(const Creature *);
private:
- Creature &i_creature;
uint64 i_victimGuid;
GuardState i_state;
TimeTracker i_tracker;
diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp
index 87dbb81c5c6..fdc39d5d851 100644
--- a/src/game/Guild.cpp
+++ b/src/game/Guild.cpp
@@ -21,7 +21,6 @@
#include "Database/DatabaseEnv.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "MapManager.h"
#include "Player.h"
#include "Opcodes.h"
#include "ObjectMgr.h"
@@ -29,6 +28,7 @@
#include "Chat.h"
#include "SocialMgr.h"
#include "Util.h"
+#include "Language.h"
Guild::Guild()
{
@@ -52,27 +52,25 @@ Guild::~Guild()
}
-bool Guild::create(uint64 lGuid, std::string gname)
+bool Guild::create(Player* leader, std::string gname)
{
- std::string rname;
- std::string lName;
-
- if(!objmgr.GetPlayerNameByGUID(lGuid, lName))
- return false;
if(objmgr.GetGuildByName(gname))
return false;
- sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(lGuid));
+ WorldSession* lSession = leader->GetSession();
+ if(!lSession)
+ return false;
- leaderGuid = lGuid;
+ leaderGuid = leader->GetGUID();
name = gname;
GINFO = "";
MOTD = "No message set.";
guildbank_money = 0;
purchased_tabs = 0;
-
Id = objmgr.GenerateGuildId();
+ sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(leaderGuid));
+
// gname already assigned to Guild::name, use it to encode string for DB
CharacterDatabase.escape_string(gname);
@@ -90,18 +88,13 @@ bool Guild::create(uint64 lGuid, std::string gname)
Id, gname.c_str(), GUID_LOPART(leaderGuid), dbGINFO.c_str(), dbMOTD.c_str(), EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, guildbank_money);
CharacterDatabase.CommitTransaction();
- rname = "Guild Master";
- CreateRank(rname,GR_RIGHT_ALL);
- rname = "Officer";
- CreateRank(rname,GR_RIGHT_ALL);
- rname = "Veteran";
- CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
- rname = "Member";
- CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
- rname = "Initiate";
- CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
+ CreateRank(lSession->GetMangosString(LANG_GUILD_MASTER), GR_RIGHT_ALL);
+ CreateRank(lSession->GetMangosString(LANG_GUILD_OFFICER), GR_RIGHT_ALL);
+ CreateRank(lSession->GetMangosString(LANG_GUILD_VETERAN), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
+ CreateRank(lSession->GetMangosString(LANG_GUILD_MEMBER), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
+ CreateRank(lSession->GetMangosString(LANG_GUILD_INITIATE),GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
- return AddMember(lGuid, (uint32)GR_GUILDMASTER);
+ return AddMember(leaderGuid, (uint32)GR_GUILDMASTER);
}
bool Guild::AddMember(uint64 plGuid, uint32 plRank)
@@ -569,7 +562,7 @@ void Guild::BroadcastToOfficers(WorldSession *session, const std::string& msg, u
{
if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_OFFCHATSPEAK))
{
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
WorldPacket data;
ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, NULL, 0, msg.c_str(),NULL);
@@ -584,7 +577,7 @@ void Guild::BroadcastToOfficers(WorldSession *session, const std::string& msg, u
void Guild::BroadcastPacket(WorldPacket *packet)
{
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
if(player)
@@ -594,7 +587,7 @@ void Guild::BroadcastPacket(WorldPacket *packet)
void Guild::BroadcastPacketToRank(WorldPacket *packet, uint32 rankId)
{
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
if (itr->second.RankId == rankId)
{
@@ -621,7 +614,7 @@ void Guild::CreateRank(std::string name_,uint32 rights)
// name now can be used for encoding to DB
CharacterDatabase.escape_string(name_);
- CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", Id, m_ranks.size(), name_.c_str(), rights );
+ CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", Id, (unsigned int)m_ranks.size(), name_.c_str(), rights );
}
void Guild::AddRank(const std::string& name_,uint32 rights, uint32 money)
@@ -681,7 +674,7 @@ void Guild::SetRankRights(uint32 rankId, uint32 rights)
int32 Guild::GetRank(uint32 LowGuid)
{
- MemberList::iterator itr = members.find(LowGuid);
+ MemberList::const_iterator itr = members.find(LowGuid);
if (itr==members.end())
return -1;
@@ -696,7 +689,7 @@ void Guild::Disband()
while (!members.empty())
{
- MemberList::iterator itr = members.begin();
+ MemberList::const_iterator itr = members.begin();
DelMember(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER), true);
}
@@ -785,6 +778,7 @@ void Guild::Query(WorldSession *session)
data << uint32(BorderStyle);
data << uint32(BorderColor);
data << uint32(BackgroundColor);
+ data << uint32(0); // something new in WotLK
session->SendPacket( &data );
sLog.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" );
@@ -1603,7 +1597,21 @@ void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
{
data << uint8((*itr)->LogEntry);
data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER));
- data << uint32((*itr)->ItemOrMoney);
+ if ((*itr)->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY ||
+ (*itr)->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY ||
+ (*itr)->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY ||
+ (*itr)->LogEntry == GUILD_BANK_LOG_UNK1 ||
+ (*itr)->LogEntry == GUILD_BANK_LOG_UNK2)
+ {
+ data << uint32((*itr)->ItemOrMoney);
+ }
+ else
+ {
+ data << uint32((*itr)->ItemOrMoney);
+ data << uint32((*itr)->ItemStackCount);
+ if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2)
+ data << uint8((*itr)->DestTabId); // moved tab
+ }
data << uint32(time(NULL)-(*itr)->TimeStamp);
}
session->SendPacket(&data);
@@ -1619,10 +1627,21 @@ void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
{
data << uint8((*itr)->LogEntry);
data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER));
- data << uint32((*itr)->ItemOrMoney);
- data << uint8((*itr)->ItemStackCount);
- if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2)
- data << uint8((*itr)->DestTabId); // moved tab
+ if ((*itr)->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY ||
+ (*itr)->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY ||
+ (*itr)->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY ||
+ (*itr)->LogEntry == GUILD_BANK_LOG_UNK1 ||
+ (*itr)->LogEntry == GUILD_BANK_LOG_UNK2)
+ {
+ data << uint32((*itr)->ItemOrMoney);
+ }
+ else
+ {
+ data << uint32((*itr)->ItemOrMoney);
+ data << uint32((*itr)->ItemStackCount);
+ if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2)
+ data << uint8((*itr)->DestTabId); // moved tab
+ }
data << uint32(time(NULL)-(*itr)->TimeStamp);
}
session->SendPacket(&data);
@@ -1704,7 +1723,7 @@ void Guild::AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *t
// SuffixFactor +4
data << (uint32) pItem->GetItemSuffixFactor();
// +12 // ITEM_FIELD_STACK_COUNT
- data << uint8(pItem->GetCount());
+ data << uint32(pItem->GetCount());
data << uint32(0); // +16 // Unknown value
data << uint8(0); // unknown 2.4.2
if (uint32 Enchant0 = pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT))
@@ -1961,6 +1980,9 @@ void Guild::SetGuildBankTabText(uint8 TabId, std::string text)
CharacterDatabase.escape_string(text);
CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text.c_str(), Id, uint32(TabId));
+
+ // announce
+ SendGuildBankTabText(NULL,TabId);
}
void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId)
@@ -1975,7 +1997,12 @@ void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId)
WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1);
data << uint8(TabId);
data << tab->Text;
- session->SendPacket(&data);
+
+ if(session)
+ session->SendPacket(&data);
+ else
+ BroadcastPacket(&data);
+
}
bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const
diff --git a/src/game/Guild.h b/src/game/Guild.h
index 5dc6c00111d..9f832260f14 100644
--- a/src/game/Guild.h
+++ b/src/game/Guild.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,10 +53,11 @@ enum GuildRankRights
GR_RIGHT_VIEWOFFNOTE = 0x00004040,
GR_RIGHT_EOFFNOTE = 0x00008040,
GR_RIGHT_MODIFY_GUILD_INFO = 0x00010040,
- GR_RIGHT_REPAIR_FROM_GUILD = 0x00020000, // unused in 2.4.x?, Remove money withdraw capacity
+ GR_RIGHT_WITHDRAW_GOLD_LOCK = 0x00020000, // remove money withdraw capacity
GR_RIGHT_WITHDRAW_REPAIR = 0x00040000, // withdraw for repair
GR_RIGHT_WITHDRAW_GOLD = 0x00080000, // withdraw gold
- GR_RIGHT_ALL = 0x000FF1FF
+ GR_RIGHT_CREATE_GUILD_EVENT = 0x00100000, // wotlk
+ GR_RIGHT_ALL = 0x001DF1FF
};
enum Typecommand
@@ -156,6 +157,8 @@ enum GuildBankLogEntries
GUILD_BANK_LOG_WITHDRAW_MONEY = 5,
GUILD_BANK_LOG_REPAIR_MONEY = 6,
GUILD_BANK_LOG_MOVE_ITEM2 = 7,
+ GUILD_BANK_LOG_UNK1 = 8,
+ GUILD_BANK_LOG_UNK2 = 9,
};
enum GuildEventLogEntryTypes
@@ -188,6 +191,22 @@ enum GuildEmblem
ERR_GUILDEMBLEM_INVALIDVENDOR = 5
};
+inline uint32 GetGuildBankTabPrice(uint8 Index)
+{
+ switch(Index)
+ {
+ case 0: return 100;
+ case 1: return 250;
+ case 2: return 500;
+ case 3: return 1000;
+ case 4: return 2500;
+ case 5: return 5000;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
struct GuildBankEvent
{
uint32 LogGuid;
@@ -217,12 +236,12 @@ struct GuildBankTab
struct GuildItemPosCount
{
- GuildItemPosCount(uint8 _slot, uint8 _count) : slot(_slot), count(_count) {}
+ GuildItemPosCount(uint8 _slot, uint32 _count) : slot(_slot), count(_count) {}
bool isContainedIn(std::vector<GuildItemPosCount> const& vec) const;
uint8 slot;
- uint8 count;
+ uint32 count;
};
typedef std::vector<GuildItemPosCount> GuildItemPosCountVec;
@@ -266,7 +285,7 @@ class Guild
Guild();
~Guild();
- bool create(uint64 lGuid, std::string gname);
+ bool create(Player* leader, std::string gname);
void Disband();
typedef std::map<uint32, MemberSlot> MemberList;
@@ -314,6 +333,15 @@ class Guild
void BroadcastPacketToRank(WorldPacket *packet, uint32 rankId);
void BroadcastPacket(WorldPacket *packet);
+ template<class Do>
+ void BroadcastWorker(Do& _do, Player* except = NULL)
+ {
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ if(Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
+ if(player != except)
+ _do(player);
+ }
+
void CreateRank(std::string name,uint32 rights);
void DelRank();
std::string GetRankName(uint32 rankId);
diff --git a/src/game/GuildHandler.cpp b/src/game/GuildHandler.cpp
index 77e9af49ed3..4055497c730 100644
--- a/src/game/GuildHandler.cpp
+++ b/src/game/GuildHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +26,6 @@
#include "Log.h"
#include "Opcodes.h"
#include "Guild.h"
-#include "MapManager.h"
#include "GossipDef.h"
#include "SocialMgr.h"
@@ -65,7 +64,7 @@ void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket)
return;
Guild *guild = new Guild;
- if(!guild->create(GetPlayer()->GetGUID(),gname))
+ if(!guild->create(GetPlayer(),gname))
{
delete guild;
return;
@@ -375,7 +374,7 @@ void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket)
guild->ChangeRank(plGuid, (slot->RankId+1));
// Put record into guildlog
- guild->LogGuildEvent(GUILD_EVENT_LOG_DEMOTE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), (slot->RankId));
+ guild->LogGuildEvent(GUILD_EVENT_LOG_DEMOTE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), slot->RankId);
WorldPacket data(SMSG_GUILD_EVENT, (2+30)); // guess size
data << (uint8)GE_DEMOTION;
@@ -663,7 +662,7 @@ void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket)
guild->SetRankName(rankId, rankname);
if(rankId==GR_GUILDMASTER) // prevent loss leader rights
- rights |= GR_RIGHT_ALL;
+ rights = GR_RIGHT_ALL;
guild->SetRankRights(rankId, rights);
@@ -783,7 +782,7 @@ void WorldSession::HandleGuildSaveEmblemOpcode(WorldPacket& recvPacket)
recvPacket >> vendorGuid;
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorGuid,UNIT_NPC_FLAG_TABARDDESIGNER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid,UNIT_NPC_FLAG_TABARDDESIGNER);
if (!pCreature)
{
//"That's not an emblem vendor!"
@@ -794,7 +793,7 @@ void WorldSession::HandleGuildSaveEmblemOpcode(WorldPacket& recvPacket)
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
recvPacket >> EmblemStyle;
recvPacket >> EmblemColor;
@@ -906,7 +905,7 @@ void WorldSession::HandleGuildBankQuery( WorldPacket & recv_data )
uint8 unk;
recv_data >> GoGuid >> unk;
- if (!objmgr.IsGuildVaultGameObject(_player, GoGuid))
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK))
return;
if (uint32 GuildId = GetPlayer()->GetGuildId())
@@ -930,7 +929,7 @@ void WorldSession::HandleGuildBankTabColon( WorldPacket & recv_data )
uint8 TabId,unk1;
recv_data >> GoGuid >> TabId >> unk1;
- if (!objmgr.IsGuildVaultGameObject(_player, GoGuid))
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK))
return;
uint32 GuildId = GetPlayer()->GetGuildId();
@@ -959,7 +958,7 @@ void WorldSession::HandleGuildBankDeposit( WorldPacket & recv_data )
if (!money)
return;
- if (!objmgr.IsGuildVaultGameObject(_player, GoGuid))
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK))
return;
uint32 GuildId = GetPlayer()->GetGuildId();
@@ -1007,7 +1006,7 @@ void WorldSession::HandleGuildBankWithdraw( WorldPacket & recv_data )
if (!money)
return;
- if (!objmgr.IsGuildVaultGameObject(_player, GoGuid))
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK))
return;
uint32 GuildId = GetPlayer()->GetGuildId();
@@ -1109,7 +1108,7 @@ void WorldSession::HandleGuildBankDepositItem( WorldPacket & recv_data )
return;
}
- if (!objmgr.IsGuildVaultGameObject(_player, GoGuid))
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK))
return;
uint32 GuildId = GetPlayer()->GetGuildId();
@@ -1195,7 +1194,7 @@ void WorldSession::HandleGuildBankDepositItem( WorldPacket & recv_data )
else // swap
{
gDest.clear();
- uint8 msg = pGuild->CanStoreItem(BankTabDst,BankTabSlotDst,gDest,pItemSrc->GetCount(),pItemSrc,true);
+ msg = pGuild->CanStoreItem(BankTabDst,BankTabSlotDst,gDest,pItemSrc->GetCount(),pItemSrc,true);
if( msg != EQUIP_ERR_OK )
{
pl->SendEquipError( msg, pItemSrc, NULL );
@@ -1564,7 +1563,7 @@ void WorldSession::HandleGuildBankBuyTab( WorldPacket & recv_data )
recv_data >> GoGuid;
recv_data >> TabId;
- if (!objmgr.IsGuildVaultGameObject(_player, GoGuid))
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK))
return;
uint32 GuildId = GetPlayer()->GetGuildId();
@@ -1575,7 +1574,7 @@ void WorldSession::HandleGuildBankBuyTab( WorldPacket & recv_data )
if(!pGuild)
return;
- uint32 TabCost = objmgr.GetGuildBankTabPrice(TabId) * GOLD;
+ uint32 TabCost = GetGuildBankTabPrice(TabId) * GOLD;
if (!TabCost)
return;
@@ -1621,7 +1620,7 @@ void WorldSession::HandleGuildBankModifyTab( WorldPacket & recv_data )
if(IconIndex.empty())
return;
- if (!objmgr.IsGuildVaultGameObject(_player, GoGuid))
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK))
return;
uint32 GuildId = GetPlayer()->GetGuildId();
diff --git a/src/game/HomeMovementGenerator.cpp b/src/game/HomeMovementGenerator.cpp
index 0d3d409320c..a2bad0b0db7 100644
--- a/src/game/HomeMovementGenerator.cpp
+++ b/src/game/HomeMovementGenerator.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,9 +20,8 @@
#include "HomeMovementGenerator.h"
#include "Creature.h"
+#include "CreatureAI.h"
#include "Traveller.h"
-#include "MapManager.h"
-#include "ObjectAccessor.h"
#include "DestinationHolderImp.h"
#include "WorldPacket.h"
@@ -70,11 +69,14 @@ HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff
// restore orientation of not moving creature at returning to home
if(owner.GetDefaultMovementType()==IDLE_MOTION_TYPE)
{
+ //sLog.outDebug("Entering HomeMovement::GetDestination(z,y,z)");
owner.SetOrientation(ori);
WorldPacket packet;
owner.BuildHeartBeatMsg(&packet);
owner.SendMessageToSet(&packet, false);
}
+
+ owner.AI()->JustReachedHome();
return false;
}
diff --git a/src/game/HomeMovementGenerator.h b/src/game/HomeMovementGenerator.h
index 12d5f150405..964b5c3e801 100644
--- a/src/game/HomeMovementGenerator.h
+++ b/src/game/HomeMovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,6 +47,7 @@ class TRINITY_DLL_SPEC HomeMovementGenerator<Creature>
MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; }
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; }
+
private:
void _setTargetLocation(Creature &);
DestinationHolder< Traveller<Creature> > i_destinationHolder;
diff --git a/src/game/HostilRefManager.cpp b/src/game/HostilRefManager.cpp
index f1cb465520e..4a51d54248d 100644
--- a/src/game/HostilRefManager.cpp
+++ b/src/game/HostilRefManager.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
#include "HostilRefManager.h"
#include "ThreatManager.h"
#include "Unit.h"
-#include "Database/DBCStructure.h"
+#include "DBCStructure.h"
#include "SpellMgr.h"
HostilRefManager::~HostilRefManager()
diff --git a/src/game/HostilRefManager.h b/src/game/HostilRefManager.h
index e7addd5479b..316509e3908 100644
--- a/src/game/HostilRefManager.h
+++ b/src/game/HostilRefManager.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/IdleMovementGenerator.cpp b/src/game/IdleMovementGenerator.cpp
index f8161c186c5..17e777db240 100644
--- a/src/game/IdleMovementGenerator.cpp
+++ b/src/game/IdleMovementGenerator.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
*/
#include "IdleMovementGenerator.h"
+#include "CreatureAI.h"
#include "Creature.h"
IdleMovementGenerator si_idleMovement;
@@ -60,3 +61,9 @@ DistractMovementGenerator::Update(Unit& owner, const uint32& time_diff)
return true;
}
+void
+AssistanceDistractMovementGenerator::Finalize(Unit &unit)
+{
+ unit.clearUnitState(UNIT_STAT_DISTRACTED);
+ ((Creature*)&unit)->SetReactState(REACT_AGGRESSIVE);
+}
diff --git a/src/game/IdleMovementGenerator.h b/src/game/IdleMovementGenerator.h
index ac5a4da529c..2d5b7d94314 100644
--- a/src/game/IdleMovementGenerator.h
+++ b/src/game/IdleMovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -51,5 +51,15 @@ class TRINITY_DLL_SPEC DistractMovementGenerator : public MovementGenerator
uint32 m_timer;
};
+class MANGOS_DLL_SPEC AssistanceDistractMovementGenerator : public DistractMovementGenerator
+{
+ public:
+ AssistanceDistractMovementGenerator(uint32 timer) :
+ DistractMovementGenerator(timer) {}
+
+ MovementGeneratorType GetMovementGeneratorType() { return ASSISTANCE_DISTRACT_MOTION_TYPE; }
+ void Finalize(Unit& unit);
+};
+
#endif
diff --git a/src/game/InstanceData.cpp b/src/game/InstanceData.cpp
index 0f62e9e27af..bb4bfe5e8fc 100644
--- a/src/game/InstanceData.cpp
+++ b/src/game/InstanceData.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,21 +21,25 @@
#include "InstanceData.h"
#include "Database/DatabaseEnv.h"
#include "Map.h"
+#include "GameObject.h"
+#include "Creature.h"
+#include "CreatureAI.h"
void InstanceData::SaveToDB()
{
- if(!Save()) return;
- std::string data = Save();
+ std::string data = GetSaveData();
+ if(data.empty())
+ return;
CharacterDatabase.escape_string(data);
CharacterDatabase.PExecute("UPDATE instance SET data = '%s' WHERE id = '%d'", data.c_str(), instance->GetInstanceId());
}
-void InstanceData::HandleGameObject(uint64 GUID, bool open, GameObject *go)
-{
+void InstanceData::HandleGameObject(uint64 GUID, bool open, GameObject *go)
+{
if(!go)
- go = instance->GetGameObjectInMap(GUID);
+ go = instance->GetGameObject(GUID);
if(go)
- go->SetGoState(open ? 0 : 1);
+ go->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
else
debug_log("TSCR: InstanceData: HandleGameObject failed");
}
@@ -49,83 +53,196 @@ bool InstanceData::IsEncounterInProgress() const
return false;
}
-void InstanceData::AddBossRoomDoor(uint32 id, GameObject *door)
+//This will be removed in the future, just compitiable with Mangos
+void InstanceData::OnCreatureCreate(Creature *creature, bool add)
{
- if(id < bosses.size())
+ OnCreatureCreate(creature, creature->GetEntry());
+}
+
+void InstanceData::LoadMinionData(const MinionData *data)
+{
+ while(data->entry)
{
- BossInfo *bossInfo = &bosses[id];
- bossInfo->roomDoor.insert(door);
- // Room door is only closed when encounter is in progress
- if(bossInfo->state == IN_PROGRESS)
- door->SetGoState(1);
- else
- door->SetGoState(0);
+ if(data->bossId < bosses.size())
+ minions.insert(std::make_pair(data->entry, MinionInfo(&bosses[data->bossId])));
+
+ ++data;
}
+ sLog.outDebug("InstanceData::LoadMinionData: %u minions loaded.", doors.size());
}
-void InstanceData::AddBossPassageDoor(uint32 id, GameObject *door)
+void InstanceData::LoadDoorData(const DoorData *data)
{
- if(id < bosses.size())
+ while(data->entry)
{
- BossInfo *bossInfo = &bosses[id];
- bossInfo->passageDoor.insert(door);
- // Passage door is only opened when boss is defeated
- if(bossInfo->state == DONE)
- door->SetGoState(0);
- else
- door->SetGoState(1);
+ if(data->bossId < bosses.size())
+ doors.insert(std::make_pair(data->entry, DoorInfo(&bosses[data->bossId], data->type, BoundaryType(data->boundary))));
+
+ ++data;
}
+ sLog.outDebug("InstanceData::LoadDoorData: %u doors loaded.", doors.size());
}
-void InstanceData::RemoveBossRoomDoor(uint32 id, GameObject *door)
+void InstanceData::UpdateMinionState(Creature *minion, EncounterState state)
{
- if(id < bosses.size())
+ switch(state)
+ {
+ case NOT_STARTED:
+ if(!minion->isAlive())
+ minion->Respawn();
+ else if(minion->isInCombat())
+ minion->AI()->EnterEvadeMode();
+ break;
+ case IN_PROGRESS:
+ if(!minion->isAlive())
+ minion->Respawn();
+ else if(!minion->getVictim())
+ minion->AI()->DoZoneInCombat();
+ break;
+ }
+}
+
+void InstanceData::UpdateDoorState(GameObject *door)
+{
+ DoorInfoMap::iterator lower = doors.lower_bound(door->GetEntry());
+ DoorInfoMap::iterator upper = doors.upper_bound(door->GetEntry());
+ if(lower == upper)
+ return;
+
+ bool open = true;
+ for(DoorInfoMap::iterator itr = lower; itr != upper; ++itr)
{
- bosses[id].roomDoor.erase(door);
+ if(itr->second.type == DOOR_TYPE_ROOM)
+ {
+ if(itr->second.bossInfo->state == IN_PROGRESS)
+ {
+ open = false;
+ break;
+ }
+ }
+ else if(itr->second.type == DOOR_TYPE_PASSAGE)
+ {
+ if(itr->second.bossInfo->state != DONE)
+ {
+ open = false;
+ break;
+ }
+ }
}
+
+ door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
}
-void InstanceData::RemoveBossPassageDoor(uint32 id, GameObject *door)
+void InstanceData::AddDoor(GameObject *door, bool add)
{
- if(id < bosses.size())
+ DoorInfoMap::iterator lower = doors.lower_bound(door->GetEntry());
+ DoorInfoMap::iterator upper = doors.upper_bound(door->GetEntry());
+ if(lower == upper)
+ return;
+
+ for(DoorInfoMap::iterator itr = lower; itr != upper; ++itr)
{
- bosses[id].passageDoor.erase(door);
+ if(add)
+ {
+ itr->second.bossInfo->door[itr->second.type].insert(door);
+ switch(itr->second.boundary)
+ {
+ default:
+ case BOUNDARY_NONE:
+ break;
+ case BOUNDARY_N:
+ case BOUNDARY_S:
+ itr->second.bossInfo->boundary[itr->second.boundary] = door->GetPositionX();
+ break;
+ case BOUNDARY_E:
+ case BOUNDARY_W:
+ itr->second.bossInfo->boundary[itr->second.boundary] = door->GetPositionY();
+ break;
+ case BOUNDARY_NW:
+ case BOUNDARY_SE:
+ itr->second.bossInfo->boundary[itr->second.boundary] = door->GetPositionX() + door->GetPositionY();
+ break;
+ case BOUNDARY_NE:
+ case BOUNDARY_SW:
+ itr->second.bossInfo->boundary[itr->second.boundary] = door->GetPositionX() - door->GetPositionY();
+ break;
+ }
+ }
+ else
+ itr->second.bossInfo->door[itr->second.type].erase(door);
}
+
+ if(add)
+ UpdateDoorState(door);
}
-void InstanceData::SetBossState(uint32 id, EncounterState state)
+void InstanceData::AddMinion(Creature *minion, bool add)
+{
+ MinionInfoMap::iterator itr = minions.find(minion->GetEntry());
+ if(itr == minions.end())
+ return;
+
+ if(add)
+ itr->second.bossInfo->minion.insert(minion);
+ else
+ itr->second.bossInfo->minion.erase(minion);
+}
+
+bool InstanceData::SetBossState(uint32 id, EncounterState state)
{
if(id < bosses.size())
{
BossInfo *bossInfo = &bosses[id];
-
- bossInfo->state = state;
- switch(state)
+ if(bossInfo->state == TO_BE_DECIDED) // loading
{
- case NOT_STARTED:
- // Open all room doors, close all passage doors
- for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i)
- (*i)->SetGoState(0);
- for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i)
- (*i)->SetGoState(1);
- break;
- case IN_PROGRESS:
- // Close all doors
- for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i)
- (*i)->SetGoState(1);
- for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i)
- (*i)->SetGoState(1);
- break;
- case DONE:
- // Open all doors
- for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i)
- (*i)->SetGoState(0);
- for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i)
- (*i)->SetGoState(0);
- break;
- default:
- break;
+ bossInfo->state = state;
+ return false;
+ }
+ else
+ {
+ if(bossInfo->state == state)
+ return false;
+
+ if(state == DONE)
+ for(MinionSet::iterator i = bossInfo->minion.begin(); i != bossInfo->minion.end(); ++i)
+ if((*i)->isWorldBoss() && (*i)->isAlive())
+ return false;
+
+ bossInfo->state = state;
+ SaveToDB();
}
+
+ for(uint32 type = 0; type < MAX_DOOR_TYPES; ++type)
+ for(DoorSet::iterator i = bossInfo->door[type].begin(); i != bossInfo->door[type].end(); ++i)
+ UpdateDoorState(*i);
+
+ for(MinionSet::iterator i = bossInfo->minion.begin(); i != bossInfo->minion.end(); ++i)
+ UpdateMinionState(*i, state);
+
+ return true;
}
+ return false;
}
+std::string InstanceData::LoadBossState(const char * data)
+{
+ if(!data) return NULL;
+ std::istringstream loadStream(data);
+ uint32 buff;
+ uint32 bossId = 0;
+ for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i, ++bossId)
+ {
+ loadStream >> buff;
+ if(buff < TO_BE_DECIDED)
+ SetBossState(bossId, (EncounterState)buff);
+ }
+ return loadStream.str();
+}
+
+std::string InstanceData::GetBossSaveData()
+{
+ std::ostringstream saveStream;
+ for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i)
+ saveStream << (uint32)i->state << " ";
+ return saveStream.str();
+}
diff --git a/src/game/InstanceData.h b/src/game/InstanceData.h
index 2f2b0c49be0..133f92ecc60 100644
--- a/src/game/InstanceData.h
+++ b/src/game/InstanceData.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,8 +22,8 @@
#define TRINITY_INSTANCE_DATA_H
#include "Common.h"
-#include "GameObject.h"
-#include "Map.h"
+//#include "GameObject.h"
+//#include "Map.h"
class Map;
class Unit;
@@ -31,24 +31,84 @@ class Player;
class GameObject;
class Creature;
+typedef std::set<GameObject*> DoorSet;
+typedef std::set<Creature*> MinionSet;
+
enum EncounterState
{
NOT_STARTED = 0,
IN_PROGRESS = 1,
FAIL = 2,
DONE = 3,
- SPECIAL = 4
+ SPECIAL = 4,
+ TO_BE_DECIDED = 5,
};
-typedef std::set<GameObject*> DoorSet;
+enum DoorType
+{
+ DOOR_TYPE_ROOM = 0,
+ DOOR_TYPE_PASSAGE,
+ MAX_DOOR_TYPES,
+};
+
+enum BoundaryType
+{
+ BOUNDARY_NONE = 0,
+ BOUNDARY_N,
+ BOUNDARY_S,
+ BOUNDARY_E,
+ BOUNDARY_W,
+ BOUNDARY_NE,
+ BOUNDARY_NW,
+ BOUNDARY_SE,
+ BOUNDARY_SW,
+ BOUNDARY_MAX_X = BOUNDARY_N,
+ BOUNDARY_MIN_X = BOUNDARY_S,
+ BOUNDARY_MAX_Y = BOUNDARY_W,
+ BOUNDARY_MIN_Y = BOUNDARY_E,
+};
+
+typedef std::map<BoundaryType, float> BossBoundaryMap;
+
+struct DoorData
+{
+ uint32 entry, bossId;
+ DoorType type;
+ uint32 boundary;
+};
+
+struct MinionData
+{
+ uint32 entry, bossId;
+};
struct BossInfo
{
- BossInfo() : state(NOT_STARTED) {}
+ BossInfo() : state(TO_BE_DECIDED) {}
EncounterState state;
- DoorSet roomDoor, passageDoor;
+ DoorSet door[MAX_DOOR_TYPES];
+ MinionSet minion;
+ BossBoundaryMap boundary;
+};
+
+struct DoorInfo
+{
+ explicit DoorInfo(BossInfo *_bossInfo, DoorType _type, BoundaryType _boundary)
+ : bossInfo(_bossInfo), type(_type), boundary(_boundary) {}
+ BossInfo *bossInfo;
+ DoorType type;
+ BoundaryType boundary;
};
+struct MinionInfo
+{
+ explicit MinionInfo(BossInfo *_bossInfo) : bossInfo(_bossInfo) {}
+ BossInfo *bossInfo;
+};
+
+typedef std::multimap<uint32 /*entry*/, DoorInfo> DoorInfoMap;
+typedef std::map<uint32 /*entry*/, MinionInfo> MinionInfoMap;
+
class TRINITY_DLL_SPEC InstanceData
{
public:
@@ -62,10 +122,10 @@ class TRINITY_DLL_SPEC InstanceData
virtual void Initialize() {}
//On load
- virtual void Load(const char* /*data*/) {}
+ virtual void Load(const char * data) { LoadBossState(data); }
//When save is needed, this function generates the data
- virtual const char* Save() { return ""; }
+ virtual std::string GetSaveData() { return GetBossSaveData(); }
void SaveToDB();
@@ -80,13 +140,14 @@ class TRINITY_DLL_SPEC InstanceData
virtual void OnPlayerEnter(Player *) {}
//Called when a gameobject is created
- virtual void OnObjectCreate(GameObject *) {}
+ virtual void OnObjectCreate(GameObject *go, bool add) { OnObjectCreate(go); }
//called on creature creation
- virtual void OnCreatureCreate(Creature * /*creature*/, uint32 /*creature_entry*/) {}
+ virtual void OnCreatureCreate(Creature *, bool add);
- virtual void OnCreatureRemove(Creature*) {}
- virtual void OnObjectRemove(GameObject*) {}
+ //All-purpose data storage 64 bit
+ virtual uint64 GetData64(uint32 /*Data*/) { return 0; }
+ virtual void SetData64(uint32 /*Data*/, uint64 /*Value*/) { }
//All-purpose data storage 32 bit
virtual uint32 GetData(uint32) { return 0; }
@@ -97,25 +158,28 @@ class TRINITY_DLL_SPEC InstanceData
//use HandleGameObject(GUID,boolen,NULL); in any other script
void HandleGameObject(uint64 GUID, bool open, GameObject *go = NULL);
+ virtual bool SetBossState(uint32 id, EncounterState state);
+ const BossBoundaryMap * GetBossBoundary(uint32 id) const { return id < bosses.size() ? &bosses[id].boundary : NULL; }
protected:
- void AddBossRoomDoor(uint32 id, GameObject *door);
- void AddBossPassageDoor(uint32 id, GameObject *door);
- void RemoveBossRoomDoor(uint32 id, GameObject *door);
- void RemoveBossPassageDoor(uint32 id, GameObject *door);
+ void SetBossNumber(uint32 number) { bosses.resize(number); }
+ void LoadDoorData(const DoorData *data);
+ void LoadMinionData(const MinionData *data);
- void SetBossState(uint32 id, EncounterState state);
+ void AddDoor(GameObject *door, bool add);
+ void AddMinion(Creature *minion, bool add);
- std::string GetBossSave()
- {
- std::ostringstream saveStream;
- for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i)
- saveStream << (uint32)i->state << " ";
- return saveStream.str();
- }
+ void UpdateDoorState(GameObject *door);
+ void UpdateMinionState(Creature *minion, EncounterState state);
+ std::string LoadBossState(const char * data);
+ std::string GetBossSaveData();
private:
std::vector<BossInfo> bosses;
+ DoorInfoMap doors;
+ MinionInfoMap minions;
+ virtual void OnObjectCreate(GameObject *) {}
+ virtual void OnCreatureCreate(Creature *, uint32 entry) {}
};
#endif
diff --git a/src/game/InstanceSaveMgr.cpp b/src/game/InstanceSaveMgr.cpp
index ba34f949a5f..7e2ad67c518 100644
--- a/src/game/InstanceSaveMgr.cpp
+++ b/src/game/InstanceSaveMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,13 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "InstanceSaveMgr.h"
#include "Common.h"
#include "Database/SQLStorage.h"
#include "Player.h"
#include "GridNotifiers.h"
-#include "WorldSession.h"
#include "Log.h"
#include "GridStates.h"
#include "CellImpl.h"
@@ -37,12 +35,13 @@
#include "GridNotifiersImpl.h"
#include "Config/ConfigEnv.h"
#include "Transports.h"
-#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "World.h"
#include "Group.h"
#include "InstanceData.h"
#include "ProgressBar.h"
+#include "Policies/Singleton.h"
+#include "Policies/SingletonImp.h"
INSTANTIATE_SINGLETON_1( InstanceSaveManager );
@@ -58,16 +57,16 @@ InstanceSaveManager::~InstanceSaveManager()
for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end(); ++itr)
{
InstanceSave *save = itr->second;
- for(InstanceSave::PlayerListType::iterator itr = save->m_playerList.begin(), next = itr; itr != save->m_playerList.end(); itr = next)
+ for(InstanceSave::PlayerListType::iterator itr2 = save->m_playerList.begin(), next = itr2; itr2 != save->m_playerList.end(); itr2 = next)
{
++next;
- (*itr)->UnbindInstance(save->GetMapId(), save->GetDifficulty(), true);
+ (*itr2)->UnbindInstance(save->GetMapId(), save->GetDifficulty(), true);
}
save->m_playerList.clear();
- for(InstanceSave::GroupListType::iterator itr = save->m_groupList.begin(), next = itr; itr != save->m_groupList.end(); itr = next)
+ for(InstanceSave::GroupListType::iterator itr2 = save->m_groupList.begin(), next = itr2; itr2 != save->m_groupList.end(); itr2 = next)
{
++next;
- (*itr)->UnbindInstance(save->GetMapId(), save->GetDifficulty(), true);
+ (*itr2)->UnbindInstance(save->GetMapId(), save->GetDifficulty(), true);
}
save->m_groupList.clear();
delete save;
@@ -142,9 +141,8 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 InstanceId)
}
}
-InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, uint8 difficulty,
- time_t resetTime, bool canReset)
-: m_mapid(MapId), m_instanceid(InstanceId), m_resetTime(resetTime),
+InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, uint8 difficulty, time_t resetTime, bool canReset)
+: m_resetTime(resetTime), m_instanceid(InstanceId), m_mapid(MapId),
m_difficulty(difficulty), m_canReset(canReset)
{
}
@@ -167,11 +165,11 @@ void InstanceSave::SaveToDB()
if(map)
{
assert(map->IsDungeon());
- InstanceData *iData = ((InstanceMap *)map)->GetInstanceData();
- if(iData && iData->Save())
+ if(InstanceData *iData = ((InstanceMap*)map)->GetInstanceData())
{
- data = iData->Save();
- CharacterDatabase.escape_string(data);
+ data = iData->GetSaveData();
+ if(!data.empty())
+ CharacterDatabase.escape_string(data);
}
}
@@ -270,7 +268,7 @@ void InstanceSaveManager::CleanupInstances()
// creature_respawn and gameobject_respawn are in another database
// first, obtain total instance set
- std::set< uint32 > InstanceSet;
+ std::set<uint32> InstanceSet;
QueryResult *result = CharacterDatabase.Query("SELECT id FROM instance");
if( result )
{
@@ -322,7 +320,7 @@ void InstanceSaveManager::PackInstances()
// TODO: this can be done a LOT more efficiently
// obtain set of all associations
- std::set< uint32 > InstanceSet;
+ std::set<uint32> InstanceSet;
// all valid ids are in the instance table
// any associations to ids not in this table are assumed to be
@@ -344,7 +342,7 @@ void InstanceSaveManager::PackInstances()
uint32 InstanceNumber = 1;
// we do assume std::set is sorted properly on integer value
- for (std::set< uint32 >::iterator i = InstanceSet.begin(); i != InstanceSet.end(); ++i)
+ for (std::set<uint32>::iterator i = InstanceSet.begin(); i != InstanceSet.end(); ++i)
{
if (*i != InstanceNumber)
{
@@ -361,8 +359,8 @@ void InstanceSaveManager::PackInstances()
bar.step();
}
- sLog.outString();
sLog.outString( ">> Instance numbers remapped, next instance id is %u", InstanceNumber );
+ sLog.outString();
}
void InstanceSaveManager::LoadResetTimes()
@@ -375,14 +373,14 @@ void InstanceSaveManager::LoadResetTimes()
// get the current reset times for normal instances (these may need to be updated)
// these are only kept in memory for InstanceSaves that are loaded later
// resettime = 0 in the DB for raid/heroic instances so those are skipped
- typedef std::map<uint32, std::pair<uint32, uint64> > ResetTimeMapType;
+ typedef std::map<uint32, std::pair<uint32, time_t> > ResetTimeMapType;
ResetTimeMapType InstResetTime;
QueryResult *result = CharacterDatabase.Query("SELECT id, map, resettime FROM instance WHERE resettime > 0");
if( result )
{
do
{
- if(uint64 resettime = (*result)[2].GetUInt64())
+ if(time_t resettime = time_t((*result)[2].GetUInt64()))
{
uint32 id = (*result)[0].GetUInt32();
uint32 mapid = (*result)[1].GetUInt32();
@@ -400,11 +398,11 @@ void InstanceSaveManager::LoadResetTimes()
{
Field *fields = result->Fetch();
uint32 instance = fields[1].GetUInt32();
- uint64 resettime = fields[0].GetUInt64() + 2 * HOUR;
+ time_t resettime = time_t(fields[0].GetUInt64() + 2 * HOUR);
ResetTimeMapType::iterator itr = InstResetTime.find(instance);
if(itr != InstResetTime.end() && itr->second.second != resettime)
{
- CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '"I64FMTD"' WHERE id = '%u'", resettime, instance);
+ CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '"I64FMTD"' WHERE id = '%u'", uint64(resettime), instance);
itr->second.second = resettime;
}
}
@@ -454,7 +452,7 @@ void InstanceSaveManager::LoadResetTimes()
// add the global reset times to the priority queue
for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++)
{
- InstanceTemplate* temp = (InstanceTemplate*)objmgr.GetInstanceTemplate(i);
+ InstanceTemplate const* temp = objmgr.GetInstanceTemplate(i);
if(!temp) continue;
// only raid/heroic maps have a global reset time
const MapEntry* entry = sMapStore.LookupEntry(temp->map);
@@ -559,6 +557,7 @@ void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator &itr)
Group *group = *(gList.begin());
group->UnbindInstance(itr->second->GetMapId(), itr->second->GetDifficulty(), true);
}
+ delete itr->second;
m_instanceSaveById.erase(itr++);
lock_instLists = false;
}
@@ -583,7 +582,7 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeLe
{
// global reset for all instances of the given map
// note: this isn't fast but it's meant to be executed very rarely
- Map *map = (MapInstanced*)MapManager::Instance().GetBaseMap(mapid);
+ Map const *map = MapManager::Instance().GetBaseMap(mapid);
if(!map->Instanceable())
return;
uint64 now = (uint64)time(NULL);
@@ -591,7 +590,7 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeLe
if(!warn)
{
// this is called one minute before the reset time
- InstanceTemplate* temp = (InstanceTemplate*)objmgr.GetInstanceTemplate(mapid);
+ InstanceTemplate const* temp = objmgr.GetInstanceTemplate(mapid);
if(!temp || !temp->reset_delay)
{
sLog.outError("InstanceSaveManager::ResetOrWarnAll: no instance template or reset delay for map %d", mapid);
@@ -626,10 +625,10 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeLe
MapInstanced::InstancedMaps::iterator mitr;
for(mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr)
{
- Map *map = mitr->second;
- if(!map->IsDungeon()) continue;
- if(warn) ((InstanceMap*)map)->SendResetWarnings(timeLeft);
- else ((InstanceMap*)map)->Reset(INSTANCE_RESET_GLOBAL);
+ Map *map2 = mitr->second;
+ if(!map2->IsDungeon()) continue;
+ if(warn) ((InstanceMap*)map2)->SendResetWarnings(timeLeft);
+ else ((InstanceMap*)map2)->Reset(INSTANCE_RESET_GLOBAL);
}
// TODO: delete creature/gameobject respawn times even if the maps are not loaded
diff --git a/src/game/InstanceSaveMgr.h b/src/game/InstanceSaveMgr.h
index 58b891b3a9f..29972210f3d 100644
--- a/src/game/InstanceSaveMgr.h
+++ b/src/game/InstanceSaveMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
#include "Platform/Define.h"
#include "Policies/Singleton.h"
-#include "zthread/Mutex.h"
+#include "ace/Thread_Mutex.h"
#include <list>
#include <map>
#include "Utilities/UnorderedMap.h"
@@ -113,7 +113,7 @@ class InstanceSave
bool m_canReset;
};
-class TRINITY_DLL_DECL InstanceSaveManager : public Trinity::Singleton<InstanceSaveManager, Trinity::ClassLevelLockable<InstanceSaveManager, ZThread::Mutex> >
+class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSaveManager, MaNGOS::ClassLevelLockable<InstanceSaveManager, ACE_Thread_Mutex> >
{
friend class InstanceSave;
public:
diff --git a/src/game/Item.cpp b/src/game/Item.cpp
index 766bd81d640..02a9b37d994 100644
--- a/src/game/Item.cpp
+++ b/src/game/Item.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
#include "WorldPacket.h"
#include "Database/DatabaseEnv.h"
#include "ItemEnchantmentMgr.h"
+#include "SpellMgr.h"
void AddItemsSetItem(Player*player,Item *item)
{
@@ -206,6 +207,10 @@ bool ItemCanGoIntoBag(ItemPrototype const *pProto, ItemPrototype const *pBagProt
if(!(pProto->BagFamily & BAG_FAMILY_MASK_LEATHERWORKING_SUPP))
return false;
return true;
+ case ITEM_SUBCLASS_INSCRIPTION_CONTAINER:
+ if(!(pProto->BagFamily & BAG_FAMILY_MASK_INSCRIPTION_SUPP))
+ return false;
+ return true;
default:
return false;
}
@@ -261,7 +266,7 @@ bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner)
SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability);
SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability);
- for(int i = 0; i < 5; ++i)
+ for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
SetSpellCharges(i,itemProto->Spells[i].SpellCharges);
SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags);
@@ -284,7 +289,7 @@ void Item::UpdateDuration(Player* owner, uint32 diff)
}
SetUInt32Value(ITEM_FIELD_DURATION, GetUInt32Value(ITEM_FIELD_DURATION) - diff);
- SetState(ITEM_CHANGED); // save new time in database
+ SetState(ITEM_CHANGED, owner); // save new time in database
}
void Item::SaveToDB()
@@ -297,7 +302,7 @@ void Item::SaveToDB()
CharacterDatabase.PExecute( "DELETE FROM item_instance WHERE guid = '%u'", guid );
std::ostringstream ss;
ss << "INSERT INTO item_instance (guid,owner_guid,data) VALUES (" << guid << "," << GUID_LOPART(GetOwnerGUID()) << ",'";
- for(uint16 i = 0; i < m_valuesCount; i++ )
+ for(uint16 i = 0; i < m_valuesCount; ++i )
ss << GetUInt32Value(i) << " ";
ss << "' )";
CharacterDatabase.Execute( ss.str().c_str() );
@@ -306,7 +311,7 @@ void Item::SaveToDB()
{
std::ostringstream ss;
ss << "UPDATE item_instance SET data = '";
- for(uint16 i = 0; i < m_valuesCount; i++ )
+ for(uint16 i = 0; i < m_valuesCount; ++i )
ss << GetUInt32Value(i) << " ";
ss << "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid << "'";
@@ -346,7 +351,7 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result)
if (!result)
{
- sLog.outError("ERROR: Item (GUID: %u owner: %u) not found in table `item_instance`, can't load. ",guid,GUID_LOPART(owner_guid));
+ sLog.outError("Item (GUID: %u owner: %u) not found in table `item_instance`, can't load. ",guid,GUID_LOPART(owner_guid));
return false;
}
@@ -354,7 +359,7 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result)
if(!LoadValues(fields[0].GetString()))
{
- sLog.outError("ERROR: Item #%d have broken data in `data` field. Can't be loaded.",guid);
+ sLog.outError("Item #%d have broken data in `data` field. Can't be loaded.",guid);
if (delete_result) delete result;
return false;
}
@@ -407,7 +412,7 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result)
{
std::ostringstream ss;
ss << "UPDATE item_instance SET data = '";
- for(uint16 i = 0; i < m_valuesCount; i++ )
+ for(uint16 i = 0; i < m_valuesCount; ++i )
ss << GetUInt32Value(i) << " ";
ss << "', owner_guid = '" << GUID_LOPART(GetOwnerGUID()) << "' WHERE guid = '" << guid << "'";
@@ -450,7 +455,7 @@ uint32 Item::GetSkill()
const static uint32 item_armor_skills[MAX_ITEM_SUBCLASS_ARMOR] =
{
- 0,SKILL_CLOTH,SKILL_LEATHER,SKILL_MAIL,SKILL_PLATE_MAIL,0,SKILL_SHIELD,0,0,0
+ 0,SKILL_CLOTH,SKILL_LEATHER,SKILL_MAIL,SKILL_PLATE_MAIL,0,SKILL_SHIELD,0,0,0,0
};
ItemPrototype const* proto = GetProto();
@@ -740,6 +745,12 @@ bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const
if (spellInfo->EquippedItemClass != -1) // -1 == any item class
{
+ // Special case - accept vellum for armor/weapon requirements
+ if( (spellInfo->EquippedItemClass==ITEM_CLASS_ARMOR && proto->IsArmorVellum())
+ ||( spellInfo->EquippedItemClass==ITEM_CLASS_WEAPON && proto->IsWeaponVellum()))
+ if (spellmgr.IsSkillTypeSpell(spellInfo->Id, SKILL_ENCHANTING)) // only for enchanting spells
+ return true;
+
if(spellInfo->EquippedItemClass != int32(proto->Class))
return false; // wrong item class
@@ -752,7 +763,12 @@ bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const
if(spellInfo->EquippedItemInventoryTypeMask != 0) // 0 == any inventory type
{
- if((spellInfo->EquippedItemInventoryTypeMask & (1 << proto->InventoryType)) == 0)
+ // Special case - accept weapon type for main and offhand requirements
+ if(proto->InventoryType == INVTYPE_WEAPON &&
+ (spellInfo->EquippedItemInventoryTypeMask & (1 << INVTYPE_WEAPONMAINHAND) ||
+ spellInfo->EquippedItemInventoryTypeMask & (1 << INVTYPE_WEAPONOFFHAND)))
+ return true;
+ else if ((spellInfo->EquippedItemInventoryTypeMask & (1 << proto->InventoryType)) == 0)
return false; // inventory type not present in mask
}
@@ -765,9 +781,9 @@ void Item::SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint
if((GetEnchantmentId(slot) == id) && (GetEnchantmentDuration(slot) == duration) && (GetEnchantmentCharges(slot) == charges))
return;
- SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET,id);
- SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET,duration);
- SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET,charges);
+ SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET,id);
+ SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET,duration);
+ SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET,charges);
SetState(ITEM_CHANGED);
}
@@ -776,7 +792,7 @@ void Item::SetEnchantmentDuration(EnchantmentSlot slot, uint32 duration)
if(GetEnchantmentDuration(slot) == duration)
return;
- SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET,duration);
+ SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET,duration);
SetState(ITEM_CHANGED);
}
@@ -785,7 +801,7 @@ void Item::SetEnchantmentCharges(EnchantmentSlot slot, uint32 charges)
if(GetEnchantmentCharges(slot) == charges)
return;
- SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET,charges);
+ SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET,charges);
SetState(ITEM_CHANGED);
}
@@ -795,14 +811,14 @@ void Item::ClearEnchantment(EnchantmentSlot slot)
return;
for(uint8 x = 0; x < 3; ++x)
- SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + x, 0);
+ SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + x, 0);
SetState(ITEM_CHANGED);
}
bool Item::GemsFitSockets() const
{
bool fits = true;
- for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
{
uint8 SocketColor = GetProto()->Socket[enchant_slot-SOCK_ENCHANTMENT_SLOT].Color;
@@ -842,7 +858,7 @@ bool Item::GemsFitSockets() const
uint8 Item::GetGemCountWithID(uint32 GemID) const
{
uint8 count = 0;
- for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
{
uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot));
if(!enchant_id)
@@ -858,6 +874,29 @@ uint8 Item::GetGemCountWithID(uint32 GemID) const
return count;
}
+uint8 Item::GetGemCountWithLimitCategory(uint32 limitCategory) const
+{
+ uint8 count = 0;
+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
+ {
+ uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot));
+ if(!enchant_id)
+ continue;
+
+ SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
+ if(!enchantEntry)
+ continue;
+
+ ItemPrototype const* gemProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID);
+ if(!gemProto)
+ continue;
+
+ if(gemProto->ItemLimitCategory==limitCategory)
+ ++count;
+ }
+ return count;
+}
+
bool Item::IsLimitedToAnotherMapOrZone( uint32 cur_mapId, uint32 cur_zoneId) const
{
ItemPrototype const* proto = GetProto();
@@ -886,8 +925,8 @@ Item* Item::CreateItem( uint32 item, uint32 count, Player const* player )
ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
if( pProto )
{
- if ( count > pProto->Stackable )
- count = pProto->Stackable;
+ if ( count > pProto->GetMaxStackSize())
+ count = pProto->GetMaxStackSize();
assert(count !=0 && "pProto->Stackable==0 but checked at loading already");
diff --git a/src/game/Item.h b/src/game/Item.h
index 3417f2fcc6d..9237c6715f2 100644
--- a/src/game/Item.h
+++ b/src/game/Item.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -148,29 +148,32 @@ enum SellFailure
// -1 from client enchantment slot number
enum EnchantmentSlot
{
- PERM_ENCHANTMENT_SLOT = 0,
- TEMP_ENCHANTMENT_SLOT = 1,
- SOCK_ENCHANTMENT_SLOT = 2,
- SOCK_ENCHANTMENT_SLOT_2 = 3,
- SOCK_ENCHANTMENT_SLOT_3 = 4,
- BONUS_ENCHANTMENT_SLOT = 5,
- MAX_INSPECTED_ENCHANTMENT_SLOT = 6,
-
- PROP_ENCHANTMENT_SLOT_0 = 6, // used with RandomSuffix
- PROP_ENCHANTMENT_SLOT_1 = 7, // used with RandomSuffix
- PROP_ENCHANTMENT_SLOT_2 = 8, // used with RandomSuffix and RandomProperty
- PROP_ENCHANTMENT_SLOT_3 = 9, // used with RandomProperty
- PROP_ENCHANTMENT_SLOT_4 = 10, // used with RandomProperty
- MAX_ENCHANTMENT_SLOT = 11
+ PERM_ENCHANTMENT_SLOT = 0,
+ TEMP_ENCHANTMENT_SLOT = 1,
+ SOCK_ENCHANTMENT_SLOT = 2,
+ SOCK_ENCHANTMENT_SLOT_2 = 3,
+ SOCK_ENCHANTMENT_SLOT_3 = 4,
+ BONUS_ENCHANTMENT_SLOT = 5,
+ PRISMATIC_ENCHANTMENT_SLOT = 6, // added at apply special permanent enchantment
+ MAX_INSPECTED_ENCHANTMENT_SLOT = 7,
+
+ PROP_ENCHANTMENT_SLOT_0 = 7, // used with RandomSuffix
+ PROP_ENCHANTMENT_SLOT_1 = 8, // used with RandomSuffix
+ PROP_ENCHANTMENT_SLOT_2 = 9, // used with RandomSuffix and RandomProperty
+ PROP_ENCHANTMENT_SLOT_3 = 10, // used with RandomProperty
+ PROP_ENCHANTMENT_SLOT_4 = 11, // used with RandomProperty
+ MAX_ENCHANTMENT_SLOT = 12
};
-#define MAX_VISIBLE_ITEM_OFFSET 16 // 16 fields per visible item (creator(2) + enchantments(12) + properties(1) + pad(1))
+#define MAX_VISIBLE_ITEM_OFFSET 18 // 18 fields per visible item (creator(2) + enchantments(13) + properties(1) + seed(1) + pad(1))
+
+#define MAX_GEM_SOCKETS MAX_ITEM_PROTO_SOCKETS// (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) and item proto size, equal value expected
enum EnchantmentOffset
{
ENCHANTMENT_ID_OFFSET = 0,
ENCHANTMENT_DURATION_OFFSET = 1,
- ENCHANTMENT_CHARGES_OFFSET = 2
+ ENCHANTMENT_CHARGES_OFFSET = 2 // now here not only charges, but something new in wotlk
};
#define MAX_ENCHANTMENT_OFFSET 3
@@ -211,6 +214,7 @@ class TRINITY_DLL_SPEC Item : public Object
void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS,ITEM_FLAGS_BINDED,val); }
bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BINDED); }
+ bool IsAccountBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BOA); }
bool IsBindedNotWith(uint64 guid) const { return IsSoulBound() && GetOwnerGUID()!= guid; }
bool IsBoundByEnchant() const;
virtual void SaveToDB();
@@ -230,8 +234,9 @@ class TRINITY_DLL_SPEC Item : public Object
uint32 GetCount() const { return GetUInt32Value (ITEM_FIELD_STACK_COUNT); }
void SetCount(uint32 value) { SetUInt32Value (ITEM_FIELD_STACK_COUNT, value); }
- uint32 GetMaxStackCount() const { return GetProto()->Stackable; }
+ uint32 GetMaxStackCount() const { return GetProto()->GetMaxStackSize(); }
uint8 GetGemCountWithID(uint32 GemID) const;
+ uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const;
uint8 GetSlot() const {return m_slot;}
Bag *GetContainer() { return m_container; }
@@ -256,9 +261,9 @@ class TRINITY_DLL_SPEC Item : public Object
void SetEnchantmentDuration(EnchantmentSlot slot, uint32 duration);
void SetEnchantmentCharges(EnchantmentSlot slot, uint32 charges);
void ClearEnchantment(EnchantmentSlot slot);
- uint32 GetEnchantmentId(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET);}
- uint32 GetEnchantmentDuration(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET);}
- uint32 GetEnchantmentCharges(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET);}
+ uint32 GetEnchantmentId(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET);}
+ uint32 GetEnchantmentDuration(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET);}
+ uint32 GetEnchantmentCharges(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot*MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET);}
void SendTimeUpdate(Player* owner);
void UpdateDuration(Player* owner, uint32 diff);
@@ -282,13 +287,12 @@ class TRINITY_DLL_SPEC Item : public Object
uState = state;
}
- bool hasQuest(uint32 quest_id) const
- {
- ItemPrototype const *itemProto = GetProto();
- return itemProto && itemProto->StartQuest == quest_id;
- }
+ bool hasQuest(uint32 quest_id) const { return GetProto()->StartQuest == quest_id; }
bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; }
-
+ bool IsPotion() const { return GetProto()->IsPotion(); }
+ bool IsWeaponVellum() const { return GetProto()->IsWeaponVellum(); }
+ bool IsArmorVellum() const { return GetProto()->IsArmorVellum(); }
+ bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); }
private:
uint8 m_slot;
Bag *m_container;
diff --git a/src/game/ItemEnchantmentMgr.cpp b/src/game/ItemEnchantmentMgr.cpp
index 3326fb56e96..b40a398a782 100644
--- a/src/game/ItemEnchantmentMgr.cpp
+++ b/src/game/ItemEnchantmentMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ void LoadRandomEnchantmentsTable()
{
RandomItemEnch.clear(); // for reload case
- EnchantmentStore::iterator tab;
+ EnchantmentStore::const_iterator tab;
uint32 entry, ench;
float chance;
uint32 count = 0;
@@ -92,7 +92,7 @@ uint32 GetItemEnchantMod(uint32 entry)
{
if (!entry) return 0;
- EnchantmentStore::iterator tab = RandomItemEnch.find(entry);
+ EnchantmentStore::const_iterator tab = RandomItemEnch.find(entry);
if (tab == RandomItemEnch.end())
{
@@ -103,7 +103,7 @@ uint32 GetItemEnchantMod(uint32 entry)
double dRoll = rand_chance();
float fCount = 0;
- for(EnchStoreList::iterator ench_iter = tab->second.begin(); ench_iter != tab->second.end(); ++ench_iter)
+ for(EnchStoreList::const_iterator ench_iter = tab->second.begin(); ench_iter != tab->second.end(); ++ench_iter)
{
fCount += ench_iter->chance;
@@ -114,7 +114,7 @@ uint32 GetItemEnchantMod(uint32 entry)
dRoll = (irand(0, (int)floor(fCount * 100) + 1)) / 100;
fCount = 0;
- for(EnchStoreList::iterator ench_iter = tab->second.begin(); ench_iter != tab->second.end(); ++ench_iter)
+ for(EnchStoreList::const_iterator ench_iter = tab->second.begin(); ench_iter != tab->second.end(); ++ench_iter)
{
fCount += ench_iter->chance;
diff --git a/src/game/ItemEnchantmentMgr.h b/src/game/ItemEnchantmentMgr.h
index 17cf634860e..ce627515aee 100644
--- a/src/game/ItemEnchantmentMgr.h
+++ b/src/game/ItemEnchantmentMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp
index 0e46115de08..3be61c80ea2 100644
--- a/src/game/ItemHandler.cpp
+++ b/src/game/ItemHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "World.h"
#include "Opcodes.h"
#include "Log.h"
#include "ObjectMgr.h"
@@ -202,7 +201,7 @@ void WorldSession::HandleAutoEquipItemOpcode( WorldPacket & recv_data )
// check dest->src move possibility
ItemPosCountVec sSrc;
- uint16 eSrc;
+ uint16 eSrc = 0;
if( _player->IsInventoryPos( src ) )
{
msg = _player->CanStoreItem( srcbag, srcslot, sSrc, pDstItem, true );
@@ -324,7 +323,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->ItemId;
data << pProto->Class;
data << pProto->SubClass;
- data << uint32(-1); // new 2.0.3, not exist in wdb cache?
+ data << int32(pProto->Unk0); // new 2.0.3, not exist in wdb cache?
data << Name;
data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name...
data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00);
@@ -346,15 +345,18 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->RequiredCityRank;
data << pProto->RequiredReputationFaction;
data << pProto->RequiredReputationRank;
- data << pProto->MaxCount;
- data << pProto->Stackable;
+ data << int32(pProto->MaxCount);
+ data << int32(pProto->Stackable);
data << pProto->ContainerSlots;
- for(int i = 0; i < 10; i++)
+ data << pProto->StatsCount; // item stats count
+ for(uint32 i = 0; i < pProto->StatsCount; ++i)
{
data << pProto->ItemStat[i].ItemStatType;
data << pProto->ItemStat[i].ItemStatValue;
}
- for(int i = 0; i < 5; i++)
+ data << pProto->ScalingStatDistribution; // scaling stats distribution
+ data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column
+ for(int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
data << pProto->Damage[i].DamageMin;
data << pProto->Damage[i].DamageMax;
@@ -374,7 +376,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->AmmoType;
data << pProto->RangedModRange;
- for(int s = 0; s < 5; s++)
+ for(int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
{
// send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
// use `item_template` or if not set then only use spell cooldowns
@@ -417,7 +419,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->PageMaterial;
data << pProto->StartQuest;
data << pProto->LockID;
- data << pProto->Material;
+ data << int32(pProto->Material);
data << pProto->Sheath;
data << pProto->RandomProperty;
data << pProto->RandomSuffix;
@@ -428,7 +430,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch
data << pProto->BagFamily;
data << pProto->TotemCategory;
- for(int s = 0; s < 3; s++)
+ for(int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
{
data << pProto->Socket[s].Color;
data << pProto->Socket[s].Content;
@@ -437,7 +439,8 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->GemProperties;
data << pProto->RequiredDisenchantSkill;
data << pProto->ArmorDamageModifier;
- data << uint32(0); // added in 2.4.2.8209, duration (seconds)
+ data << pProto->Duration; // added in 2.4.2.8209, duration (seconds)
+ data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory
SendPacket( &data );
}
else
@@ -515,7 +518,7 @@ void WorldSession::HandleSellItemOpcode( WorldPacket & recv_data )
if(!itemguid)
return;
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
@@ -525,7 +528,7 @@ void WorldSession::HandleSellItemOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
Item *pItem = _player->GetItemByGuid( itemguid );
if( pItem )
@@ -620,7 +623,7 @@ void WorldSession::HandleBuybackItem(WorldPacket & recv_data)
recv_data >> vendorguid >> slot;
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
@@ -630,7 +633,7 @@ void WorldSession::HandleBuybackItem(WorldPacket & recv_data)
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
Item *pItem = _player->GetItemFromBuyBackSlot( slot );
if( pItem )
@@ -707,7 +710,7 @@ void WorldSession::SendListInventory( uint64 vendorguid )
{
sLog.outDebug( "WORLD: Sent SMSG_LIST_INVENTORY" );
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR);
if (!pCreature)
{
sLog.outDebug( "WORLD: SendListInventory - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
@@ -717,7 +720,7 @@ void WorldSession::SendListInventory( uint64 vendorguid )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
// Stop the npc if moving
pCreature->StopMoving();
@@ -738,7 +741,7 @@ void WorldSession::SendListInventory( uint64 vendorguid )
float discountMod = _player->GetReputationPriceDiscount(pCreature);
- for(int i = 0; i < numitems; i++ )
+ for(int i = 0; i < numitems; ++i )
{
if(VendorItem const* crItem = vItems->GetItem(i))
{
@@ -824,11 +827,24 @@ void WorldSession::HandleAutoStoreBagItemOpcode( WorldPacket & recv_data )
_player->StoreItem( dest, pItem, true );
}
-void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& /*recvPacket*/)
+void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket)
{
+ CHECK_PACKET_SIZE(recvPacket, 8);
+
sLog.outDebug("WORLD: CMSG_BUY_BANK_SLOT");
- uint32 slot = _player->GetByteValue(PLAYER_BYTES_2, 2);
+ uint64 guid;
+ recvPacket >> guid;
+
+ // cheating protection
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER);
+ if(!pCreature)
+ {
+ sLog.outDebug( "WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
+ return;
+ }
+
+ uint32 slot = _player->GetBankBagSlotCount();
// next slot
++slot;
@@ -845,7 +861,8 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& /*recvPacket*/)
if (_player->GetMoney() < price)
return;
- _player->SetByteValue(PLAYER_BYTES_2, 2, slot);
+ _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT, slot);
+ _player->SetBankBagSlotCount(slot);
_player->ModifyMoney(-int32(price));
}
@@ -1106,120 +1123,193 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recv_data)
{
sLog.outDebug("WORLD: CMSG_SOCKET_GEMS");
- CHECK_PACKET_SIZE(recv_data,8*4);
-
- uint64 guids[4];
- uint32 GemEnchants[3], OldEnchants[3];
- Item *Gems[3];
- bool SocketBonusActivated, SocketBonusToBeActivated;
+ CHECK_PACKET_SIZE(recv_data,8+8*MAX_GEM_SOCKETS);
- for(int i = 0; i < 4; i++)
- recv_data >> guids[i];
+ uint64 item_guid;
+ uint64 gem_guids[MAX_GEM_SOCKETS];
- if(!guids[0])
+ recv_data >> item_guid;
+ if(!item_guid)
return;
+ for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
+ recv_data >> gem_guids[i];
+
//cheat -> tried to socket same gem multiple times
- if((guids[1] && (guids[1] == guids[2] || guids[1] == guids[3])) || (guids[2] && (guids[2] == guids[3])))
+ if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) ||
+ (gem_guids[1] && (gem_guids[1] == gem_guids[2])))
return;
- Item *itemTarget = _player->GetItemByGuid(guids[0]);
+ Item *itemTarget = _player->GetItemByGuid(item_guid);
if(!itemTarget) //missing item to socket
return;
+ ItemPrototype const* itemProto = itemTarget->GetProto();
+ if(!itemProto)
+ return;
+
//this slot is excepted when applying / removing meta gem bonus
- uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : NULL_SLOT;
+ uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT);
- for(int i = 0; i < 3; i++)
- Gems[i] = guids[i + 1] ? _player->GetItemByGuid(guids[i + 1]) : NULL;
+ Item *Gems[MAX_GEM_SOCKETS];
+ for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
+ Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL;
- GemPropertiesEntry const *GemProps[3];
- for(int i = 0; i < 3; ++i) //get geminfo from dbc storage
- {
+ GemPropertiesEntry const *GemProps[MAX_GEM_SOCKETS];
+ for(int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage
GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL;
- }
- for(int i = 0; i < 3; ++i) //check for hack maybe
+ for(int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe
{
- // tried to put gem in socket where no socket exists / tried to put normal gem in meta socket
+ if (!GemProps[i])
+ continue;
+
+ // tried to put gem in socket where no socket exists (take care about prismatic sockets)
+ if (!itemProto->Socket[i].Color)
+ {
+ // no prismatic socket
+ if(!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
+ return;
+
+ // not first not-colored (not normaly used) socket
+ if(i!=0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color))
+ return;
+
+ // ok, this is first not colored socket for item with prismatic socket
+ }
+
+ // tried to put normal gem in meta socket
+ if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META)
+ return;
+
// tried to put meta gem in normal socket
- if( GemProps[i] && ( !itemTarget->GetProto()->Socket[i].Color ||
- itemTarget->GetProto()->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META ||
- itemTarget->GetProto()->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META ) )
+ if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META)
return;
}
- for(int i = 0; i < 3; ++i) //get new and old enchantments
+ uint32 GemEnchants[MAX_GEM_SOCKETS];
+ uint32 OldEnchants[MAX_GEM_SOCKETS];
+ for(int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments
{
GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0;
OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i));
}
// check unique-equipped conditions
- for(int i = 0; i < 3; ++i)
+ for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
{
- if (Gems[i] && (Gems[i]->GetProto()->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED))
+ if(!Gems[i])
+ continue;
+
+ // continue check for case when attempt add 2 similar unique equipped gems in one item.
+ ItemPrototype const* iGemProto = Gems[i]->GetProto();
+
+ // unique item (for new and already placed bit removed enchantments
+ if (iGemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
{
- // for equipped item check all equipment for duplicate equipped gems
- if(itemTarget->IsEquipped())
+ for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
{
- if(GetPlayer()->GetItemOrItemWithGemEquipped(Gems[i]->GetEntry()))
+ if(i==j) // skip self
+ continue;
+
+ if (Gems[j])
{
- _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE, itemTarget, NULL );
- return;
+ if (iGemProto->ItemId == Gems[j]->GetEntry())
+ {
+ _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
+ return;
+ }
+ }
+ else if(OldEnchants[j])
+ {
+ if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
+ {
+ if (iGemProto->ItemId == enchantEntry->GemID)
+ {
+ _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
+ return;
+ }
+ }
}
+
}
+ }
- // continue check for case when attempt add 2 similar unique equipped gems in one item.
- for (int j = 0; j < 3; ++j)
+ // unique limit type item
+ int32 limit_newcount = 0;
+ if (iGemProto->ItemLimitCategory)
+ {
+ if(ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory))
{
- if ((i != j) && (Gems[j]) && (Gems[i]->GetProto()->ItemId == Gems[j]->GetProto()->ItemId))
+ for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
+ {
+ if (Gems[j])
+ {
+ // destroyed gem
+ if (OldEnchants[j])
+ {
+ if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
+ if(ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID))
+ if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
+ --limit_newcount;
+ }
+
+ // new gem
+ if (iGemProto->ItemLimitCategory == Gems[j]->GetProto()->ItemLimitCategory)
+ ++limit_newcount;
+ }
+ // existed gem
+ else if(OldEnchants[j])
+ {
+ if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
+ if(ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID))
+ if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
+ ++limit_newcount;
+ }
+ }
+
+ if(limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount)
{
_player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
return;
}
}
- for (int j = 0; j < 3; ++j)
- {
- if (OldEnchants[j])
- {
- SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]);
- if(!enchantEntry)
- continue;
+ }
- if ((enchantEntry->GemID == Gems[i]->GetProto()->ItemId) && (i != j))
- {
- _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
- return;
- }
- }
+ // for equipped item check all equipment for duplicate equipped gems
+ if(itemTarget->IsEquipped())
+ {
+ if(uint8 res = _player->CanEquipUniqueItem(Gems[i],slot,limit_newcount >= 0 ? limit_newcount : 0))
+ {
+ _player->SendEquipError( res, itemTarget, NULL );
+ return;
}
}
}
- SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus
+ bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus
_player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item)
//if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met
//remove ALL enchants
- for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
_player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),false);
- for(int i = 0; i < 3; ++i)
+ for(int i = 0; i < MAX_GEM_SOCKETS; ++i)
{
if(GemEnchants[i])
{
itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0);
- if(Item* guidItem = _player->GetItemByGuid(guids[i + 1]))
+ if(Item* guidItem = _player->GetItemByGuid(gem_guids[i]))
_player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true );
}
}
- for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
_player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),true);
- SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state
+ bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state
if(SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change...
{
_player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,false);
diff --git a/src/game/ItemPrototype.h b/src/game/ItemPrototype.h
index 15b01faf5a2..e7a37dc8e14 100644
--- a/src/game/ItemPrototype.h
+++ b/src/game/ItemPrototype.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,10 +57,18 @@ enum ItemModType
ITEM_MOD_CRIT_TAKEN_RATING = 34,
ITEM_MOD_RESILIENCE_RATING = 35,
ITEM_MOD_HASTE_RATING = 36,
- ITEM_MOD_EXPERTISE_RATING = 37
+ ITEM_MOD_EXPERTISE_RATING = 37,
+ ITEM_MOD_ATTACK_POWER = 38,
+ ITEM_MOD_RANGED_ATTACK_POWER = 39,
+ ITEM_MOD_FERAL_ATTACK_POWER = 40,
+ ITEM_MOD_SPELL_HEALING_DONE = 41,
+ ITEM_MOD_SPELL_DAMAGE_DONE = 42,
+ ITEM_MOD_MANA_REGENERATION = 43,
+ ITEM_MOD_ARMOR_PENETRATION_RATING = 44,
+ ITEM_MOD_SPELL_POWER = 45
};
-#define MAX_ITEM_MOD 38
+#define MAX_ITEM_MOD 46
enum ItemSpelltriggerType
{
@@ -68,6 +76,12 @@ enum ItemSpelltriggerType
ITEM_SPELLTRIGGER_ON_EQUIP = 1,
ITEM_SPELLTRIGGER_CHANCE_ON_HIT = 2,
ITEM_SPELLTRIGGER_SOULSTONE = 4,
+ /*
+ * ItemSpelltriggerType 5 might have changed on 2.4.3/3.0.3: Such auras
+ * will be applied on item pickup and removed on item loss - maybe on the
+ * other hand the item is destroyed if the aura is removed ("removed on
+ * death" of spell 57348 makes me think so)
+ */
ITEM_SPELLTRIGGER_ON_NO_DELAY_USE = 5, // no equip cooldown
ITEM_SPELLTRIGGER_LEARN_SPELL_ID = 6 // used in item_template.spell_2 with spell_id with SPELL_GENERIC_LEARN in spell_1
};
@@ -93,14 +107,17 @@ enum ITEM_FLAGS
ITEM_FLAGS_CONJURED = 0x00000002,
ITEM_FLAGS_OPENABLE = 0x00000004,
ITEM_FLAGS_WRAPPED = 0x00000008,
+ ITEM_FLAGS_BROKEN = 0x00000010, // appears red icon (like when item durability==0)
ITEM_FLAGS_WRAPPER = 0x00000200, // used or not used wrapper
ITEM_FLAGS_PARTY_LOOT = 0x00000800, // determines if item is party loot or not
ITEM_FLAGS_CHARTER = 0x00002000, // arena/guild charter
+ ITEM_FLAGS_PROSPECTABLE = 0x00040000,
ITEM_FLAGS_UNIQUE_EQUIPPED = 0x00080000,
ITEM_FLAGS_USEABLE_IN_ARENA = 0x00200000,
ITEM_FLAGS_THROWABLE = 0x00400000, // not used in game for check trow possibility, only for item in game tooltip
ITEM_FLAGS_SPECIALUSE = 0x00800000, // last used flag in 2.3.0
ITEM_FLAGS_BOA = 0x08000000, // bind on account
+ ITEM_FLAGS_TRIGGERED_CAST = 0x10000000, // used by enchanting scrolls made with vellum
ITEM_FLAGS_MILLABLE = 0x20000000
};
@@ -185,10 +202,11 @@ enum ItemClass
ITEM_CLASS_QUEST = 12,
ITEM_CLASS_KEY = 13,
ITEM_CLASS_PERMANENT = 14,
- ITEM_CLASS_JUNK = 15
+ ITEM_CLASS_MISC = 15,
+ ITEM_CLASS_GLYPH = 16
};
-#define MAX_ITEM_CLASS 16
+#define MAX_ITEM_CLASS 17
enum ItemSubclassConsumable
{
@@ -214,10 +232,11 @@ enum ItemSubclassContainer
ITEM_SUBCLASS_ENGINEERING_CONTAINER = 4,
ITEM_SUBCLASS_GEM_CONTAINER = 5,
ITEM_SUBCLASS_MINING_CONTAINER = 6,
- ITEM_SUBCLASS_LEATHERWORKING_CONTAINER = 7
+ ITEM_SUBCLASS_LEATHERWORKING_CONTAINER = 7,
+ ITEM_SUBCLASS_INSCRIPTION_CONTAINER = 8
};
-#define MAX_ITEM_SUBCLASS_CONTAINER 8
+#define MAX_ITEM_SUBCLASS_CONTAINER 9
enum ItemSubclassWeapon
{
@@ -244,6 +263,10 @@ enum ItemSubclassWeapon
ITEM_SUBCLASS_WEAPON_FISHING_POLE = 20
};
+#define ITEM_SUBCLASS_MASK_WEAPON_RANGED (\
+ (1 << ITEM_SUBCLASS_WEAPON_BOW) | (1 << ITEM_SUBCLASS_WEAPON_GUN) |\
+ (1 << ITEM_SUBCLASS_WEAPON_CROSSBOW) | (1 << ITEM_SUBCLASS_WEAPON_THROWN))
+
#define MAX_ITEM_SUBCLASS_WEAPON 21
enum ItemSubclassGem
@@ -272,10 +295,11 @@ enum ItemSubclassArmor
ITEM_SUBCLASS_ARMOR_SHIELD = 6,
ITEM_SUBCLASS_ARMOR_LIBRAM = 7,
ITEM_SUBCLASS_ARMOR_IDOL = 8,
- ITEM_SUBCLASS_ARMOR_TOTEM = 9
+ ITEM_SUBCLASS_ARMOR_TOTEM = 9,
+ ITEM_SUBCLASS_ARMOR_SIGIL = 10
};
-#define MAX_ITEM_SUBCLASS_ARMOR 10
+#define MAX_ITEM_SUBCLASS_ARMOR 11
enum ItemSubclassReagent
{
@@ -310,10 +334,12 @@ enum ItemSubclassTradeGoods
ITEM_SUBCLASS_ELEMENTAL = 10,
ITEM_SUBCLASS_TRADE_GOODS_OTHER = 11,
ITEM_SUBCLASS_ENCHANTING = 12,
- ITEM_SUBCLASS_MATERIAL = 13 // Added in 2.4.2
+ ITEM_SUBCLASS_MATERIAL = 13,
+ ITEM_SUBCLASS_ARMOR_ENCHANTMENT = 14,
+ ITEM_SUBCLASS_WEAPON_ENCHANTMENT = 15
};
-#define MAX_ITEM_SUBCLASS_TRADE_GOODS 14
+#define MAX_ITEM_SUBCLASS_TRADE_GOODS 16
enum ItemSubclassGeneric
{
@@ -423,7 +449,8 @@ const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] =
MAX_ITEM_SUBCLASS_QUEST,
MAX_ITEM_SUBCLASS_KEY,
MAX_ITEM_SUBCLASS_PERMANENT,
- MAX_ITEM_SUBCLASS_JUNK
+ MAX_ITEM_SUBCLASS_JUNK,
+ MAX_ITEM_SUBCLASS_GLYPH
};
inline uint8 ItemSubClassToDurabilityMultiplierId(uint32 ItemClass, uint32 ItemSubClass)
@@ -472,12 +499,17 @@ struct _Socket
uint32 Content;
};
+#define MAX_ITEM_PROTO_DAMAGES 5
+#define MAX_ITEM_PROTO_SOCKETS 3
+#define MAX_ITEM_PROTO_SPELLS 5
+#define MAX_ITEM_PROTO_STATS 10
+
struct ItemPrototype
{
uint32 ItemId;
uint32 Class; // id from ItemClass.dbc
uint32 SubClass; // id from ItemSubClass.dbc
- uint32 Unk0;
+ int32 Unk0;
char* Name1;
uint32 DisplayInfoID; // id from ItemDisplayInfo.dbc
uint32 Quality;
@@ -497,11 +529,14 @@ struct ItemPrototype
uint32 RequiredCityRank;
uint32 RequiredReputationFaction; // id from Faction.dbc
uint32 RequiredReputationRank;
- uint32 MaxCount;
- uint32 Stackable;
+ int32 MaxCount; // <=0: no limit
+ int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot)
uint32 ContainerSlots;
- _ItemStat ItemStat[10];
- _Damage Damage[5];
+ uint32 StatsCount;
+ _ItemStat ItemStat[MAX_ITEM_PROTO_STATS];
+ uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc
+ uint32 ScalingStatValue; // mask for selecting column in ScalingStatValues.dbc
+ _Damage Damage[MAX_ITEM_PROTO_DAMAGES];
uint32 Armor;
uint32 HolyRes;
uint32 FireRes;
@@ -512,7 +547,7 @@ struct ItemPrototype
uint32 Delay;
uint32 AmmoType;
float RangedModRange;
- _Spell Spells[5];
+ _Spell Spells[MAX_ITEM_PROTO_SPELLS];
uint32 Bonding;
char* Description;
uint32 PageText;
@@ -520,7 +555,7 @@ struct ItemPrototype
uint32 PageMaterial;
uint32 StartQuest; // id from QuestCache.wdb
uint32 LockID;
- uint32 Material; // id from Material.dbc
+ int32 Material; // id from Material.dbc
uint32 Sheath;
uint32 RandomProperty; // id from ItemRandomProperties.dbc
uint32 RandomSuffix; // id from ItemRandomSuffix.dbc
@@ -529,19 +564,20 @@ struct ItemPrototype
uint32 MaxDurability;
uint32 Area; // id from AreaTable.dbc
uint32 Map; // id from Map.dbc
- uint32 BagFamily; // id from ItemBagFamily.dbc
+ uint32 BagFamily; // bit string (1 << id from ItemBagFamily.dbc)
uint32 TotemCategory; // id from TotemCategory.dbc
- _Socket Socket[3];
+ _Socket Socket[MAX_ITEM_PROTO_SOCKETS];
uint32 socketBonus; // id from SpellItemEnchantment.dbc
uint32 GemProperties; // id from GemProperties.dbc
uint32 RequiredDisenchantSkill;
float ArmorDamageModifier;
+ int32 Duration; // negative = realtime, positive = ingame time
+ uint32 ItemLimitCategory; // id from ItemLimitCategory.dbc
uint32 ScriptId;
uint32 DisenchantID;
uint32 FoodType;
uint32 MinMoneyLoot;
uint32 MaxMoneyLoot;
- int32 Duration; // negative = realtime, positive = ingame time
// helpers
bool CanChangeEquipStateInCombat() const
@@ -563,6 +599,36 @@ struct ItemPrototype
return false;
}
+
+ uint32 GetMaxStackSize() const { return Stackable > 0 ? uint32(Stackable) : uint32(0x7FFFFFFF-1); }
+
+ float getDPS() const
+ {
+ if (Delay == 0)
+ return 0;
+ float temp = 0;
+ for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
+ temp+=Damage[i].DamageMin + Damage[i].DamageMax;
+ return temp*500/Delay;
+ }
+
+ int32 getFeralBonus(int32 extraDPS = 0) const
+ {
+ // 0x02A5F3 - is mask for Melee weapon from ItemSubClassMask.dbc
+ if (Class == ITEM_CLASS_WEAPON && (1<<SubClass)&0x02A5F3)
+ {
+ int32 bonus = int32((extraDPS + getDPS())*14.0f) - 767;
+ if (bonus < 0)
+ return 0;
+ return bonus;
+ }
+ return 0;
+ }
+
+ bool IsPotion() const { return Class==ITEM_CLASS_CONSUMABLE && SubClass==ITEM_SUBCLASS_POTION; }
+ bool IsWeaponVellum() const { return Class==ITEM_CLASS_TRADE_GOODS && SubClass==ITEM_SUBCLASS_WEAPON_ENCHANTMENT; }
+ bool IsArmorVellum() const { return Class==ITEM_CLASS_TRADE_GOODS && SubClass==ITEM_SUBCLASS_ARMOR_ENCHANTMENT; }
+ bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAGS_CONJURED); }
};
struct ItemLocale
diff --git a/src/game/LFGHandler.cpp b/src/game/LFGHandler.cpp
index 667b65327d5..85c196a9346 100644
--- a/src/game/LFGHandler.cpp
+++ b/src/game/LFGHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Language.h b/src/game/Language.h
index 03c485a4b02..2b063999951 100644
--- a/src/game/Language.h
+++ b/src/game/Language.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -84,7 +84,8 @@ enum TrinityStrings
LANG_MOTD_CURRENT = 56,
LANG_USING_WORLD_DB = 57,
LANG_USING_SCRIPT_LIB = 58,
- // Room for more level 0 59-99 not used
+ LANG_USING_EVENT_AI = 59,
+ // Room for more level 0 60-99 not used
// level 1 chat
LANG_GLOBAL_NOTIFY = 100,
@@ -95,7 +96,6 @@ enum TrinityStrings
LANG_CANNOT_GO_TO_INST_GM = 105,
LANG_CANNOT_GO_INST_INST = 106,
LANG_CANNOT_SUMMON_INST_INST = 107,
-
LANG_SUMMONING = 108,
LANG_SUMMONED_BY = 109,
LANG_TELEPORTING_TO = 110,
@@ -103,7 +103,6 @@ enum TrinityStrings
LANG_NO_PLAYER = 112,
LANG_APPEARING_AT = 113,
LANG_APPEARING_TO = 114,
-
LANG_BAD_VALUE = 115,
LANG_NO_CHAR_SELECTED = 116,
LANG_NOT_IN_GROUP = 117,
@@ -168,9 +167,12 @@ enum TrinityStrings
LANG_MAIL_SENT = 169,
LANG_SOUND_NOT_EXIST = 170,
- LANG_TELEPORTED_TO_BY_CONSOLE = 171,
+ LANG_CANT_TELEPORT_SELF = 171,
LANG_CONSOLE_COMMAND = 172,
- // Room for more level 1 173-199 not used
+ LANG_YOU_CHANGE_RUNIC_POWER = 173,
+ LANG_YOURS_RUNIC_POWER_CHANGED = 174,
+ LANG_LIQUID_STATUS = 175,
+ // Room for more level 1 176-199 not used
// level 2 chat
LANG_NO_SELECTION = 200,
@@ -264,14 +266,14 @@ enum TrinityStrings
LANG_COMMAND_ADDVENDORITEMITEMS = 280,
LANG_COMMAND_KICKSELF = 281,
LANG_COMMAND_KICKMESSAGE = 282,
- LANG_COMMAND_KICKNOTFOUNDPLAYER = 283,
+ // 283, not used
LANG_COMMAND_WHISPERACCEPTING = 284,
LANG_COMMAND_WHISPERON = 285,
LANG_COMMAND_WHISPEROFF = 286,
LANG_COMMAND_CREATGUIDNOTFOUND = 287,
- // TICKET STRINGS NEED REWRITE // 288-296 FREE
+ // TICKET STRINGS NEED REWRITE // 288-296 FREE
- // END
+ // END
LANG_COMMAND_SPAWNDIST = 297,
LANG_COMMAND_SPAWNTIME = 298,
LANG_COMMAND_MODIFY_HONOR = 299,
@@ -322,7 +324,10 @@ enum TrinityStrings
LANG_CREATURE_NOT_FOLLOW_YOU_NOW = 342,
LANG_CREATURE_NON_TAMEABLE = 343,
LANG_YOU_ALREADY_HAVE_PET = 344,
- // Room for more level 2 345-399 not used
+ LANG_CUSTOMIZE_PLAYER = 345,
+ LANG_CUSTOMIZE_PLAYER_GUID = 346,
+ LANG_COMMAND_GOTAXINODENOTFOUND = 347,
+ // Room for more level 2 348-399 not used
// level 3 chat
LANG_SCRIPTS_RELOADED = 400,
@@ -397,8 +402,7 @@ enum TrinityStrings
LANG_COMMAND_TP_ADDED = 463,
LANG_COMMAND_TP_ADDEDERR = 464,
LANG_COMMAND_TP_DELETED = 465,
- // 466, // not used
-
+ LANG_COMMAND_NOTAXINODEFOUND = 466,
LANG_COMMAND_TARGET_LISTAURAS = 467,
LANG_COMMAND_TARGET_AURADETAIL = 468,
LANG_COMMAND_TARGET_LISTAURATYPE = 469,
@@ -529,9 +533,9 @@ enum TrinityStrings
LANG_CHANGE_32BIT = 575, //log
LANG_CHANGE_32BIT_FIELD = 576,
- LANG_INVISIBLE_INVISIBLE = 577,
- LANG_INVISIBLE_VISIBLE = 578,
- LANG_SELECTED_TARGET_NOT_HAVE_VICTIM = 579,
+ LANG_INVISIBLE_INVISIBLE = 577,
+ LANG_INVISIBLE_VISIBLE = 578,
+ LANG_SELECTED_TARGET_NOT_HAVE_VICTIM = 579,
LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST = 580,
LANG_COMMAND_NEAROBJMESSAGE = 581,
@@ -561,9 +565,11 @@ enum TrinityStrings
// Battleground
LANG_BG_A_WINS = 600,
LANG_BG_H_WINS = 601,
- LANG_BG_WS_ONE_MINUTE = 602,
- LANG_BG_WS_HALF_MINUTE = 603,
- LANG_BG_WS_BEGIN = 604,
+
+ LANG_BG_WS_START_TWO_MINUTES = 753,
+ LANG_BG_WS_START_ONE_MINUTE = 602,
+ LANG_BG_WS_START_HALF_MINUTE = 603,
+ LANG_BG_WS_HAS_BEGUN = 604,
LANG_BG_WS_CAPTURED_HF = 605,
LANG_BG_WS_CAPTURED_AF = 606,
@@ -577,9 +583,10 @@ enum TrinityStrings
LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED = 614,
LANG_BG_WS_HORDE_FLAG_RESPAWNED = 615,
- LANG_BG_EY_ONE_MINUTE = 636,
- LANG_BG_EY_HALF_MINUTE = 637,
- LANG_BG_EY_BEGIN = 638,
+ LANG_BG_EY_START_TWO_MINUTES = 755,
+ LANG_BG_EY_START_ONE_MINUTE = 636,
+ LANG_BG_EY_START_HALF_MINUTE = 637,
+ LANG_BG_EY_HAS_BEGUN = 638,
LANG_BG_AB_ALLY = 650,
LANG_BG_AB_HORDE = 651,
@@ -592,9 +599,11 @@ enum TrinityStrings
LANG_BG_AB_NODE_DEFENDED = 658,
LANG_BG_AB_NODE_ASSAULTED = 659,
LANG_BG_AB_NODE_CLAIMED = 660,
- LANG_BG_AB_ONEMINTOSTART = 661,
- LANG_BG_AB_HALFMINTOSTART = 662,
- LANG_BG_AB_STARTED = 663,
+
+ LANG_BG_AB_START_TWO_MINUTES = 754,
+ LANG_BG_AB_START_ONE_MINUTE = 661,
+ LANG_BG_AB_START_HALF_MINUTE = 662,
+ LANG_BG_AB_HAS_BEGUN = 663,
LANG_BG_AB_A_NEAR_VICTORY = 664,
LANG_BG_AB_H_NEAR_VICTORY = 665,
LANG_BG_MARK_BY_MAIL = 666,
@@ -625,7 +634,7 @@ enum TrinityStrings
LANG_ARENA_ONE_MINUTE = 701,
LANG_ARENA_THIRTY_SECONDS = 702,
LANG_ARENA_FIFTEEN_SECONDS = 703,
- LANG_ARENA_BEGUN = 704,
+ LANG_ARENA_HAS_BEGUN = 704,
LANG_WAIT_BEFORE_SPEAKING = 705,
LANG_NOT_EQUIPPED_ITEM = 706,
@@ -636,77 +645,58 @@ enum TrinityStrings
LANG_BG_QUEUE_ANNOUNCE_SELF = 711,
LANG_BG_QUEUE_ANNOUNCE_WORLD = 712,
-
-
LANG_YOUR_ARENA_LEVEL_REQ_ERROR = 713,
-// LANG_HIS_ARENA_LEVEL_REQ_ERROR = 714, an opcode exists for this
+// = 714, not used
LANG_YOUR_BG_LEVEL_REQ_ERROR = 715,
-// LANG_YOUR_ARENA_TEAM_FULL = 716, an opcode exists for this
-
- LANG_BG_AV_ALLY = 717,
- LANG_BG_AV_HORDE = 718,
- LANG_BG_AV_TOWER_TAKEN = 719,
- LANG_BG_AV_TOWER_ASSAULTED = 720,
- LANG_BG_AV_TOWER_DEFENDED = 721,
- LANG_BG_AV_GRAVE_TAKEN = 722,
- LANG_BG_AV_GRAVE_DEFENDED = 723,
- LANG_BG_AV_GRAVE_ASSAULTED = 724,
-
- LANG_BG_AV_MINE_TAKEN = 725,
- LANG_BG_AV_MINE_NORTH = 726,
- LANG_BG_AV_MINE_SOUTH = 727,
-
- LANG_BG_AV_NODE_GRAVE_STORM_AID = 728,
- LANG_BG_AV_NODE_TOWER_DUN_S = 729,
- LANG_BG_AV_NODE_TOWER_DUN_N = 730,
- LANG_BG_AV_NODE_GRAVE_STORMPIKE = 731,
- LANG_BG_AV_NODE_TOWER_ICEWING = 732,
- LANG_BG_AV_NODE_GRAVE_STONE = 733,
- LANG_BG_AV_NODE_TOWER_STONE = 734,
- LANG_BG_AV_NODE_GRAVE_SNOW = 735,
- LANG_BG_AV_NODE_TOWER_ICE = 736,
- LANG_BG_AV_NODE_GRAVE_ICE = 737,
- LANG_BG_AV_NODE_TOWER_POINT = 738,
- LANG_BG_AV_NODE_GRAVE_FROST = 739,
- LANG_BG_AV_NODE_TOWER_FROST_E = 740,
- LANG_BG_AV_NODE_TOWER_FROST_W = 741,
- LANG_BG_AV_NODE_GRAVE_FROST_HUT = 742,
-
- LANG_BG_AV_ONEMINTOSTART = 743,
- LANG_BG_AV_HALFMINTOSTART = 744,
- LANG_BG_AV_STARTED = 745,
- LANG_BG_AV_A_NEAR_LOSE = 746,
- LANG_BG_AV_H_NEAR_LOSE = 747,
- LANG_BG_AV_H_CAPTAIN_DEAD = 748,
- LANG_BG_AV_A_CAPTAIN_DEAD = 749,
- LANG_NPCINFO_LINKGUID = 750,
+// = 716, not used
+ LANG_BG_STARTED_ANNOUNCE_WORLD = 717,
+ LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN= 718,
+ LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT= 719,
+
+ LANG_BG_GROUP_TOO_LARGE = 720, // "Your group is too large for this battleground. Please regroup to join."
+ LANG_ARENA_GROUP_TOO_LARGE = 721, // "Your group is too large for this arena. Please regroup to join."
+ LANG_ARENA_YOUR_TEAM_ONLY = 722, // "Your group has members not in your arena team. Please regroup to join."
+ LANG_ARENA_NOT_ENOUGH_PLAYERS = 723, // "Your group does not have enough players to join this match."
+ LANG_ARENA_GOLD_WINS = 724, // "The Gold Team wins!"
+ LANG_ARENA_GREEN_WINS = 725, // "The Green Team wins!"
+// = 726, not used
+ LANG_BG_GROUP_OFFLINE_MEMBER = 727, // "Your group has an offline member. Please remove him before joining."
+ LANG_BG_GROUP_MIXED_FACTION = 728, // "Your group has players from the opposing faction. You can't join the battleground as a group."
+ LANG_BG_GROUP_MIXED_LEVELS = 729, // "Your group has players from different battleground brakets. You can't join as group."
+ LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE = 730, // "Someone in your party is already in this battleground queue. (S)he must leave it before joining as group."
+ LANG_BG_GROUP_MEMBER_DESERTER = 731, // "Someone in your party is Deserter. You can't join as group."
+ LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS = 732, // "Someone in your party is already in three battleground queues. You cannot join as group."
+
+ LANG_CANNOT_TELE_TO_BG = 733, // "You cannot teleport to a battleground or arena map."
+ LANG_CANNOT_SUMMON_TO_BG = 734, // "You cannot summon players to a battleground or arena map."
+ LANG_CANNOT_GO_TO_BG_GM = 735, // "You must be in GM mode to teleport to a player in a battleground."
+ LANG_CANNOT_GO_TO_BG_FROM_BG = 736, // "You cannot teleport to a battleground from another battleground. Please leave the current battleground first."
+ LANG_DEBUG_ARENA_ON = 737,
+ LANG_DEBUG_ARENA_OFF = 738,
+ LANG_DEBUG_BG_ON = 739,
+ LANG_DEBUG_BG_OFF = 740,
+ LANG_DIST_ARENA_POINTS_START = 741,
+ LANG_DIST_ARENA_POINTS_ONLINE_START = 742,
+ LANG_DIST_ARENA_POINTS_ONLINE_END = 743,
+ LANG_DIST_ARENA_POINTS_TEAM_START = 744,
+ LANG_DIST_ARENA_POINTS_TEAM_END = 745,
+ LANG_DIST_ARENA_POINTS_END = 746,
+// = 747, not used
+// = 748, not used
+// = 749, not used
+ LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins."
+ LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds."
+// = 752, not used
+// LANG_BG_WS_START_TWO_MINUTES = 753, - defined above
+// LANG_BG_AB_START_TWO_MINUTES = 754, - defined above
+// LANG_BG_EY_START_TWO_MINUTES = 755, - defined above
+ // Room for batleground/arena strings 756-799 not used
// Room for BG/ARENA 751-769 not used
-
LANG_ARENA_TESTING = 785,
-
LANG_AUTO_ANN = 786,
LANG_ANNOUNCE_COLOR = 787,
- LANG_BG_GROUP_TOO_LARGE = 1122, // "Your group is too large for this battleground. Please regroup to join."
- LANG_ARENA_GROUP_TOO_LARGE = 1123, // "Your group is too large for this arena. Please regroup to join."
- LANG_ARENA_YOUR_TEAM_ONLY = 1124, // "Your group has members not in your arena team. Please regroup to join."
- LANG_ARENA_NOT_ENOUGH_PLAYERS = 1125, // "Your group does not have enough players to join this match."
- LANG_ARENA_GOLD_WINS = 1126, // "The Gold Team wins!"
- LANG_ARENA_GREEN_WINS = 1127, // "The Green Team wins!"
- LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 1128, // The battleground will end soon, because there aren't enough players. Get more ppl or win already!
- LANG_BG_GROUP_OFFLINE_MEMBER = 1129, // "Your group has an offline member. Please remove him before joining."
- LANG_BG_GROUP_MIXED_FACTION = 1130, // "Your group has players from the opposing faction. You can't join the battleground as a group."
- LANG_BG_GROUP_MIXED_LEVELS = 1131, // "Your group has players from different battleground brakets. You can't join as group."
- LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE = 1132, // "Someone in your party is already in this battleground queue. (S)he must leave it before joining as group."
- LANG_BG_GROUP_MEMBER_DESERTER = 1133, // "Someone in your party is Deserter. You can't join as group."
- LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS = 1134, // "Someone in your party is already in three battleground queues. You cannot join as group."
-
- LANG_CANNOT_TELE_TO_BG = 1135, // "You cannot teleport to a battleground or arena map."
- LANG_CANNOT_SUMMON_TO_BG = 1136, // "You cannot summon players to a battleground or arena map."
- LANG_CANNOT_GO_TO_BG_GM = 1137, // "You must be in GM mode to teleport to a player in a battleground."
- LANG_CANNOT_GO_TO_BG_FROM_BG = 1138, // "You cannot teleport to a battleground from another battleground. Please leave the current battleground first."
-
// in game strings
LANG_PET_INVALID_NAME = 800,
LANG_NOT_ENOUGH_GOLD = 801,
@@ -718,7 +708,13 @@ enum TrinityStrings
LANG_NEED_CHARACTER_NAME = 807,
LANG_PLAYER_NOT_EXIST_OR_OFFLINE = 808,
LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND = 809,
- // Room for in-game strings 810-999 not used
+ LANG_ACHIEVEMENT_EARNED = 810,
+ LANG_GUILD_MASTER = 811,
+ LANG_GUILD_OFFICER = 812,
+ LANG_GUILD_VETERAN = 813,
+ LANG_GUILD_MEMBER = 814,
+ LANG_GUILD_INITIATE = 815,
+ // Room for in-game strings 816-999 not used
// Level 4 (CLI only commands)
LANG_COMMAND_EXIT = 1000,
@@ -733,7 +729,10 @@ enum TrinityStrings
LANG_CHARACTER_DELETED = 1009,
LANG_ACCOUNT_LIST_HEADER = 1010,
LANG_ACCOUNT_LIST_ERROR = 1011,
- // Room for more level 4 1012-1099 not used
+ LANG_ACCOUNT_LIST_BAR = 1012,
+ LANG_ACCOUNT_LIST_LINE = 1013,
+ LANG_ACCOUNT_LIST_EMPTY = 1014,
+ // Room for more level 4 1015-1099 not used
// Level 3 (continue)
LANG_ACCOUNT_SETADDON = 1100,
@@ -758,6 +757,61 @@ enum TrinityStrings
LANG_MUST_MALE_OR_FEMALE = 1119,
LANG_YOU_CHANGE_GENDER = 1120,
LANG_YOUR_GENDER_CHANGED = 1121,
+ LANG_SKILL_VALUES = 1122,
+ LANG_NO_PET_FOUND = 1123,
+ LANG_WRONG_PET_TYPE = 1124,
+ LANG_COMMAND_LEARN_PET_TALENTS = 1125,
+ LANG_RESET_PET_TALENTS = 1126,
+ LANG_RESET_PET_TALENTS_ONLINE = 1127,
+ LANG_TAXINODE_ENTRY_LIST_CHAT = 1128,
+ LANG_TAXINODE_ENTRY_LIST_CONSOLE = 1129,
+ // Room for more level 3 1130-1199 not used
+
+ // Debug commands
+ LANG_CINEMATIC_NOT_EXIST = 1200,
+ LANG_MOVIE_NOT_EXIST = 1201,
+ // Room for more debug 1202-1299 not used
+
+ // FREE IDS 1300-9999
+
+ // AV
+ LANG_BG_AV_ALLY = 1300,
+ LANG_BG_AV_HORDE = 1301,
+ LANG_BG_AV_TOWER_TAKEN = 1302,
+ LANG_BG_AV_TOWER_ASSAULTED = 1303,
+ LANG_BG_AV_TOWER_DEFENDED = 1304,
+ LANG_BG_AV_GRAVE_TAKEN = 1305,
+ LANG_BG_AV_GRAVE_DEFENDED = 1306,
+ LANG_BG_AV_GRAVE_ASSAULTED = 1307,
+
+ LANG_BG_AV_MINE_TAKEN = 1308,
+ LANG_BG_AV_MINE_NORTH = 1309,
+ LANG_BG_AV_MINE_SOUTH = 1310,
+
+ LANG_BG_AV_NODE_GRAVE_STORM_AID = 1311,
+ LANG_BG_AV_NODE_TOWER_DUN_S = 1312,
+ LANG_BG_AV_NODE_TOWER_DUN_N = 1313,
+ LANG_BG_AV_NODE_GRAVE_STORMPIKE = 1314,
+ LANG_BG_AV_NODE_TOWER_ICEWING = 1315,
+ LANG_BG_AV_NODE_GRAVE_STONE = 1316,
+ LANG_BG_AV_NODE_TOWER_STONE = 1317,
+ LANG_BG_AV_NODE_GRAVE_SNOW = 1318,
+ LANG_BG_AV_NODE_TOWER_ICE = 1319,
+ LANG_BG_AV_NODE_GRAVE_ICE = 1320,
+ LANG_BG_AV_NODE_TOWER_POINT = 1321,
+ LANG_BG_AV_NODE_GRAVE_FROST = 1322,
+ LANG_BG_AV_NODE_TOWER_FROST_E = 1323,
+ LANG_BG_AV_NODE_TOWER_FROST_W = 1324,
+ LANG_BG_AV_NODE_GRAVE_FROST_HUT = 1325,
+
+ LANG_BG_AV_ONEMINTOSTART = 1326,
+ LANG_BG_AV_HALFMINTOSTART = 1327,
+ LANG_BG_AV_STARTED = 1328,
+ LANG_BG_AV_A_NEAR_LOSE = 1329,
+ LANG_BG_AV_H_NEAR_LOSE = 1330,
+ LANG_BG_AV_H_CAPTAIN_DEAD = 1331,
+ LANG_BG_AV_A_CAPTAIN_DEAD = 1332,
+ // FREE IDS 1333-1999
// Ticket Strings 2000-2029
LANG_COMMAND_TICKETNEW = 2000,
@@ -787,7 +841,7 @@ enum TrinityStrings
LANG_COMMAND_TICKETLISTADDCOMMENT = 2024,
LANG_COMMAND_TICKETLISTAGECREATE = 2025,
- // Trinity strings 5000-9999
+ // Trinity strings 5000-9999
LANG_COMMAND_FREEZE = 5000,
LANG_COMMAND_FREEZE_ERROR = 5001,
LANG_COMMAND_FREEZE_WRONG = 5002,
@@ -795,14 +849,21 @@ enum TrinityStrings
LANG_COMMAND_NO_FROZEN_PLAYERS = 5004,
LANG_COMMAND_LIST_FREEZE = 5005,
LANG_COMMAND_FROZEN_PLAYERS = 5006,
- LANG_INSTANCE_MUST_RAID_GRP = 5007,
- LANG_INSTANCE_NOT_AS_GHOST = 5008,
+ LANG_INSTANCE_RAID_GROUP_ONLY = 5007,
+ //LANG_INSTANCE_NOT_AS_GHOST = 5008,
LANG_COMMAND_PLAYED_TO_ALL = 5009,
- // Room for more Trinity strings 5010-9999
+ LANG_NPCINFO_LINKGUID = 5010,
+ LANG_TELEPORTED_TO_BY_CONSOLE = 5011,
+ // Room for more Trinity strings 5012-9999
// Used for GM Announcements
LANG_GM_BROADCAST = 6613,
LANG_GM_NOTIFY = 6614,
LANG_GM_ANNOUNCE_COLOR = 6615,
+ LANG_RESETALL_PET_SPELLS = 6616,
+
+ LANG_WORLD_CLOSED = 7523,
+ LANG_WORLD_OPENED = 7524,
+
// Use for not-in-offcial-sources patches
// 10000-10999
@@ -868,9 +929,7 @@ enum TrinityStrings
LANG_OPVP_EP_FLIGHT_CGT = 10053,
LANG_OPVP_ZM_GOSSIP_ALLIANCE = 10054,
LANG_OPVP_ZM_GOSSIP_HORDE = 10055,
- LANG_NO_ENTER_HALL_OF_LEGENDS = 10056,
- LANG_NO_ENTER_CHAMPIONS_HALL = 10057,
-
+
// Use for custom patches 11000-11999
// NOT RESERVED IDS 12000-1999999999
diff --git a/src/game/Level0.cpp b/src/game/Level0.cpp
index 62aa5d41709..c4f6935bced 100644
--- a/src/game/Level0.cpp
+++ b/src/game/Level0.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,13 +20,10 @@
#include "Common.h"
#include "Database/DatabaseEnv.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
#include "World.h"
#include "Player.h"
#include "Opcodes.h"
#include "Chat.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Language.h"
#include "AccountMgr.h"
@@ -59,8 +56,8 @@ bool ChatHandler::HandleCommandsCommand(const char* args)
bool ChatHandler::HandleAccountCommand(const char* /*args*/)
{
- uint32 gmlevel = m_session->GetSecurity();
- PSendSysMessage(LANG_ACCOUNT_LEVEL, gmlevel);
+ AccountTypes gmlevel = m_session->GetSecurity();
+ PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmlevel));
return true;
}
@@ -105,6 +102,7 @@ bool ChatHandler::HandleServerInfoCommand(const char* /*args*/)
//SendSysMessage(full);
//PSendSysMessage(LANG_USING_SCRIPT_LIB,sWorld.GetScriptsVersion());
//PSendSysMessage(LANG_USING_WORLD_DB,sWorld.GetDBVersion());
+ //PSendSysMessage(LANG_USING_EVENT_AI,sWorld.GetCreatureEventAIVersion());
PSendSysMessage(LANG_CONNECTED_USERS, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum);
PSendSysMessage(LANG_UPTIME, str.c_str());
PSendSysMessage("Update time diff: %u.", updateTime);
@@ -130,7 +128,7 @@ bool ChatHandler::HandleDismountCommand(const char* /*args*/)
}
m_session->GetPlayer()->Unmount();
- m_session->GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+ m_session->GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED);
return true;
}
@@ -139,7 +137,7 @@ bool ChatHandler::HandleSaveCommand(const char* /*args*/)
Player *player=m_session->GetPlayer();
// save GM account without delay and output message (testing, etc)
- if(m_session->GetSecurity())
+ if(m_session->GetSecurity() > SEC_PLAYER)
{
player->SaveToDB();
SendSysMessage(LANG_PLAYER_SAVED);
@@ -148,7 +146,7 @@ bool ChatHandler::HandleSaveCommand(const char* /*args*/)
// save or plan save after 20 sec (logout delay) if current next save time more this value and _not_ output any messages to prevent cheat planning
uint32 save_interval = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
- if(save_interval==0 || save_interval > 20*1000 && player->GetSaveTimer() <= save_interval - 20*1000)
+ if(save_interval==0 || save_interval > 20*IN_MILISECONDS && player->GetSaveTimer() <= save_interval - 20*IN_MILISECONDS)
player->SaveToDB();
return true;
@@ -159,10 +157,10 @@ bool ChatHandler::HandleGMListIngameCommand(const char* /*args*/)
bool first = true;
HashMapHolder<Player>::MapType &m = HashMapHolder<Player>::GetContainer();
- HashMapHolder<Player>::MapType::iterator itr = m.begin();
+ HashMapHolder<Player>::MapType::const_iterator itr = m.begin();
for(; itr != m.end(); ++itr)
{
- if (itr->second->GetSession()->GetSecurity() &&
+ if (itr->second->GetSession()->GetSecurity() > SEC_PLAYER &&
(itr->second->isGameMaster() || sWorld.getConfig(CONFIG_GM_IN_GM_LIST)) &&
(!m_session || itr->second->IsVisibleGloballyFor(m_session->GetPlayer())) )
{
@@ -172,7 +170,7 @@ bool ChatHandler::HandleGMListIngameCommand(const char* /*args*/)
first = false;
}
- SendSysMessage(itr->second->GetName());
+ SendSysMessage(GetNameLink(itr->second).c_str());
}
}
@@ -182,7 +180,7 @@ bool ChatHandler::HandleGMListIngameCommand(const char* /*args*/)
return true;
}
-bool ChatHandler::HandlePasswordCommand(const char* args)
+bool ChatHandler::HandleAccountPasswordCommand(const char* args)
{
if(!*args)
return false;
@@ -233,7 +231,7 @@ bool ChatHandler::HandlePasswordCommand(const char* args)
return true;
}
-bool ChatHandler::HandleLockAccountCommand(const char* args)
+bool ChatHandler::HandleAccountLockCommand(const char* args)
{
if (!*args)
{
diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp
index 1966bf6aa51..5dba3ce5063 100644
--- a/src/game/Level1.cpp
+++ b/src/game/Level1.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
#include "VMapFactory.h"
#endif
+//-----------------------Npc Commands-----------------------
bool ChatHandler::HandleNpcSayCommand(const char* args)
{
if(!*args)
@@ -53,7 +54,7 @@ bool ChatHandler::HandleNpcSayCommand(const char* args)
return false;
}
- pCreature->Say(args, LANG_UNIVERSAL, 0);
+ pCreature->MonsterSay(args, LANG_UNIVERSAL, 0);
return true;
}
@@ -71,7 +72,7 @@ bool ChatHandler::HandleNpcYellCommand(const char* args)
return false;
}
- pCreature->Yell(args, LANG_UNIVERSAL, 0);
+ pCreature->MonsterYell(args, LANG_UNIVERSAL, 0);
return true;
}
@@ -91,7 +92,7 @@ bool ChatHandler::HandleNpcTextEmoteCommand(const char* args)
return false;
}
- pCreature->TextEmote(args, 0);
+ pCreature->MonsterTextEmote(args, 0);
return true;
}
@@ -106,7 +107,7 @@ bool ChatHandler::HandleNpcWhisperCommand(const char* args)
char* text = strtok(NULL, "");
uint64 guid = m_session->GetPlayer()->GetSelection();
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
+ Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(guid);
if(!pCreature || !receiver_str || !text)
{
@@ -115,18 +116,22 @@ bool ChatHandler::HandleNpcWhisperCommand(const char* args)
uint64 receiver_guid= atol(receiver_str);
- pCreature->Whisper(text,receiver_guid);
+ // check online security
+ if (HasLowerSecurity(objmgr.GetPlayer(receiver_guid), 0))
+ return false;
+
+ pCreature->MonsterWhisper(text,receiver_guid);
return true;
}
+//----------------------------------------------------------
bool ChatHandler::HandleNameAnnounceCommand(const char* args)
{
WorldPacket data;
if(!*args)
return false;
- //char str[1024];
- //sprintf(str, GetTrinityString(LANG_ANNOUNCE_COLOR), m_session->GetPlayer()->GetName(), args);
+
sWorld.SendWorldText(LANG_ANNOUNCE_COLOR, m_session->GetPlayer()->GetName(), args);
return true;
}
@@ -194,7 +199,7 @@ bool ChatHandler::HandleGMNotifyCommand(const char* args)
}
//Enable\Dissable GM Mode
-bool ChatHandler::HandleGMmodeCommand(const char* args)
+bool ChatHandler::HandleGMCommand(const char* args)
{
if(!*args)
{
@@ -627,7 +632,7 @@ bool ChatHandler::HandleGMTicketReloadCommand(const char*)
}
//Enable\Dissable Invisible mode
-bool ChatHandler::HandleVisibleCommand(const char* args)
+bool ChatHandler::HandleGMVisibleCommand(const char* args)
{
if (!*args)
{
@@ -656,14 +661,16 @@ bool ChatHandler::HandleVisibleCommand(const char* args)
return false;
}
+
+
bool ChatHandler::HandleGPSCommand(const char* args)
{
WorldObject *obj = NULL;
if (*args)
{
- std::string name = args;
- if(normalizePlayerName(name))
- obj = objmgr.GetPlayer(name.c_str());
+ uint64 guid = extractGuidFromLink((char*)args);
+ if(guid)
+ obj = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*m_session->GetPlayer(),guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
if(!obj)
{
@@ -686,8 +693,8 @@ bool ChatHandler::HandleGPSCommand(const char* args)
CellPair cell_val = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
Cell cell(cell_val);
- uint32 zone_id = obj->GetZoneId();
- uint32 area_id = obj->GetAreaId();
+ uint32 zone_id, area_id;
+ obj->GetZoneAndAreaId(zone_id,area_id);
MapEntry const* mapEntry = sMapStore.LookupEntry(obj->GetMapId());
AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zone_id);
@@ -711,107 +718,142 @@ bool ChatHandler::HandleGPSCommand(const char* args)
uint32 have_vmap = Map::ExistVMap(obj->GetMapId(),gx,gy) ? 1 : 0;
PSendSysMessage(LANG_MAP_POSITION,
- obj->GetMapId(), (mapEntry ? mapEntry->name[m_session->GetSessionDbcLocale()] : "<unknown>" ),
- zone_id, (zoneEntry ? zoneEntry->area_name[m_session->GetSessionDbcLocale()] : "<unknown>" ),
- area_id, (areaEntry ? areaEntry->area_name[m_session->GetSessionDbcLocale()] : "<unknown>" ),
+ obj->GetMapId(), (mapEntry ? mapEntry->name[GetSessionDbcLocale()] : "<unknown>" ),
+ zone_id, (zoneEntry ? zoneEntry->area_name[GetSessionDbcLocale()] : "<unknown>" ),
+ area_id, (areaEntry ? areaEntry->area_name[GetSessionDbcLocale()] : "<unknown>" ),
+ obj->GetPhaseMask(),
obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(),
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(),
zone_x, zone_y, ground_z, floor_z, have_map, have_vmap );
sLog.outDebug("Player %s GPS call for %s '%s' (%s: %u):",
- GetName(),
+ m_session ? GetNameLink().c_str() : GetMangosString(LANG_CONSOLE_COMMAND),
(obj->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), obj->GetName(),
(obj->GetTypeId() == TYPEID_PLAYER ? "GUID" : "Entry"), (obj->GetTypeId() == TYPEID_PLAYER ? obj->GetGUIDLow(): obj->GetEntry()) );
sLog.outDebug(GetTrinityString(LANG_MAP_POSITION),
obj->GetMapId(), (mapEntry ? mapEntry->name[sWorld.GetDefaultDbcLocale()] : "<unknown>" ),
zone_id, (zoneEntry ? zoneEntry->area_name[sWorld.GetDefaultDbcLocale()] : "<unknown>" ),
area_id, (areaEntry ? areaEntry->area_name[sWorld.GetDefaultDbcLocale()] : "<unknown>" ),
+ obj->GetPhaseMask(),
obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(),
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(),
zone_x, zone_y, ground_z, floor_z, have_map, have_vmap );
+ LiquidData liquid_status;
+ ZLiquidStatus res = map->getLiquidStatus(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), MAP_ALL_LIQUIDS, &liquid_status);
+ if (res)
+ {
+ PSendSysMessage(LANG_LIQUID_STATUS, liquid_status.level, liquid_status.depth_level, liquid_status.type, res);
+ }
return true;
}
//Summon Player
bool ChatHandler::HandleNamegoCommand(const char* args)
{
- if(!*args)
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
- std::string name = args;
-
- if(!normalizePlayerName(name))
+ Player* _player = m_session->GetPlayer();
+ if (target == _player || target_guid == _player->GetGUID())
{
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ PSendSysMessage(LANG_CANT_TELEPORT_SELF);
SetSentErrorMessage(true);
return false;
}
- Player *chr = objmgr.GetPlayer(name.c_str());
- if (chr)
+ if (target)
{
- if(chr->IsBeingTeleported()==true)
+ std::string nameLink = playerLink(target_name);
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
+ if (target->IsBeingTeleported())
{
- PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName());
+ PSendSysMessage(LANG_IS_TELEPORTED, nameLink.c_str());
SetSentErrorMessage(true);
return false;
}
Map* pMap = m_session->GetPlayer()->GetMap();
- if(pMap->IsBattleGroundOrArena())
+ if (pMap->IsBattleGroundOrArena())
{
- // cannot summon to bg
- PSendSysMessage(LANG_CANNOT_SUMMON_TO_BG,chr->GetName());
- SetSentErrorMessage(true);
- return false;
+ // only allow if gm mode is on
+ if (!target->isGameMaster())
+ {
+ PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM,nameLink.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ }
+ // if both players are in different bgs
+ else if (target->GetBattleGroundId() && m_session->GetPlayer()->GetBattleGroundId() != target->GetBattleGroundId())
+ {
+ PSendSysMessage(LANG_CANNOT_GO_TO_BG_FROM_BG,nameLink.c_str());
+ SetSentErrorMessage(true);
+ return false;
+ }
+ // all's well, set bg id
+ // when porting out from the bg, it will be reset to 0
+ target->SetBattleGroundId(m_session->GetPlayer()->GetBattleGroundId(), m_session->GetPlayer()->GetBattleGroundTypeId());
+ // remember current position as entry point for return at bg end teleportation
+ target->SetBattleGroundEntryPoint(target->GetMapId(),target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(),target->GetOrientation());
}
- else if(pMap->IsDungeon())
+ else if (pMap->IsDungeon())
{
- Map* cMap = chr->GetMap();
- if( cMap->Instanceable() && cMap->GetInstanceId() != pMap->GetInstanceId() )
+ Map* cMap = target->GetMap();
+ if (cMap->Instanceable() && cMap->GetInstanceId() != pMap->GetInstanceId())
{
// cannot summon from instance to instance
- PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,chr->GetName());
+ PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,nameLink.c_str());
SetSentErrorMessage(true);
return false;
}
// we are in instance, and can summon only player in our group with us as lead
- if ( !m_session->GetPlayer()->GetGroup() || !chr->GetGroup() ||
- (chr->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) ||
- (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) )
+ if (!m_session->GetPlayer()->GetGroup() || !target->GetGroup() ||
+ (target->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) ||
+ (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()))
// the last check is a bit excessive, but let it be, just in case
{
- PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,chr->GetName());
+ PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,nameLink.c_str());
SetSentErrorMessage(true);
return false;
}
}
- PSendSysMessage(LANG_SUMMONING, chr->GetName(),"");
- if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_SUMMONED_BY, GetName());
+ PSendSysMessage(LANG_SUMMONING, nameLink.c_str(),"");
+ if (needReportToTarget(target))
+ ChatHandler(target).PSendSysMessage(LANG_SUMMONED_BY, nameLink.c_str());
// stop flight if need
- if(chr->isInFlight())
+ if (target->isInFlight())
{
- chr->GetMotionMaster()->MovementExpired();
- chr->m_taxi.ClearTaxiDestinations();
+ target->GetMotionMaster()->MovementExpired();
+ target->m_taxi.ClearTaxiDestinations();
}
// save only in non-flight case
else
- chr->SaveRecallPosition();
+ target->SaveRecallPosition();
// before GM
float x,y,z;
- m_session->GetPlayer()->GetClosePoint(x,y,z,chr->GetObjectSize());
- chr->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,chr->GetOrientation());
+ m_session->GetPlayer()->GetClosePoint(x,y,z,target->GetObjectSize());
+ target->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,target->GetOrientation());
}
- else if (uint64 guid = objmgr.GetPlayerGUIDByName(name))
+ else
{
- PSendSysMessage(LANG_SUMMONING, name.c_str(),GetTrinityString(LANG_OFFLINE));
+ // check offline security
+ if (HasLowerSecurity(NULL, target_guid))
+ return false;
+
+ std::string nameLink = playerLink(target_name);
+
+ PSendSysMessage(LANG_SUMMONING, nameLink.c_str(),GetTrinityString(LANG_OFFLINE));
// in point where GM stay
Player::SavePositionInDB(m_session->GetPlayer()->GetMapId(),
@@ -820,12 +862,7 @@ bool ChatHandler::HandleNamegoCommand(const char* args)
m_session->GetPlayer()->GetPositionZ(),
m_session->GetPlayer()->GetOrientation(),
m_session->GetPlayer()->GetZoneId(),
- guid);
- }
- else
- {
- PSendSysMessage(LANG_NO_PLAYER, args);
- SetSentErrorMessage(true);
+ target_guid);
}
return true;
@@ -834,43 +871,51 @@ bool ChatHandler::HandleNamegoCommand(const char* args)
//Teleport to Player
bool ChatHandler::HandleGonameCommand(const char* args)
{
- if(!*args)
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
Player* _player = m_session->GetPlayer();
-
- std::string name = args;
-
- if(!normalizePlayerName(name))
+ if (target == _player || target_guid == _player->GetGUID())
{
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SendSysMessage(LANG_CANT_TELEPORT_SELF);
SetSentErrorMessage(true);
return false;
}
- Player *chr = objmgr.GetPlayer(name.c_str());
- if (chr)
+
+ if (target)
{
- Map* cMap = chr->GetMap();
- if(cMap->IsBattleGroundOrArena())
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
+ std::string chrNameLink = playerLink(target_name);
+
+ Map* cMap = target->GetMap();
+ if (cMap->IsBattleGroundOrArena())
{
// only allow if gm mode is on
if (!_player->isGameMaster())
{
- PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM,chr->GetName());
+ PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM,chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
- // if already in a bg, don't let port to other
- else if (_player->GetBattleGroundId())
+ // if both players are in different bgs
+ else if (_player->GetBattleGroundId() && _player->GetBattleGroundId() != target->GetBattleGroundId())
{
- PSendSysMessage(LANG_CANNOT_GO_TO_BG_FROM_BG,chr->GetName());
+ PSendSysMessage(LANG_CANNOT_GO_TO_BG_FROM_BG,chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
// all's well, set bg id
// when porting out from the bg, it will be reset to 0
- _player->SetBattleGroundId(chr->GetBattleGroundId());
+ _player->SetBattleGroundId(target->GetBattleGroundId(), target->GetBattleGroundTypeId());
+ // remember current position as entry point for return at bg end teleportation
+ _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
}
else if(cMap->IsDungeon())
{
@@ -882,9 +927,9 @@ bool ChatHandler::HandleGonameCommand(const char* args)
if (_player->GetGroup())
{
// we are in group, we can go only if we are in the player group
- if (_player->GetGroup() != chr->GetGroup())
+ if (_player->GetGroup() != target->GetGroup())
{
- PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY,chr->GetName());
+ PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY,chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
@@ -894,7 +939,7 @@ bool ChatHandler::HandleGonameCommand(const char* args)
// we are not in group, let's verify our GM mode
if (!_player->isGameMaster())
{
- PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM,chr->GetName());
+ PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM,chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
@@ -902,29 +947,27 @@ bool ChatHandler::HandleGonameCommand(const char* args)
// if the player or the player's group is bound to another instance
// the player will not be bound to another one
- InstancePlayerBind *pBind = _player->GetBoundInstance(chr->GetMapId(), chr->GetDifficulty());
- if(!pBind)
+ InstancePlayerBind *pBind = _player->GetBoundInstance(target->GetMapId(), target->GetDifficulty());
+ if (!pBind)
{
Group *group = _player->GetGroup();
- InstanceGroupBind *gBind = group ? group->GetBoundInstance(chr->GetMapId(), chr->GetDifficulty()) : NULL;
- if(!gBind)
- {
- // if no bind exists, create a solo bind
- InstanceSave *save = sInstanceSaveManager.GetInstanceSave(chr->GetInstanceId());
- if(save) _player->BindToInstance(save, !save->CanReset());
- }
+ // if no bind exists, create a solo bind
+ InstanceGroupBind *gBind = group ? group->GetBoundInstance(target->GetMapId(), target->GetDifficulty()) : NULL;
+ // if no bind exists, create a solo bind
+ if (!gBind)
+ if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(target->GetInstanceId()))
+ _player->BindToInstance(save, !save->CanReset());
}
- _player->SetDifficulty(chr->GetDifficulty());
+ _player->SetDifficulty(target->GetDifficulty());
}
- PSendSysMessage(LANG_APPEARING_AT, chr->GetName());
-
- if (_player->IsVisibleGloballyFor(chr))
- ChatHandler(chr).PSendSysMessage(LANG_APPEARING_TO, _player->GetName());
+ PSendSysMessage(LANG_APPEARING_AT, chrNameLink.c_str());
+ if (needReportToTarget(target))
+ ChatHandler(target).PSendSysMessage(LANG_APPEARING_TO, GetNameLink().c_str());
// stop flight if need
- if(_player->isInFlight())
+ if (_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
_player->m_taxi.ClearTaxiDestinations();
@@ -935,91 +978,69 @@ bool ChatHandler::HandleGonameCommand(const char* args)
// to point to see at target with same orientation
float x,y,z;
- chr->GetContactPoint(m_session->GetPlayer(),x,y,z);
-
- _player->TeleportTo(chr->GetMapId(), x, y, z, _player->GetAngle( chr ), TELE_TO_GM_MODE);
+ target->GetContactPoint(_player,x,y,z);
- return true;
+ _player->TeleportTo(target->GetMapId(), x, y, z, _player->GetAngle(target), TELE_TO_GM_MODE);
}
-
- if (uint64 guid = objmgr.GetPlayerGUIDByName(name))
+ else
{
- PSendSysMessage(LANG_APPEARING_AT, name.c_str());
+ // check offline security
+ if (HasLowerSecurity(NULL, target_guid))
+ return false;
+
+ std::string nameLink = playerLink(target_name);
+
+ PSendSysMessage(LANG_APPEARING_AT, nameLink.c_str());
// to point where player stay (if loaded)
float x,y,z,o;
uint32 map;
bool in_flight;
- if(Player::LoadPositionFromDB(map,x,y,z,o,in_flight,guid))
- {
- // stop flight if need
- if(_player->isInFlight())
- {
- _player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
- }
- // save only in non-flight case
- else
- _player->SaveRecallPosition();
+ if (!Player::LoadPositionFromDB(map,x,y,z,o,in_flight,target_guid))
+ return false;
- _player->TeleportTo(map, x, y, z,_player->GetOrientation());
- return true;
+ // stop flight if need
+ if (_player->isInFlight())
+ {
+ _player->GetMotionMaster()->MovementExpired();
+ _player->m_taxi.ClearTaxiDestinations();
}
- }
+ // save only in non-flight case
+ else
+ _player->SaveRecallPosition();
- PSendSysMessage(LANG_NO_PLAYER, args);
+ _player->TeleportTo(map, x, y, z,_player->GetOrientation());
+ }
- SetSentErrorMessage(true);
- return false;
+ return true;
}
// Teleport player to last position
bool ChatHandler::HandleRecallCommand(const char* args)
{
- Player* chr = NULL;
-
- if(!*args)
- {
- chr = getSelectedPlayer();
- if(!chr)
- chr = m_session->GetPlayer();
- }
- else
- {
- std::string name = args;
-
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- chr = objmgr.GetPlayer(name.c_str());
+ Player* target;
+ if(!extractPlayerTarget((char*)args,&target))
+ return false;
- if(!chr)
- {
- PSendSysMessage(LANG_NO_PLAYER, args);
- SetSentErrorMessage(true);
- return false;
- }
- }
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
- if(chr->IsBeingTeleported())
+ if (target->IsBeingTeleported())
{
- PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName());
+ PSendSysMessage(LANG_IS_TELEPORTED, GetNameLink(target).c_str());
SetSentErrorMessage(true);
return false;
}
// stop flight if need
- if(chr->isInFlight())
+ if(target->isInFlight())
{
- chr->GetMotionMaster()->MovementExpired();
- chr->m_taxi.ClearTaxiDestinations();
+ target->GetMotionMaster()->MovementExpired();
+ target->m_taxi.ClearTaxiDestinations();
}
- chr->TeleportTo(chr->m_recallMap, chr->m_recallX, chr->m_recallY, chr->m_recallZ, chr->m_recallO);
+ target->TeleportTo(target->m_recallMap, target->m_recallX, target->m_recallY, target->m_recallZ, target->m_recallO);
return true;
}
@@ -1041,6 +1062,10 @@ bool ChatHandler::HandleModifyKnownTitlesCommand(const char* args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
uint64 titles2 = titles;
for(int i=1; i < sCharTitlesStore.GetNumRows(); ++i)
@@ -1090,9 +1115,13 @@ bool ChatHandler::HandleModifyHPCommand(const char* args)
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_HP, chr->GetName(), hp, hpm);
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ PSendSysMessage(LANG_YOU_CHANGE_HP, GetNameLink(chr).c_str(), hp, hpm);
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_HP_CHANGED, GetName(), hp, hpm);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_HP_CHANGED, GetNameLink().c_str(), hp, hpm);
chr->SetMaxHealth( hpm );
chr->SetHealth( hp );
@@ -1134,9 +1163,13 @@ bool ChatHandler::HandleModifyManaCommand(const char* args)
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_MANA, chr->GetName(), mana, manam);
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ PSendSysMessage(LANG_YOU_CHANGE_MANA, GetNameLink(chr).c_str(), mana, manam);
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_MANA_CHANGED, GetName(), mana, manam);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_MANA_CHANGED, GetNameLink().c_str(), mana, manam);
chr->SetMaxPower(POWER_MANA,manam );
chr->SetPower(POWER_MANA, mana );
@@ -1179,9 +1212,13 @@ bool ChatHandler::HandleModifyEnergyCommand(const char* args)
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_ENERGY, chr->GetName(), energy/10, energym/10);
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ PSendSysMessage(LANG_YOU_CHANGE_ENERGY, GetNameLink(chr).c_str(), energy/10, energym/10);
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, GetName(), energy/10, energym/10);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, GetNameLink().c_str(), energy/10, energym/10);
chr->SetMaxPower(POWER_ENERGY,energym );
chr->SetPower(POWER_ENERGY, energy );
@@ -1226,9 +1263,13 @@ bool ChatHandler::HandleModifyRageCommand(const char* args)
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_RAGE, chr->GetName(), rage/10, ragem/10);
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ PSendSysMessage(LANG_YOU_CHANGE_RAGE, GetNameLink(chr).c_str(), rage/10, ragem/10);
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_RAGE_CHANGED, GetName(), rage/10, ragem/10);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_RAGE_CHANGED, GetNameLink().c_str(), rage/10, ragem/10);
chr->SetMaxPower(POWER_RAGE,ragem );
chr->SetPower(POWER_RAGE, rage );
@@ -1236,6 +1277,40 @@ bool ChatHandler::HandleModifyRageCommand(const char* args)
return true;
}
+// Edit Player Runic Power
+bool ChatHandler::HandleModifyRunicPowerCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ int32 rune = atoi((char*)args)*10;
+ int32 runem = atoi((char*)args)*10;
+
+ if (rune <= 0 || runem <= 0 || runem < rune)
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Player *chr = getSelectedPlayer();
+ if (chr == NULL)
+ {
+ SendSysMessage(LANG_NO_CHAR_SELECTED);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ PSendSysMessage(LANG_YOU_CHANGE_RUNIC_POWER, GetNameLink(chr).c_str(), rune/10, runem/10);
+ if (needReportToTarget(chr))
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_RUNIC_POWER_CHANGED, GetNameLink().c_str(), rune/10, runem/10);
+
+ chr->SetMaxPower(POWER_RUNIC_POWER,runem );
+ chr->SetPower(POWER_RUNIC_POWER, rune );
+
+ return true;
+}
+
//Edit Player Faction
bool ChatHandler::HandleModifyFactionCommand(const char* args)
{
@@ -1350,9 +1425,13 @@ bool ChatHandler::HandleModifySpellCommand(const char* args)
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_SPELLFLATID, spellflatid, val, mark, chr->GetName());
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ PSendSysMessage(LANG_YOU_CHANGE_SPELLFLATID, spellflatid, val, mark, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPELLFLATID_CHANGED, GetName(), spellflatid, val, mark);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPELLFLATID_CHANGED, GetNameLink().c_str(), spellflatid, val, mark);
WorldPacket data(SMSG_SET_FLAT_SPELL_MODIFIER, (1+1+2+2));
data << uint8(spellflatid);
@@ -1380,6 +1459,11 @@ bool ChatHandler::HandleModifyTalentCommand (const char* args)
SetSentErrorMessage(true);
return false;
}
+
+ // check online security
+ if (HasLowerSecurity(player, 0))
+ return false;
+
player->SetFreeTalentPoints(tp);
return true;
}
@@ -1404,21 +1488,25 @@ bool ChatHandler::HandleTaxiCheatCommand(const char* args)
chr=m_session->GetPlayer();
}
+ // check online security
+ else if (HasLowerSecurity(chr, 0))
+ return false;
+
if (argstr == "on")
{
chr->SetTaxiCheater(true);
- PSendSysMessage(LANG_YOU_GIVE_TAXIS, chr->GetName());
+ PSendSysMessage(LANG_YOU_GIVE_TAXIS, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_ADDED, GetName());
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_ADDED, GetNameLink().c_str());
return true;
}
if (argstr == "off")
{
chr->SetTaxiCheater(false);
- PSendSysMessage(LANG_YOU_REMOVE_TAXIS, chr->GetName());
+ PSendSysMessage(LANG_YOU_REMOVE_TAXIS, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_REMOVED, GetName());
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_REMOVED, GetNameLink().c_str());
return true;
}
@@ -1451,16 +1539,22 @@ bool ChatHandler::HandleModifyASpeedCommand(const char* args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ std::string chrNameLink = GetNameLink(chr);
+
if(chr->isInFlight())
{
- PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName());
+ PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, chr->GetName());
+ PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, chrNameLink.c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_ASPEED_CHANGED, GetName(), ASpeed);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_ASPEED_CHANGED, GetNameLink().c_str(), ASpeed);
chr->SetSpeed(MOVE_WALK, ASpeed,true);
chr->SetSpeed(MOVE_RUN, ASpeed,true);
@@ -1493,16 +1587,22 @@ bool ChatHandler::HandleModifySpeedCommand(const char* args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ std::string chrNameLink = GetNameLink(chr);
+
if(chr->isInFlight())
{
- PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName());
+ PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, chr->GetName());
+ PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, chrNameLink.c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPEED_CHANGED, GetName(), Speed);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPEED_CHANGED, GetNameLink().c_str(), Speed);
chr->SetSpeed(MOVE_RUN,Speed,true);
@@ -1532,16 +1632,22 @@ bool ChatHandler::HandleModifySwimCommand(const char* args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ std::string chrNameLink = GetNameLink(chr);
+
if(chr->isInFlight())
{
- PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName());
+ PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, chr->GetName());
+ PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, chrNameLink.c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_SWIM_SPEED_CHANGED, GetName(), Swim);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_SWIM_SPEED_CHANGED, GetNameLink().c_str(), Swim);
chr->SetSpeed(MOVE_SWIM,Swim,true);
@@ -1571,16 +1677,22 @@ bool ChatHandler::HandleModifyBWalkCommand(const char* args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ std::string chrNameLink = GetNameLink(chr);
+
if(chr->isInFlight())
{
- PSendSysMessage(LANG_CHAR_IN_FLIGHT,chr->GetName());
+ PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, chr->GetName());
+ PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, chrNameLink.c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_BACK_SPEED_CHANGED, GetName(), BSpeed);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_BACK_SPEED_CHANGED, GetNameLink().c_str(), BSpeed);
chr->SetSpeed(MOVE_RUN_BACK,BSpeed,true);
@@ -1610,9 +1722,13 @@ bool ChatHandler::HandleModifyFlyCommand(const char* args)
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, chr->GetName());
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_FLY_SPEED_CHANGED, GetName(), FSpeed);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_FLY_SPEED_CHANGED, GetNameLink().c_str(), FSpeed);
chr->SetSpeed(MOVE_FLIGHT,FSpeed,true);
@@ -1641,9 +1757,13 @@ bool ChatHandler::HandleModifyScaleCommand(const char* args)
return false;
}
- PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, chr->GetName());
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_SIZE_CHANGED, GetName(), Scale);
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_SIZE_CHANGED, GetNameLink().c_str(), Scale);
chr->SetFloatValue(OBJECT_FIELD_SCALE_X, Scale);
@@ -1884,9 +2004,13 @@ bool ChatHandler::HandleModifyMountCommand(const char* args)
return false;
}
- PSendSysMessage(LANG_YOU_GIVE_MOUNT, chr->GetName());
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
+ PSendSysMessage(LANG_YOU_GIVE_MOUNT, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_MOUNT_GIVED, GetName());
+ ChatHandler(chr).PSendSysMessage(LANG_MOUNT_GIVED, GetNameLink().c_str());
chr->SetUInt32Value( UNIT_FIELD_FLAGS , 0x001000 );
chr->Mount(mId);
@@ -1921,37 +2045,48 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(chr, 0))
+ return false;
+
int32 addmoney = atoi((char*)args);
uint32 moneyuser = chr->GetMoney();
- if(addmoney < 0)
+ if (addmoney < 0)
{
- int32 newmoney = moneyuser + addmoney;
+ int32 newmoney = int32(moneyuser) + addmoney;
sLog.outDetail(GetTrinityString(LANG_CURRENT_MONEY), moneyuser, addmoney, newmoney);
- if(newmoney <= 0 )
+ if (newmoney <= 0 )
{
- PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, chr->GetName());
+ PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_ALL_MONEY_GONE, GetName());
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_ALL_MONEY_GONE, GetNameLink().c_str());
chr->SetMoney(0);
}
else
{
- PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), chr->GetName());
+ if (newmoney > MAX_MONEY_AMOUNT)
+ newmoney = MAX_MONEY_AMOUNT;
+
+ PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, GetName(), abs(addmoney));
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, GetNameLink().c_str(), abs(addmoney));
chr->SetMoney( newmoney );
}
}
else
{
- PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, chr->GetName());
+ PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, GetName(), addmoney);
- chr->ModifyMoney( addmoney );
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, GetNameLink().c_str(), addmoney);
+
+ if (addmoney >=MAX_MONEY_AMOUNT)
+ chr->SetMoney(MAX_MONEY_AMOUNT);
+ else
+ chr->ModifyMoney( addmoney );
}
sLog.outDetail(GetTrinityString(LANG_NEW_MONEY), moneyuser, addmoney, chr->GetMoney() );
@@ -1959,20 +2094,24 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args)
return true;
}
-//Edit Player field
+//Edit Unit field
bool ChatHandler::HandleModifyBitCommand(const char* args)
{
if( !*args )
return false;
- Player *chr = getSelectedPlayer();
- if (chr == NULL)
+ Unit *unit = getSelectedUnit();
+ if (!unit)
{
SendSysMessage(LANG_NO_CHAR_SELECTED);
SetSentErrorMessage(true);
return false;
}
+ // check online security
+ if (unit->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player *)unit, 0))
+ return false;
+
char* pField = strtok((char*)args, " ");
if (!pField)
return false;
@@ -1984,13 +2123,12 @@ bool ChatHandler::HandleModifyBitCommand(const char* args)
uint16 field = atoi(pField);
uint32 bit = atoi(pBit);
- if (field < 1 || field >= PLAYER_END)
+ if (field < OBJECT_END || field >= unit->GetValuesCount())
{
SendSysMessage(LANG_BAD_VALUE);
SetSentErrorMessage(true);
return false;
}
-
if (bit < 1 || bit > 32)
{
SendSysMessage(LANG_BAD_VALUE);
@@ -1998,17 +2136,16 @@ bool ChatHandler::HandleModifyBitCommand(const char* args)
return false;
}
- if ( chr->HasFlag( field, (1<<(bit-1)) ) )
+ if ( unit->HasFlag( field, (1<<(bit-1)) ) )
{
- chr->RemoveFlag( field, (1<<(bit-1)) );
+ unit->RemoveFlag( field, (1<<(bit-1)) );
PSendSysMessage(LANG_REMOVE_BIT, bit, field);
}
else
{
- chr->SetFlag( field, (1<<(bit-1)) );
+ unit->SetFlag( field, (1<<(bit-1)) );
PSendSysMessage(LANG_SET_BIT, bit, field);
}
-
return true;
}
@@ -2025,11 +2162,15 @@ bool ChatHandler::HandleModifyHonorCommand (const char* args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
int32 amount = (uint32)atoi(args);
target->ModifyHonorPoints(amount);
- PSendSysMessage(LANG_COMMAND_MODIFY_HONOR, target->GetName(), target->GetHonorPoints());
+ PSendSysMessage(LANG_COMMAND_MODIFY_HONOR, GetNameLink(target).c_str(), target->GetHonorPoints());
return true;
}
@@ -2095,7 +2236,7 @@ bool ChatHandler::HandleLookupAreaCommand(const char* args)
AreaTableEntry const *areaEntry = sAreaStore.LookupEntry (areaflag);
if (areaEntry)
{
- int loc = m_session ? m_session->GetSessionDbcLocale () : sWorld.GetDefaultDbcLocale();
+ int loc = GetSessionDbcLocale ();
std::string name = areaEntry->area_name[loc];
if (name.empty())
continue;
@@ -2105,7 +2246,7 @@ bool ChatHandler::HandleLookupAreaCommand(const char* args)
loc = 0;
for(; loc < MAX_LOCALE; ++loc)
{
- if (m_session && loc==m_session->GetSessionDbcLocale ())
+ if (loc==GetSessionDbcLocale ())
continue;
name = areaEntry->area_name[loc];
@@ -2132,8 +2273,10 @@ bool ChatHandler::HandleLookupAreaCommand(const char* args)
}
}
}
+
if (counter == 0) // if counter == 0 then we found nth
SendSysMessage (LANG_COMMAND_NOAREAFOUND);
+
return true;
}
@@ -2215,35 +2358,6 @@ bool ChatHandler::HandleWhispersCommand(const char* args)
return false;
}
-//Play sound
-bool ChatHandler::HandlePlaySoundCommand(const char* args)
-{
- // USAGE: .debug playsound #soundid
- // #soundid - ID decimal number from SoundEntries.dbc (1st column)
- // this file have about 5000 sounds.
- // In this realization only caller can hear this sound.
- if( *args )
- {
- uint32 dwSoundId = atoi((char*)args);
-
- if( !sSoundEntriesStore.LookupEntry(dwSoundId) )
- {
- PSendSysMessage(LANG_SOUND_NOT_EXIST, dwSoundId);
- SetSentErrorMessage(true);
- return false;
- }
-
- WorldPacket data(SMSG_PLAY_OBJECT_SOUND,4+8);
- data << uint32(dwSoundId) << m_session->GetPlayer()->GetGUID();
- m_session->SendPacket(&data);
-
- PSendSysMessage(LANG_YOU_HEAR_SOUND, dwSoundId);
- return true;
- }
-
- return false;
-}
-
//Save all players in the world
bool ChatHandler::HandleSaveAllCommand(const char* /*args*/)
{
@@ -2255,13 +2369,11 @@ bool ChatHandler::HandleSaveAllCommand(const char* /*args*/)
//Send mail by command
bool ChatHandler::HandleSendMailCommand(const char* args)
{
- if(!*args)
- return false;
-
// format: name "subject text" "mail text"
-
- char* pName = strtok((char*)args, " ");
- if(!pName)
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
char* tail1 = strtok(NULL, "");
@@ -2300,27 +2412,10 @@ bool ChatHandler::HandleSendMailCommand(const char* args)
if (!msgText)
return false;
- // pName, msgSubject, msgText isn't NUL after prev. check
- std::string name = pName;
+ // msgSubject, msgText isn't NUL after prev. check
std::string subject = msgSubject;
std::string text = msgText;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 receiver_guid = objmgr.GetPlayerGUIDByName(name);
- if(!receiver_guid)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 mailId = objmgr.GenerateMailID();
// from console show not existed sender
uint32 sender_guidlo = m_session ? m_session->GetPlayer()->GetGUIDLow() : 0;
@@ -2328,40 +2423,30 @@ bool ChatHandler::HandleSendMailCommand(const char* args)
uint32 stationery = MAIL_STATIONERY_GM;
uint32 itemTextId = !text.empty() ? objmgr.CreateItemText( text ) : 0;
- Player *receiver = objmgr.GetPlayer(receiver_guid);
-
- WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_NONE);
+ WorldSession::SendMailTo(target,messagetype, stationery, sender_guidlo, GUID_LOPART(target_guid), subject, itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_NONE);
- PSendSysMessage(LANG_MAIL_SENT, name.c_str());
+ std::string nameLink = playerLink(target_name);
+ PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str());
return true;
}
// teleport player to given game_tele.entry
-bool ChatHandler::HandleNameTeleCommand(const char * args)
+bool ChatHandler::HandleTeleNameCommand(const char * args)
{
- if(!*args)
- return false;
-
- char* pName = strtok((char*)args, " ");
-
- if(!pName)
- return false;
-
- std::string name = pName;
-
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
+ char* nameStr;
+ char* teleStr;
+ extractOptFirstArg((char*)args,&nameStr,&teleStr);
+ if(!teleStr)
return false;
- }
-
- char* tail = strtok(NULL, "");
- if(!tail)
+
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name))
return false;
// id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r
- GameTele const* tele = extractGameTeleFromLink(tail);
+ GameTele const* tele = extractGameTeleFromLink(teleStr);
if(!tele)
{
SendSysMessage(LANG_COMMAND_TELE_NOTFOUND);
@@ -2369,7 +2454,7 @@ bool ChatHandler::HandleNameTeleCommand(const char * args)
return false;
}
- MapEntry const * me = sMapStore.LookupEntry(tele->mapId);
+/* MapEntry const * me = sMapStore.LookupEntry(tele->mapId);
if(!me || me->IsBattleGroundOrArena())
{
SendSysMessage(LANG_CANNOT_TELE_TO_BG);
@@ -2377,46 +2462,57 @@ bool ChatHandler::HandleNameTeleCommand(const char * args)
return false;
}
- Player *chr = objmgr.GetPlayer(name.c_str());
- if (chr)
+ Player *chr = objmgr.GetPlayer(name.c_str());*/
+
+ if (target)
{
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
- if(chr->IsBeingTeleported()==true)
+ std::string chrNameLink = playerLink(target_name);
+
+ if(target->IsBeingTeleported()==true)
{
- PSendSysMessage(LANG_IS_TELEPORTED, chr->GetName());
+ PSendSysMessage(LANG_IS_TELEPORTED, chrNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
- PSendSysMessage(LANG_TELEPORTING_TO, chr->GetName(),"", tele->name.c_str());
- if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_TELEPORTED_TO_BY, GetName());
+ PSendSysMessage(LANG_TELEPORTING_TO, chrNameLink.c_str(),"", tele->name.c_str());
+ if (needReportToTarget(target))
+ ChatHandler(target).PSendSysMessage(LANG_TELEPORTED_TO_BY, GetNameLink().c_str());
// stop flight if need
- if(chr->isInFlight())
+ if(target->isInFlight())
{
- chr->GetMotionMaster()->MovementExpired();
- chr->m_taxi.ClearTaxiDestinations();
+ target->GetMotionMaster()->MovementExpired();
+ target->m_taxi.ClearTaxiDestinations();
}
// save only in non-flight case
else
- chr->SaveRecallPosition();
+ target->SaveRecallPosition();
- chr->TeleportTo(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation);
+ target->TeleportTo(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation);
}
- else if (uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()))
+ else
{
- PSendSysMessage(LANG_TELEPORTING_TO, name.c_str(), GetTrinityString(LANG_OFFLINE), tele->name.c_str());
- Player::SavePositionInDB(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation,MapManager::Instance().GetZoneId(tele->mapId,tele->position_x,tele->position_y),guid);
+ // check offline security
+ if (HasLowerSecurity(NULL, target_guid))
+ return false;
+
+ std::string nameLink = playerLink(target_name);
+
+ PSendSysMessage(LANG_TELEPORTING_TO, nameLink.c_str(), GetMangosString(LANG_OFFLINE), tele->name.c_str());
+ Player::SavePositionInDB(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation,
+ MapManager::Instance().GetZoneId(tele->mapId,tele->position_x,tele->position_y,tele->position_z),target_guid);
}
- else
- PSendSysMessage(LANG_NO_PLAYER, name.c_str());
return true;
}
//Teleport group to given game_tele.entry
-bool ChatHandler::HandleGroupTeleCommand(const char * args)
+bool ChatHandler::HandleTeleGroupCommand(const char * args)
{
if(!*args)
return false;
@@ -2429,6 +2525,10 @@ bool ChatHandler::HandleGroupTeleCommand(const char * args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(player, 0))
+ return false;
+
// id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r
GameTele const* tele = extractGameTeleFromLink((char*)args);
if(!tele)
@@ -2445,10 +2545,13 @@ bool ChatHandler::HandleGroupTeleCommand(const char * args)
SetSentErrorMessage(true);
return false;
}
+
+ std::string nameLink = GetNameLink(player);
+
Group *grp = player->GetGroup();
if(!grp)
{
- PSendSysMessage(LANG_NOT_IN_GROUP,player->GetName());
+ PSendSysMessage(LANG_NOT_IN_GROUP,nameLink.c_str());
SetSentErrorMessage(true);
return false;
}
@@ -2460,15 +2563,21 @@ bool ChatHandler::HandleGroupTeleCommand(const char * args)
if(!pl || !pl->GetSession() )
continue;
+ // check online security
+ if (HasLowerSecurity(pl, 0))
+ return false;
+
+ std::string plNameLink = GetNameLink(pl);
+
if(pl->IsBeingTeleported())
{
- PSendSysMessage(LANG_IS_TELEPORTED, pl->GetName());
+ PSendSysMessage(LANG_IS_TELEPORTED, plNameLink.c_str());
continue;
}
- PSendSysMessage(LANG_TELEPORTING_TO, pl->GetName(),"", tele->name.c_str());
+ PSendSysMessage(LANG_TELEPORTING_TO, plNameLink.c_str(),"", tele->name.c_str());
if (needReportToTarget(pl))
- ChatHandler(pl).PSendSysMessage(LANG_TELEPORTED_TO_BY, GetName());
+ ChatHandler(pl).PSendSysMessage(LANG_TELEPORTED_TO_BY, nameLink.c_str());
// stop flight if need
if(pl->isInFlight())
@@ -2489,36 +2598,26 @@ bool ChatHandler::HandleGroupTeleCommand(const char * args)
//Summon group of player
bool ChatHandler::HandleGroupgoCommand(const char* args)
{
- if(!*args)
+ Player* target;
+ if(!extractPlayerTarget((char*)args,&target))
return false;
- std::string name = args;
-
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
+ // check online security
+ if (HasLowerSecurity(target, 0))
return false;
- }
- Player *player = objmgr.GetPlayer(name.c_str());
- if (!player)
- {
- PSendSysMessage(LANG_NO_PLAYER, args);
- SetSentErrorMessage(true);
- return false;
- }
+ Group *grp = target->GetGroup();
- Group *grp = player->GetGroup();
+ std::string nameLink = GetNameLink(target);
if(!grp)
{
- PSendSysMessage(LANG_NOT_IN_GROUP,player->GetName());
+ PSendSysMessage(LANG_NOT_IN_GROUP,nameLink.c_str());
SetSentErrorMessage(true);
return false;
}
- Map* gmMap = MapManager::Instance().GetMap(m_session->GetPlayer()->GetMapId(),m_session->GetPlayer());
+ Map* gmMap = m_session->GetPlayer()->GetMap();
bool to_instance = gmMap->Instanceable();
// we are in instance, and can summon only player in our group with us as lead
@@ -2539,29 +2638,35 @@ bool ChatHandler::HandleGroupgoCommand(const char* args)
if(!pl || pl==m_session->GetPlayer() || !pl->GetSession() )
continue;
+ // check online security
+ if (HasLowerSecurity(pl, 0))
+ return false;
+
+ std::string plNameLink = GetNameLink(pl);
+
if(pl->IsBeingTeleported()==true)
{
- PSendSysMessage(LANG_IS_TELEPORTED, pl->GetName());
+ PSendSysMessage(LANG_IS_TELEPORTED, plNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
if (to_instance)
{
- Map* plMap = MapManager::Instance().GetMap(pl->GetMapId(),pl);
+ Map* plMap = pl->GetMap();
if ( plMap->Instanceable() && plMap->GetInstanceId() != gmMap->GetInstanceId() )
{
// cannot summon from instance to instance
- PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,pl->GetName());
+ PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,plNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
}
- PSendSysMessage(LANG_SUMMONING, pl->GetName(),"");
+ PSendSysMessage(LANG_SUMMONING, plNameLink.c_str(),"");
if (needReportToTarget(pl))
- ChatHandler(pl).PSendSysMessage(LANG_SUMMONED_BY, GetName());
+ ChatHandler(pl).PSendSysMessage(LANG_SUMMONED_BY, GetNameLink().c_str());
// stop flight if need
if(pl->isInFlight())
@@ -2582,6 +2687,51 @@ bool ChatHandler::HandleGroupgoCommand(const char* args)
return true;
}
+bool ChatHandler::HandleGoTaxinodeCommand(const char* args)
+{
+ Player* _player = m_session->GetPlayer();
+
+ if (!*args)
+ return false;
+
+ char* cNodeId = extractKeyFromLink((char*)args,"Htaxinode");
+ if (!cNodeId)
+ return false;
+
+ int32 i_nodeId = atoi(cNodeId);
+ if (!i_nodeId)
+ return false;
+
+ TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i_nodeId);
+ if (!node)
+ {
+ PSendSysMessage(LANG_COMMAND_GOTAXINODENOTFOUND,i_nodeId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (node->x == 0.0f && node->y == 0.0f && node->z == 0.0f ||
+ !MapManager::IsValidMapCoord(node->map_id,node->x,node->y,node->z))
+ {
+ PSendSysMessage(LANG_INVALID_TARGET_COORD,node->x,node->y,node->map_id);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // stop flight if need
+ if (_player->isInFlight())
+ {
+ _player->GetMotionMaster()->MovementExpired();
+ _player->m_taxi.ClearTaxiDestinations();
+ }
+ // save only in non-flight case
+ else
+ _player->SaveRecallPosition();
+
+ _player->TeleportTo(node->map_id, node->x, node->y, node->z, _player->GetOrientation());
+ return true;
+}
+
//teleport at coordinates
bool ChatHandler::HandleGoXYCommand(const char* args)
{
@@ -2695,6 +2845,11 @@ bool ChatHandler::HandleGoZoneXYCommand(const char* args)
float x = (float)atof(px);
float y = (float)atof(py);
+
+ // prevent accept wrong numeric args
+ if (x==0.0f && *px!='0' || y==0.0f && *py!='0')
+ return false;
+
uint32 areaid = cAreaId ? (uint32)atoi(cAreaId) : _player->GetZoneId();
AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaid);
@@ -2713,7 +2868,7 @@ bool ChatHandler::HandleGoZoneXYCommand(const char* args)
if(map->Instanceable())
{
- PSendSysMessage(LANG_INVALID_ZONE_MAP,areaEntry->ID,areaEntry->area_name[m_session->GetSessionDbcLocale()],map->GetId(),map->GetMapName());
+ PSendSysMessage(LANG_INVALID_ZONE_MAP,areaEntry->ID,areaEntry->area_name[GetSessionDbcLocale()],map->GetId(),map->GetMapName());
SetSentErrorMessage(true);
return false;
}
@@ -2791,7 +2946,7 @@ bool ChatHandler::HandleGoGridCommand(const char* args)
return true;
}
-bool ChatHandler::HandleDrunkCommand(const char* args)
+bool ChatHandler::HandleModifyDrunkCommand(const char* args)
{
if(!*args) return false;
diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp
index fc6e8a51a74..d9516835201 100644
--- a/src/game/Level2.cpp
+++ b/src/game/Level2.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,19 +10,16 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Database/DatabaseEnv.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
-#include "World.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "Item.h"
@@ -33,9 +30,11 @@
#include "MapManager.h"
#include "Language.h"
#include "World.h"
-#include "GameEvent.h"
+#include "GameEventMgr.h"
#include "SpellMgr.h"
+#include "PoolHandler.h"
#include "AccountMgr.h"
+#include "TicketMgr.h"
#include "WaypointManager.h"
#include "Util.h"
#include <cctype>
@@ -46,6 +45,7 @@
#include "TicketMgr.h"
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
+#include "CreatureGroups.h"
static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] =
{
@@ -56,298 +56,97 @@ static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] =
//mute player for some times
bool ChatHandler::HandleMuteCommand(const char* args)
{
- if (!*args)
- return false;
-
- char *charname = strtok((char*)args, " ");
- if (!charname)
+ char* nameStr;
+ char* delayStr;
+ extractOptFirstArg((char*)args,&nameStr,&delayStr);
+ if(!delayStr)
return false;
- std::string cname = charname;
-
- char *timetonotspeak = strtok(NULL, " ");
- if(!timetonotspeak)
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name))
return false;
- uint32 notspeaktime = (uint32) atoi(timetonotspeak);
-
- if(!normalizePlayerName(cname))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
+ uint32 account_id = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid);
- uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str());
- if(!guid)
+ // find only player from same account if any
+ if(!target)
{
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
+ if(WorldSession* session = sWorld.FindSession(account_id))
+ target = session->GetPlayer();
}
- Player *chr = objmgr.GetPlayer(guid);
-
- // check security
- uint32 account_id = 0;
- uint32 security = 0;
-
- if (chr)
- {
- account_id = chr->GetSession()->GetAccountId();
- security = chr->GetSession()->GetSecurity();
- }
- else
- {
- account_id = objmgr.GetPlayerAccountIdByGUID(guid);
- security = accmgr.GetSecurity(account_id);
- }
+ uint32 notspeaktime = (uint32) atoi(delayStr);
- if(m_session && security >= m_session->GetSecurity())
- {
- SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
- SetSentErrorMessage(true);
+ // must have strong lesser security level
+ if(HasLowerSecurity (target,target_guid,true))
return false;
- }
time_t mutetime = time(NULL) + notspeaktime*60;
- if (chr)
- chr->GetSession()->m_muteTime = mutetime;
+ if (target)
+ target->GetSession()->m_muteTime = mutetime;
LoginDatabase.PExecute("UPDATE account SET mutetime = " I64FMTD " WHERE id = '%u'",uint64(mutetime), account_id );
- if(chr)
- ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime);
+ if(target)
+ ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime);
- PSendSysMessage(LANG_YOU_DISABLE_CHAT, cname.c_str(), notspeaktime);
+ std::string nameLink = playerLink(target_name);
+ PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), notspeaktime);
return true;
}
//unmute player
bool ChatHandler::HandleUnmuteCommand(const char* args)
{
- if (!*args)
- return false;
-
- char *charname = strtok((char*)args, " ");
- if (!charname)
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
- std::string cname = charname;
+ uint32 account_id = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid);
- if(!normalizePlayerName(cname))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str());
- if(!guid)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- Player *chr = objmgr.GetPlayer(guid);
-
- // check security
- uint32 account_id = 0;
- uint32 security = 0;
-
- if (chr)
- {
- account_id = chr->GetSession()->GetAccountId();
- security = chr->GetSession()->GetSecurity();
- }
- else
+ // find only player from same account if any
+ if(!target)
{
- account_id = objmgr.GetPlayerAccountIdByGUID(guid);
- security = accmgr.GetSecurity(account_id);
+ if(WorldSession* session = sWorld.FindSession(account_id))
+ target = session->GetPlayer();
}
- if(m_session && security >= m_session->GetSecurity())
- {
- SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
- SetSentErrorMessage(true);
+ // must have strong lesser security level
+ if(HasLowerSecurity (target,target_guid,true))
return false;
- }
- if (chr)
+ if (target)
{
- if(chr->CanSpeak())
+ if(target->CanSpeak())
{
SendSysMessage(LANG_CHAT_ALREADY_ENABLED);
SetSentErrorMessage(true);
return false;
}
- chr->GetSession()->m_muteTime = 0;
+ target->GetSession()->m_muteTime = 0;
}
LoginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id );
- if(chr)
- ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_ENABLED);
-
- PSendSysMessage(LANG_YOU_ENABLE_CHAT, cname.c_str());
- return true;
-}
-
-bool ChatHandler::HandleTargetObjectCommand(const char* args)
-{
- Player* pl = m_session->GetPlayer();
- QueryResult *result;
- GameEvent::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList();
- if(*args)
- {
- int32 id = atoi((char*)args);
- if(id)
- result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1",
- pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),id);
- else
- {
- std::string name = args;
- WorldDatabase.escape_string(name);
- result = WorldDatabase.PQuery(
- "SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ "
- "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" ORDER BY order_ ASC LIMIT 1",
- pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str());
- }
- }
- else
- {
- std::ostringstream eventFilter;
- eventFilter << " AND (event IS NULL ";
- bool initString = true;
-
- for (GameEvent::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr)
- {
- if (initString)
- {
- eventFilter << "OR event IN (" <<*itr;
- initString =false;
- }
- else
- eventFilter << "," << *itr;
- }
-
- if (!initString)
- eventFilter << "))";
- else
- eventFilter << ")";
-
- result = WorldDatabase.PQuery("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, "
- "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject "
- "LEFT OUTER JOIN game_event_gameobject on gameobject.guid=game_event_gameobject.guid WHERE map = '%i' %s ORDER BY order_ ASC LIMIT 1",
- m_session->GetPlayer()->GetPositionX(), m_session->GetPlayer()->GetPositionY(), m_session->GetPlayer()->GetPositionZ(), m_session->GetPlayer()->GetMapId(),eventFilter.str().c_str());
- }
-
- if (!result)
- {
- SendSysMessage(LANG_COMMAND_TARGETOBJNOTFOUND);
- return true;
- }
-
- Field *fields = result->Fetch();
- uint32 lowguid = fields[0].GetUInt32();
- uint32 id = fields[1].GetUInt32();
- float x = fields[2].GetFloat();
- float y = fields[3].GetFloat();
- float z = fields[4].GetFloat();
- float o = fields[5].GetFloat();
- int mapid = fields[6].GetUInt16();
- delete result;
-
- GameObjectInfo const* goI = objmgr.GetGameObjectInfo(id);
-
- if (!goI)
- {
- PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
- return false;
- }
-
- GameObject* target = ObjectAccessor::GetGameObject(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,id,HIGHGUID_GAMEOBJECT));
-
- PSendSysMessage(LANG_GAMEOBJECT_DETAIL, lowguid, goI->name, lowguid, id, x, y, z, mapid, o);
-
if(target)
- {
- int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL);
- if(curRespawnDelay < 0)
- curRespawnDelay = 0;
+ ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_ENABLED);
- std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true);
- std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true);
+ std::string nameLink = playerLink(target_name);
- PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str());
- }
- return true;
-}
-
-//teleport to gameobject
-bool ChatHandler::HandleGoObjectCommand(const char* args)
-{
- if(!*args)
- return false;
-
- Player* _player = m_session->GetPlayer();
-
- // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hgameobject");
- if(!cId)
- return false;
-
- int32 guid = atoi(cId);
- if(!guid)
- return false;
-
- float x, y, z, ort;
- int mapid;
-
- // by DB guid
- if (GameObjectData const* go_data = objmgr.GetGOData(guid))
- {
- x = go_data->posX;
- y = go_data->posY;
- z = go_data->posZ;
- ort = go_data->orientation;
- mapid = go_data->mapid;
- }
- else
- {
- SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))
- {
- PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);
- SetSentErrorMessage(true);
- return false;
- }
-
- // stop flight if need
- if(_player->isInFlight())
- {
- _player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
- }
- // save only in non-flight case
- else
- _player->SaveRecallPosition();
-
- _player->TeleportTo(mapid, x, y, z, ort);
+ PSendSysMessage(LANG_YOU_ENABLE_CHAT, nameLink.c_str());
return true;
}
bool ChatHandler::HandleGoTicketCommand(const char * args)
{
- if(!*args)
+ if(!*args)
return false;
char *cstrticket_id = strtok((char*)args, " ");
@@ -478,15 +277,15 @@ bool ChatHandler::HandleGoGraveyardCommand(const char* args)
}
/** \brief Teleport the GM to the specified creature
- *
- * .gocreature <GUID> --> TP using creature.guid
- * .gocreature azuregos --> TP player to the mob with this name
- * Warning: If there is more than one mob with this name
- * you will be teleported to the first one that is found.
- * .gocreature id 6109 --> TP player to the mob, that has this creature_template.entry
- * Warning: If there is more than one mob with this "id"
- * you will be teleported to the first one that is found.
- */
+*
+* .gocreature <GUID> --> TP using creature.guid
+* .gocreature azuregos --> TP player to the mob with this name
+* Warning: If there is more than one mob with this name
+* you will be teleported to the first one that is found.
+* .gocreature id 6109 --> TP player to the mob, that has this creature_template.entry
+* Warning: If there is more than one mob with this "id"
+* you will be teleported to the first one that is found.
+*/
//teleport to creature
bool ChatHandler::HandleGoCreatureCommand(const char* args)
{
@@ -584,434 +383,180 @@ bool ChatHandler::HandleGoCreatureCommand(const char* args)
return true;
}
-bool ChatHandler::HandleGUIDCommand(const char* /*args*/)
+//teleport to gameobject
+bool ChatHandler::HandleGoObjectCommand(const char* args)
{
- uint64 guid = m_session->GetPlayer()->GetSelection();
-
- if (guid == 0)
- {
- SendSysMessage(LANG_NO_SELECTION);
- SetSentErrorMessage(true);
+ if(!*args)
return false;
- }
- PSendSysMessage(LANG_OBJECT_GUID, GUID_LOPART(guid), GUID_HIPART(guid));
- return true;
-}
+ Player* _player = m_session->GetPlayer();
-bool ChatHandler::HandleLookupFactionCommand(const char* args)
-{
- if (!*args)
+ // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject");
+ if(!cId)
return false;
- // Can be NULL at console call
- Player *target = getSelectedPlayer ();
-
- std::string namepart = args;
- std::wstring wnamepart;
-
- if (!Utf8toWStr (namepart,wnamepart))
+ int32 guid = atoi(cId);
+ if(!guid)
return false;
- // converting string that we try to find to lower case
- wstrToLower (wnamepart);
-
- uint32 counter = 0; // Counter for figure out that we found smth.
+ float x, y, z, ort;
+ int mapid;
- for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id)
+ // by DB guid
+ if (GameObjectData const* go_data = objmgr.GetGOData(guid))
{
- FactionEntry const *factionEntry = sFactionStore.LookupEntry (id);
- if (factionEntry)
- {
- FactionState const* repState = NULL;
- if(target)
- {
- FactionStateList::const_iterator repItr = target->m_factions.find (factionEntry->reputationListID);
- if(repItr != target->m_factions.end())
- repState = &repItr->second;
- }
-
- int loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale();
- std::string name = factionEntry->name[loc];
- if(name.empty())
- continue;
-
- if (!Utf8FitTo(name, wnamepart))
- {
- loc = 0;
- for(; loc < MAX_LOCALE; ++loc)
- {
- if(m_session && loc==m_session->GetSessionDbcLocale())
- continue;
-
- name = factionEntry->name[loc];
- if(name.empty())
- continue;
-
- if (Utf8FitTo(name, wnamepart))
- break;
- }
- }
-
- if(loc < MAX_LOCALE)
- {
- // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format
- // or "id - [faction] [no reputation]" format
- std::ostringstream ss;
- if (m_session)
- ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r";
- else
- ss << id << " - " << name << " " << localeNames[loc];
-
- if (repState) // and then target!=NULL also
- {
- ReputationRank rank = target->GetReputationRank(factionEntry);
- std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]);
-
- ss << " " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")";
-
- if(repState->Flags & FACTION_FLAG_VISIBLE)
- ss << GetTrinityString(LANG_FACTION_VISIBLE);
- if(repState->Flags & FACTION_FLAG_AT_WAR)
- ss << GetTrinityString(LANG_FACTION_ATWAR);
- if(repState->Flags & FACTION_FLAG_PEACE_FORCED)
- ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
- if(repState->Flags & FACTION_FLAG_HIDDEN)
- ss << GetTrinityString(LANG_FACTION_HIDDEN);
- if(repState->Flags & FACTION_FLAG_INVISIBLE_FORCED)
- ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
- if(repState->Flags & FACTION_FLAG_INACTIVE)
- ss << GetTrinityString(LANG_FACTION_INACTIVE);
- }
- else
- ss << GetTrinityString(LANG_FACTION_NOREPUTATION);
-
- SendSysMessage(ss.str().c_str());
- counter++;
- }
- }
+ x = go_data->posX;
+ y = go_data->posY;
+ z = go_data->posZ;
+ ort = go_data->orientation;
+ mapid = go_data->mapid;
}
-
- if (counter == 0) // if counter == 0 then we found nth
- SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND);
- return true;
-}
-
-bool ChatHandler::HandleModifyRepCommand(const char * args)
-{
- if (!*args) return false;
-
- Player* target = NULL;
- target = getSelectedPlayer();
-
- if(!target)
+ else
{
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND);
SetSentErrorMessage(true);
return false;
}
- char* factionTxt = extractKeyFromLink((char*)args,"Hfaction");
- if(!factionTxt)
- return false;
-
- uint32 factionId = atoi(factionTxt);
-
- int32 amount = 0;
- char *rankTxt = strtok(NULL, " ");
- if (!factionTxt || !rankTxt)
- return false;
-
- amount = atoi(rankTxt);
- if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0]))
- {
- std::string rankStr = rankTxt;
- std::wstring wrankStr;
- if(!Utf8toWStr(rankStr,wrankStr))
- return false;
- wstrToLower( wrankStr );
-
- int r = 0;
- amount = -42000;
- for (; r < MAX_REPUTATION_RANK; ++r)
- {
- std::string rank = GetTrinityString(ReputationRankStrIndex[r]);
- if(rank.empty())
- continue;
-
- std::wstring wrank;
- if(!Utf8toWStr(rank,wrank))
- continue;
-
- wstrToLower(wrank);
-
- if(wrank.substr(0,wrankStr.size())==wrankStr)
- {
- char *deltaTxt = strtok(NULL, " ");
- if (deltaTxt)
- {
- int32 delta = atoi(deltaTxt);
- if ((delta < 0) || (delta > Player::ReputationRank_Length[r] -1))
- {
- PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (Player::ReputationRank_Length[r]-1));
- SetSentErrorMessage(true);
- return false;
- }
- amount += delta;
- }
- break;
- }
- amount += Player::ReputationRank_Length[r];
- }
- if (r >= MAX_REPUTATION_RANK)
- {
- PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt);
- SetSentErrorMessage(true);
- return false;
- }
- }
-
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId);
-
- if (!factionEntry)
+ if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))
{
- PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId);
+ PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);
SetSentErrorMessage(true);
return false;
}
- if (factionEntry->reputationListID < 0)
+ // stop flight if need
+ if(_player->isInFlight())
{
- PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->name[m_session->GetSessionDbcLocale()], factionId);
- SetSentErrorMessage(true);
- return false;
+ _player->GetMotionMaster()->MovementExpired();
+ _player->m_taxi.ClearTaxiDestinations();
}
+ // save only in non-flight case
+ else
+ _player->SaveRecallPosition();
- target->SetFactionReputation(factionEntry,amount);
- PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[m_session->GetSessionDbcLocale()], factionId, target->GetName(), target->GetReputation(factionId));
+ _player->TeleportTo(mapid, x, y, z, ort);
return true;
}
-bool ChatHandler::HandleNameCommand(const char* args)
+bool ChatHandler::HandleGameObjectTargetCommand(const char* args)
{
- /* Temp. disabled
- if(!*args)
+ Player* pl = m_session->GetPlayer();
+ QueryResult *result;
+ GameEventMgr::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList();
+ if(*args)
+ {
+ // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry");
+ if(!cId)
return false;
- if(strlen((char*)args)>75)
+ uint32 id = atol(cId);
+
+ if(id)
+ result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1",
+ pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),id);
+ else
{
- PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75);
- return true;
+ std::string name = cId;
+ WorldDatabase.escape_string(name);
+ result = WorldDatabase.PQuery(
+ "SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ "
+ "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" ORDER BY order_ ASC LIMIT 1",
+ pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str());
}
+ }
+ else
+ {
+ std::ostringstream eventFilter;
+ eventFilter << " AND (event IS NULL ";
+ bool initString = true;
- for (uint8 i = 0; i < strlen(args); i++)
+ for (GameEventMgr::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr)
{
- if(!isalpha(args[i]) && args[i]!=' ')
+ if (initString)
{
- SendSysMessage(LANG_CHARS_ONLY);
- return false;
+ eventFilter << "OR event IN (" <<*itr;
+ initString =false;
}
+ else
+ eventFilter << "," << *itr;
}
- uint64 guid;
- guid = m_session->GetPlayer()->GetSelection();
- if (guid == 0)
- {
- SendSysMessage(LANG_NO_SELECTION);
- return true;
- }
-
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
-
- if(!pCreature)
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- return true;
- }
-
- pCreature->SetName(args);
- uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName());
- pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
-
- pCreature->SaveToDB();
- */
-
- return true;
-}
-
-bool ChatHandler::HandleSubNameCommand(const char* /*args*/)
-{
- /* Temp. disabled
-
- if(!*args)
- args = "";
-
- if(strlen((char*)args)>75)
- {
+ if (!initString)
+ eventFilter << "))";
+ else
+ eventFilter << ")";
- PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75);
- return true;
+ result = WorldDatabase.PQuery("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, "
+ "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject "
+ "LEFT OUTER JOIN game_event_gameobject on gameobject.guid=game_event_gameobject.guid WHERE map = '%i' %s ORDER BY order_ ASC LIMIT 10",
+ m_session->GetPlayer()->GetPositionX(), m_session->GetPlayer()->GetPositionY(), m_session->GetPlayer()->GetPositionZ(), m_session->GetPlayer()->GetMapId(),eventFilter.str().c_str());
}
- for (uint8 i = 0; i < strlen(args); i++)
- {
- if(!isalpha(args[i]) && args[i]!=' ')
- {
- SendSysMessage(LANG_CHARS_ONLY);
- return false;
- }
- }
- uint64 guid;
- guid = m_session->GetPlayer()->GetSelection();
- if (guid == 0)
+ if (!result)
{
- SendSysMessage(LANG_NO_SELECTION);
+ SendSysMessage(LANG_COMMAND_TARGETOBJNOTFOUND);
return true;
}
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
+ bool found = false;
+ float x, y, z, o;
+ uint32 lowguid, id;
+ uint16 mapid, pool_id;
- if(!pCreature)
+ do
{
- SendSysMessage(LANG_SELECT_CREATURE);
- return true;
- }
-
- uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID));
- pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
-
- pCreature->SaveToDB();
- */
- return true;
-}
-
-//move item to other slot
-bool ChatHandler::HandleItemMoveCommand(const char* args)
-{
- if(!*args)
- return false;
- uint8 srcslot, dstslot;
-
- char* pParam1 = strtok((char*)args, " ");
- if (!pParam1)
- return false;
-
- char* pParam2 = strtok(NULL, " ");
- if (!pParam2)
- return false;
-
- srcslot = (uint8)atoi(pParam1);
- dstslot = (uint8)atoi(pParam2);
-
- if(srcslot==dstslot)
- return true;
-
- if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot))
- return false;
-
- if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot))
- return false;
-
- uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot);
- uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot);
-
- m_session->GetPlayer()->SwapItem( src, dst );
-
- return true;
-}
-
-//add spawn of creature
-bool ChatHandler::HandleNpcAddCommand(const char* args)
-{
- if(!*args)
- return false;
- char* charID = strtok((char*)args, " ");
- if (!charID)
- return false;
-
- char* team = strtok(NULL, " ");
- int32 teamval = 0;
- if (team) { teamval = atoi(team); }
- if (teamval < 0) { teamval = 0; }
-
- uint32 id = atoi(charID);
+ Field *fields = result->Fetch();
+ lowguid = fields[0].GetUInt32();
+ id = fields[1].GetUInt32();
+ x = fields[2].GetFloat();
+ y = fields[3].GetFloat();
+ z = fields[4].GetFloat();
+ o = fields[5].GetFloat();
+ mapid = fields[6].GetUInt16();
+ pool_id = poolhandler.IsPartOfAPool(lowguid, TYPEID_GAMEOBJECT);
+ if (!pool_id || (pool_id && poolhandler.IsSpawnedObject(pool_id, lowguid, TYPEID_GAMEOBJECT)))
+ found = true;
+ } while( result->NextRow() && (!found) );
- Player *chr = m_session->GetPlayer();
- float x = chr->GetPositionX();
- float y = chr->GetPositionY();
- float z = chr->GetPositionZ();
- float o = chr->GetOrientation();
- Map *map = chr->GetMap();
+ delete result;
- Creature* pCreature = new Creature;
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, (uint32)teamval))
+ if (!found)
{
- delete pCreature;
+ PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
return false;
}
- pCreature->Relocate(x,y,z,o);
+ GameObjectInfo const* goI = objmgr.GetGameObjectInfo(id);
- if(!pCreature->IsPositionValid())
+ if (!goI)
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
- delete pCreature;
+ PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
return false;
}
- pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
-
- uint32 db_guid = pCreature->GetDBTableGUIDLow();
+ GameObject* target = m_session->GetPlayer()->GetMap()->GetGameObject(MAKE_NEW_GUID(lowguid,id,HIGHGUID_GAMEOBJECT));
- // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
- pCreature->LoadFromDB(db_guid, map);
-
- map->Add(pCreature);
- objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid));
- return true;
-}
-
-bool ChatHandler::HandleNpcDeleteCommand(const char* args)
-{
- Creature* unit = NULL;
+ PSendSysMessage(LANG_GAMEOBJECT_DETAIL, lowguid, goI->name, lowguid, id, x, y, z, mapid, o);
- if(*args)
+ if(target)
{
- // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hcreature");
- if(!cId)
- return false;
-
- uint32 lowguid = atoi(cId);
- if(!lowguid)
- return false;
+ int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL);
+ if(curRespawnDelay < 0)
+ curRespawnDelay = 0;
- if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid))
- unit = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT));
- }
- else
- unit = getSelectedCreature();
+ std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true);
+ std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true);
- if(!unit || unit->isPet() || unit->isTotem())
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
+ PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str());
}
-
- // Delete the creature
- unit->CombatStop();
- unit->DeleteFromDB();
- unit->CleanupsBeforeDelete();
- unit->AddObjectToRemoveList();
-
- SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
-
return true;
}
//delete object by selection or guid
-bool ChatHandler::HandleDelObjectCommand(const char* args)
+bool ChatHandler::HandleGameObjectDeleteCommand(const char* args)
{
// number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
char* cId = extractKeyFromLink((char*)args,"Hgameobject");
@@ -1039,7 +584,7 @@ bool ChatHandler::HandleDelObjectCommand(const char* args)
if(owner_guid)
{
Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid);
- if(!owner && !IS_PLAYER_GUID(owner_guid))
+ if(!owner || !IS_PLAYER_GUID(owner_guid))
{
PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow());
SetSentErrorMessage(true);
@@ -1059,7 +604,7 @@ bool ChatHandler::HandleDelObjectCommand(const char* args)
}
//turn selected object
-bool ChatHandler::HandleTurnObjectCommand(const char* args)
+bool ChatHandler::HandleGameObjectTurnCommand(const char* args)
{
// number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r
char* cId = extractKeyFromLink((char*)args,"Hgameobject");
@@ -1096,109 +641,24 @@ bool ChatHandler::HandleTurnObjectCommand(const char* args)
o = chr->GetOrientation();
}
- float rot2 = sin(o/2);
- float rot3 = cos(o/2);
-
- Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
+ Map* map = obj->GetMap();
map->Remove(obj,false);
obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o);
-
- obj->SetFloatValue(GAMEOBJECT_FACING, o);
- obj->SetFloatValue(GAMEOBJECT_ROTATION+2, rot2);
- obj->SetFloatValue(GAMEOBJECT_ROTATION+3, rot3);
+ obj->UpdateRotationFields();
map->Add(obj);
obj->SaveToDB();
obj->Refresh();
- PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), o);
-
- return true;
-}
-
-//move selected creature
-bool ChatHandler::HandleNpcMoveCommand(const char* args)
-{
- uint32 lowguid = 0;
-
- Creature* pCreature = getSelectedCreature();
-
- if(!pCreature)
- {
- // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hcreature");
- if(!cId)
- return false;
-
- uint32 lowguid = atoi(cId);
-
- /* FIXME: impossibel without entry
- if(lowguid)
- pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
- */
-
- // Attempting creature load from DB data
- if(!pCreature)
- {
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 map_id = data->mapid;
-
- if(m_session->GetPlayer()->GetMapId()!=map_id)
- {
- PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- }
- else
- {
- lowguid = pCreature->GetDBTableGUIDLow();
- }
- }
- else
- {
- lowguid = pCreature->GetDBTableGUIDLow();
- }
-
- float x = m_session->GetPlayer()->GetPositionX();
- float y = m_session->GetPlayer()->GetPositionY();
- float z = m_session->GetPlayer()->GetPositionZ();
- float o = m_session->GetPlayer()->GetOrientation();
+ PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow(), o);
- if (pCreature)
- {
- if(CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow()))
- {
- const_cast<CreatureData*>(data)->posX = x;
- const_cast<CreatureData*>(data)->posY = y;
- const_cast<CreatureData*>(data)->posZ = z;
- const_cast<CreatureData*>(data)->orientation = o;
- }
- MapManager::Instance().GetMap(pCreature->GetMapId(),pCreature)->CreatureRelocation(pCreature,x, y, z,o);
- pCreature->GetMotionMaster()->Initialize();
- if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- pCreature->setDeathState(JUST_DIED);
- pCreature->Respawn();
- }
- }
-
- WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid);
- PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
return true;
}
//move selected object
-bool ChatHandler::HandleMoveObjectCommand(const char* args)
+bool ChatHandler::HandleGameObjectMoveCommand(const char* args)
{
// number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
char* cId = extractKeyFromLink((char*)args,"Hgameobject");
@@ -1230,7 +690,7 @@ bool ChatHandler::HandleMoveObjectCommand(const char* args)
{
Player *chr = m_session->GetPlayer();
- Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
+ Map* map = obj->GetMap();
map->Remove(obj,false);
obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation());
@@ -1256,7 +716,7 @@ bool ChatHandler::HandleMoveObjectCommand(const char* args)
return false;
}
- Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
+ Map* map = obj->GetMap();
map->Remove(obj,false);
obj->Relocate(x, y, z, obj->GetOrientation());
@@ -1270,25 +730,422 @@ bool ChatHandler::HandleMoveObjectCommand(const char* args)
obj->SaveToDB();
obj->Refresh();
- PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow());
+ PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow());
return true;
}
-//demorph player or unit
-bool ChatHandler::HandleDeMorphCommand(const char* /*args*/)
+//spawn go
+bool ChatHandler::HandleGameObjectAddCommand(const char* args)
{
- Unit *target = getSelectedUnit();
+ if (!*args)
+ return false;
+
+ // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry");
+ if(!cId)
+ return false;
+
+ uint32 id = atol(cId);
+ if(!id)
+ return false;
+
+ char* spawntimeSecs = strtok(NULL, " ");
+
+ const GameObjectInfo *goI = objmgr.GetGameObjectInfo(id);
+
+ if (!goI)
+ {
+ PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Player *chr = m_session->GetPlayer();
+ float x = float(chr->GetPositionX());
+ float y = float(chr->GetPositionY());
+ float z = float(chr->GetPositionZ());
+ float o = float(chr->GetOrientation());
+ Map *map = chr->GetMap();
+
+ GameObject* pGameObj = new GameObject;
+ uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
+
+ if(!pGameObj->Create(db_lowGUID, goI->id, map, chr->GetPhaseMaskForSpawn(), x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
+ {
+ delete pGameObj;
+ return false;
+ }
+
+ if( spawntimeSecs )
+ {
+ uint32 value = atoi((char*)spawntimeSecs);
+ pGameObj->SetRespawnTime(value);
+ //sLog.outDebug("*** spawntimeSecs: %d", value);
+ }
+
+ // fill the gameobject data and save to the db
+ pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()),chr->GetPhaseMaskForSpawn());
+
+ // this will generate a new guid if the object is in an instance
+ if(!pGameObj->LoadFromDB(db_lowGUID, map))
+ {
+ delete pGameObj;
+ return false;
+ }
+
+ sLog.outDebug(GetMangosString(LANG_GAMEOBJECT_CURRENT), goI->name, db_lowGUID, x, y, z, o);
+
+ map->Add(pGameObj);
+
+ // TODO: is it really necessary to add both the real and DB table guid here ?
+ objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID));
+
+ PSendSysMessage(LANG_GAMEOBJECT_ADD,id,goI->name,db_lowGUID,x,y,z);
+ return true;
+}
+
+//set pahsemask for selected object
+bool ChatHandler::HandleGameObjectPhaseCommand(const char* args)
+{
+ // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject");
+ if(!cId)
+ return false;
+
+ uint32 lowguid = atoi(cId);
+ if(!lowguid)
+ return false;
+
+ GameObject* obj = NULL;
+
+ // by DB guid
+ if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
+ obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
+
+ if(!obj)
+ {
+ PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* phaseStr = strtok (NULL, " ");
+ uint32 phasemask = phaseStr? atoi(phaseStr) : 0;
+ if ( phasemask == 0 )
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ obj->SetPhaseMask(phasemask,true);
+ obj->SaveToDB();
+ return true;
+}
+
+bool ChatHandler::HandleGameObjectNearCommand(const char* args)
+{
+ float distance = (!*args) ? 10 : atol(args);
+ uint32 count = 0;
+
+ Player* pl = m_session->GetPlayer();
+ QueryResult *result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, "
+ "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ "
+ "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' ORDER BY order_",
+ pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),
+ pl->GetMapId(),pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),distance*distance);
+
+ if (result)
+ {
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 guid = fields[0].GetUInt32();
+ uint32 entry = fields[1].GetUInt32();
+ float x = fields[2].GetFloat();
+ float y = fields[3].GetFloat();
+ float z = fields[4].GetFloat();
+ int mapid = fields[5].GetUInt16();
+
+ GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(entry);
+
+ if(!gInfo)
+ continue;
+
+ PSendSysMessage(LANG_GO_LIST_CHAT, guid, guid, gInfo->name, x, y, z, mapid);
+
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+ }
+
+ PSendSysMessage(LANG_COMMAND_NEAROBJMESSAGE,distance,count);
+ return true;
+}
+
+bool ChatHandler::HandleGUIDCommand(const char* /*args*/)
+{
+ uint64 guid = m_session->GetPlayer()->GetSelection();
+
+ if (guid == 0)
+ {
+ SendSysMessage(LANG_NO_SELECTION);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ PSendSysMessage(LANG_OBJECT_GUID, GUID_LOPART(guid), GUID_HIPART(guid));
+ return true;
+}
+
+bool ChatHandler::HandleLookupFactionCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ // Can be NULL at console call
+ Player *target = getSelectedPlayer ();
+
+ std::string namepart = args;
+ std::wstring wnamepart;
+
+ if (!Utf8toWStr (namepart,wnamepart))
+ return false;
+
+ // converting string that we try to find to lower case
+ wstrToLower (wnamepart);
+
+ uint32 counter = 0; // Counter for figure out that we found smth.
+
+ for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id)
+ {
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry (id);
+ if (factionEntry)
+ {
+ FactionState const* repState = target ? target->GetReputationMgr().GetState(factionEntry) : NULL;
+
+ int loc = GetSessionDbcLocale();
+ std::string name = factionEntry->name[loc];
+ if(name.empty())
+ continue;
+
+ if (!Utf8FitTo(name, wnamepart))
+ {
+ loc = 0;
+ for(; loc < MAX_LOCALE; ++loc)
+ {
+ if(loc==GetSessionDbcLocale())
+ continue;
+
+ name = factionEntry->name[loc];
+ if(name.empty())
+ continue;
+
+ if (Utf8FitTo(name, wnamepart))
+ break;
+ }
+ }
+
+ if(loc < MAX_LOCALE)
+ {
+ // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format
+ // or "id - [faction] [no reputation]" format
+ std::ostringstream ss;
+ if (m_session)
+ ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r";
+ else
+ ss << id << " - " << name << " " << localeNames[loc];
+
+ if (repState) // and then target!=NULL also
+ {
+ ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry);
+ std::string rankName = GetMangosString(ReputationRankStrIndex[rank]);
+
+ ss << " " << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ")";
+
+ if(repState->Flags & FACTION_FLAG_VISIBLE)
+ ss << GetTrinityString(LANG_FACTION_VISIBLE);
+ if(repState->Flags & FACTION_FLAG_AT_WAR)
+ ss << GetTrinityString(LANG_FACTION_ATWAR);
+ if(repState->Flags & FACTION_FLAG_PEACE_FORCED)
+ ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
+ if(repState->Flags & FACTION_FLAG_HIDDEN)
+ ss << GetTrinityString(LANG_FACTION_HIDDEN);
+ if(repState->Flags & FACTION_FLAG_INVISIBLE_FORCED)
+ ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
+ if(repState->Flags & FACTION_FLAG_INACTIVE)
+ ss << GetTrinityString(LANG_FACTION_INACTIVE);
+ }
+ else
+ ss << GetTrinityString(LANG_FACTION_NOREPUTATION);
+
+ SendSysMessage(ss.str().c_str());
+ counter++;
+ }
+ }
+ }
+
+ if (counter == 0) // if counter == 0 then we found nth
+ SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND);
+ return true;
+}
+
+bool ChatHandler::HandleModifyRepCommand(const char * args)
+{
+ if (!*args) return false;
+
+ Player* target = NULL;
+ target = getSelectedPlayer();
+
if(!target)
- target = m_session->GetPlayer();
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
- target->DeMorph();
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+ char* factionTxt = extractKeyFromLink((char*)args,"Hfaction");
+ if(!factionTxt)
+ return false;
+
+ uint32 factionId = atoi(factionTxt);
+
+ int32 amount = 0;
+ char *rankTxt = strtok(NULL, " ");
+ if (!factionTxt || !rankTxt)
+ return false;
+
+ amount = atoi(rankTxt);
+ if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0]))
+ {
+ std::string rankStr = rankTxt;
+ std::wstring wrankStr;
+ if(!Utf8toWStr(rankStr,wrankStr))
+ return false;
+ wstrToLower( wrankStr );
+
+ int r = 0;
+ amount = -42000;
+ for (; r < MAX_REPUTATION_RANK; ++r)
+ {
+ std::string rank = GetTrinityString(ReputationRankStrIndex[r]);
+ if(rank.empty())
+ continue;
+
+ std::wstring wrank;
+ if(!Utf8toWStr(rank,wrank))
+ continue;
+
+ wstrToLower(wrank);
+
+ if(wrank.substr(0,wrankStr.size())==wrankStr)
+ {
+ char *deltaTxt = strtok(NULL, " ");
+ if (deltaTxt)
+ {
+ int32 delta = atoi(deltaTxt);
+ if ((delta < 0) || (delta > ReputationMgr::PointsInRank[r] -1))
+ {
+ PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (ReputationMgr::PointsInRank[r]-1));
+ SetSentErrorMessage(true);
+ return false;
+ }
+ amount += delta;
+ }
+ break;
+ }
+ amount += ReputationMgr::PointsInRank[r];
+ }
+ if (r >= MAX_REPUTATION_RANK)
+ {
+ PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId);
+
+ if (!factionEntry)
+ {
+ PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (factionEntry->reputationListID < 0)
+ {
+ PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->name[GetSessionDbcLocale()], factionId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target->GetReputationMgr().SetReputation(factionEntry,amount);
+ PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[GetSessionDbcLocale()], factionId,
+ GetNameLink(target).c_str(), target->GetReputationMgr().GetReputation(factionEntry));
+ return true;
+}
+
+//-----------------------Npc Commands-----------------------
+//add spawn of creature
+bool ChatHandler::HandleNpcAddCommand(const char* args)
+{
+ if(!*args)
+ return false;
+ char* charID = extractKeyFromLink((char*)args,"Hcreature_entry");
+ if(!charID)
+ return false;
+
+ char* team = strtok(NULL, " ");
+ int32 teamval = 0;
+ if (team) { teamval = atoi(team); }
+ if (teamval < 0) { teamval = 0; }
+
+ uint32 id = atoi(charID);
+
+ Player *chr = m_session->GetPlayer();
+ float x = chr->GetPositionX();
+ float y = chr->GetPositionY();
+ float z = chr->GetPositionZ();
+ float o = chr->GetOrientation();
+ Map *map = chr->GetMap();
+
+ Creature* pCreature = new Creature;
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, (uint32)teamval))
+ {
+ delete pCreature;
+ return false;
+ }
+
+ pCreature->Relocate(x,y,z,o);
+
+ if(!pCreature->IsPositionValid())
+ {
+ sLog.outError("Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ delete pCreature;
+ return false;
+ }
+
+ pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
+
+ uint32 db_guid = pCreature->GetDBTableGUIDLow();
+
+ // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
+ pCreature->LoadFromDB(db_guid, map);
+
+ map->Add(pCreature);
+ objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid));
return true;
}
//add item in vendorlist
-bool ChatHandler::HandleAddVendorItemCommand(const char* args)
+bool ChatHandler::HandleNpcAddVendorItemCommand(const char* args)
{
if (!*args)
return false;
@@ -1335,7 +1192,7 @@ bool ChatHandler::HandleAddVendorItemCommand(const char* args)
}
//del item from vendor list
-bool ChatHandler::HandleDelVendorItemCommand(const char* args)
+bool ChatHandler::HandleNpcDelVendorItemCommand(const char* args)
{
if (!*args)
return false;
@@ -1357,7 +1214,6 @@ bool ChatHandler::HandleDelVendorItemCommand(const char* args)
}
uint32 itemId = atol(pitem);
-
if(!objmgr.RemoveVendorItem(vendor->GetEntry(),itemId))
{
PSendSysMessage(LANG_ITEM_NOT_IN_LIST,itemId);
@@ -1413,9 +1269,11 @@ bool ChatHandler::HandleNpcAddMoveCommand(const char* args)
Player* player = m_session->GetPlayer();
+ //WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0);
+
// update movement type
WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
- if(pCreature && pCreature->GetWaypointPath())
+ if(pCreature && pCreature->GetWaypointPathId())
{
pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
pCreature->GetMotionMaster()->Initialize();
@@ -1427,10 +1285,198 @@ bool ChatHandler::HandleNpcAddMoveCommand(const char* args)
pCreature->SaveToDB();
}
+ SendSysMessage(LANG_WAYPOINT_ADDED);
+
return true;
}
-/**
+//change level of creature or pet
+bool ChatHandler::HandleNpcChangeLevelCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint8 lvl = (uint8) atoi((char*)args);
+ if ( lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3)
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Creature* pCreature = getSelectedCreature();
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(pCreature->isPet())
+ {
+ if(((Pet*)pCreature)->getPetType()==HUNTER_PET)
+ {
+ pCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(lvl)/4);
+ pCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
+ }
+ ((Pet*)pCreature)->GivePetLevel(lvl);
+ }
+ else
+ {
+ pCreature->SetMaxHealth( 100 + 30*lvl);
+ pCreature->SetHealth( 100 + 30*lvl);
+ pCreature->SetLevel( lvl);
+ pCreature->SaveToDB();
+ }
+
+ return true;
+}
+
+//set npcflag of creature
+bool ChatHandler::HandleNpcFlagCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 npcFlags = (uint32) atoi((char*)args);
+
+ Creature* pCreature = getSelectedCreature();
+
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);
+
+ WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry());
+
+ SendSysMessage(LANG_VALUE_SAVED_REJOIN);
+
+ return true;
+}
+
+bool ChatHandler::HandleNpcDeleteCommand(const char* args)
+{
+ Creature* unit = NULL;
+
+ if(*args)
+ {
+ // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hcreature");
+ if(!cId)
+ return false;
+
+ uint32 lowguid = atoi(cId);
+ if(!lowguid)
+ return false;
+
+ if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid))
+ unit = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT));
+ }
+ else
+ unit = getSelectedCreature();
+
+ if(!unit || unit->isPet() || unit->isTotem() || unit->isVehicle())
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Delete the creature
+ unit->CombatStop();
+ unit->DeleteFromDB();
+ unit->CleanupsBeforeDelete();
+ unit->AddObjectToRemoveList();
+
+ SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
+
+ return true;
+}
+
+//move selected creature
+bool ChatHandler::HandleNpcMoveCommand(const char* args)
+{
+ uint32 lowguid = 0;
+
+ Creature* pCreature = getSelectedCreature();
+
+ if(!pCreature)
+ {
+ // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hcreature");
+ if(!cId)
+ return false;
+
+ lowguid = atoi(cId);
+
+ /* FIXME: impossibel without entry
+ if(lowguid)
+ pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
+ */
+
+ // Attempting creature load from DB data
+ if(!pCreature)
+ {
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 map_id = data->mapid;
+
+ if(m_session->GetPlayer()->GetMapId()!=map_id)
+ {
+ PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ else
+ {
+ lowguid = pCreature->GetDBTableGUIDLow();
+ }
+ }
+ else
+ {
+ lowguid = pCreature->GetDBTableGUIDLow();
+ }
+
+ float x = m_session->GetPlayer()->GetPositionX();
+ float y = m_session->GetPlayer()->GetPositionY();
+ float z = m_session->GetPlayer()->GetPositionZ();
+ float o = m_session->GetPlayer()->GetOrientation();
+
+ if (pCreature)
+ {
+ if(CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow()))
+ {
+ const_cast<CreatureData*>(data)->posX = x;
+ const_cast<CreatureData*>(data)->posY = y;
+ const_cast<CreatureData*>(data)->posZ = z;
+ const_cast<CreatureData*>(data)->orientation = o;
+ }
+ pCreature->GetMap()->CreatureRelocation(pCreature,x, y, z,o);
+ pCreature->GetMotionMaster()->Initialize();
+ if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ pCreature->setDeathState(JUST_DIED);
+ pCreature->Respawn();
+ }
+ }
+
+ WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid);
+ PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
+ return true;
+}
+
+/**HandleNpcSetMoveTypeCommand
* Set the movement type for an NPC.<br/>
* <br/>
* Valid movement types are:
@@ -1545,11 +1591,15 @@ bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args)
else
return false;
+ // update movement type
+ //if(doNotDelete == false)
+ // WaypointMgr.DeletePath(lowguid);
+
if(pCreature)
{
// update movement type
if(doNotDelete == false)
- pCreature->LoadPath(0);
+ pCreature->SetWaypointPathId(0);
pCreature->SetDefaultMovementType(move_type);
pCreature->GetMotionMaster()->Initialize();
@@ -1570,23 +1620,49 @@ bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args)
}
return true;
-} // HandleNpcSetMoveTypeCommand
+}
-//change level of creature or pet
-bool ChatHandler::HandleChangeLevelCommand(const char* args)
+//set model of creature
+bool ChatHandler::HandleNpcSetModelCommand(const char* args)
{
if (!*args)
return false;
- uint8 lvl = (uint8) atoi((char*)args);
- if ( lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3)
+ uint32 displayId = (uint32) atoi((char*)args);
+
+ Creature *pCreature = getSelectedCreature();
+
+ if(!pCreature || pCreature->isPet())
{
- SendSysMessage(LANG_BAD_VALUE);
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ pCreature->SetDisplayId(displayId);
+ pCreature->SetNativeDisplayId(displayId);
+
+ pCreature->SaveToDB();
+
+ return true;
+}
+//set faction of creature
+bool ChatHandler::HandleNpcFactionIdCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 factionId = (uint32) atoi((char*)args);
+
+ if (!sFactionTemplateStore.LookupEntry(factionId))
+ {
+ PSendSysMessage(LANG_WRONG_FACTION, factionId);
SetSentErrorMessage(true);
return false;
}
Creature* pCreature = getSelectedCreature();
+
if(!pCreature)
{
SendSysMessage(LANG_SELECT_CREATURE);
@@ -1594,126 +1670,441 @@ bool ChatHandler::HandleChangeLevelCommand(const char* args)
return false;
}
- if(pCreature->isPet())
+ pCreature->setFaction(factionId);
+
+ // faction is set in creature_template - not inside creature
+
+ // update in memory
+ if(CreatureInfo const *cinfo = pCreature->GetCreatureInfo())
{
- ((Pet*)pCreature)->GivePetLevel(lvl);
+ const_cast<CreatureInfo*>(cinfo)->faction_A = factionId;
+ const_cast<CreatureInfo*>(cinfo)->faction_H = factionId;
+ }
+
+ // and DB
+ WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry());
+
+ return true;
+}
+//set spawn dist of creature
+bool ChatHandler::HandleNpcSpawnDistCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ float option = atof((char*)args);
+ if (option < 0.0f)
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ return false;
}
+
+ MovementGeneratorType mtype = IDLE_MOTION_TYPE;
+ if (option >0.0f)
+ mtype = RANDOM_MOTION_TYPE;
+
+ Creature *pCreature = getSelectedCreature();
+ uint32 u_guidlow = 0;
+
+ if (pCreature)
+ u_guidlow = pCreature->GetDBTableGUIDLow();
else
+ return false;
+
+ pCreature->SetRespawnRadius((float)option);
+ pCreature->SetDefaultMovementType(mtype);
+ pCreature->GetMotionMaster()->Initialize();
+ if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
{
- pCreature->SetMaxHealth( 100 + 30*lvl);
- pCreature->SetHealth( 100 + 30*lvl);
- pCreature->SetLevel( lvl);
- pCreature->SaveToDB();
+ pCreature->setDeathState(JUST_DIED);
+ pCreature->Respawn();
}
+ WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow);
+ PSendSysMessage(LANG_COMMAND_SPAWNDIST,option);
return true;
}
-
-//set npcflag of creature
-bool ChatHandler::HandleNpcFlagCommand(const char* args)
+//spawn time handling
+bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args)
{
- if (!*args)
+ if(!*args)
return false;
- uint32 npcFlags = (uint32) atoi((char*)args);
+ char* stime = strtok((char*)args, " ");
- Creature* pCreature = getSelectedCreature();
+ if (!stime)
+ return false;
- if(!pCreature)
+ int i_stime = atoi((char*)stime);
+
+ if (i_stime < 0)
{
- SendSysMessage(LANG_SELECT_CREATURE);
+ SendSysMessage(LANG_BAD_VALUE);
SetSentErrorMessage(true);
return false;
}
- pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);
+ Creature *pCreature = getSelectedCreature();
+ uint32 u_guidlow = 0;
- WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry());
+ if (pCreature)
+ u_guidlow = pCreature->GetDBTableGUIDLow();
+ else
+ return false;
- SendSysMessage(LANG_VALUE_SAVED_REJOIN);
+ WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow);
+ pCreature->SetRespawnDelay((uint32)i_stime);
+ PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime);
return true;
}
-
-//set model of creature
-bool ChatHandler::HandleNpcSetModelCommand(const char* args)
+//npc follow handling
+bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/)
{
- if (!*args)
+ Player *player = m_session->GetPlayer();
+ Creature *creature = getSelectedCreature();
+
+ if(!creature)
+ {
+ PSendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
return false;
+ }
- uint32 displayId = (uint32) atoi((char*)args);
+ // Follow player - Using pet's default dist and angle
+ creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
- Creature *pCreature = getSelectedCreature();
+ PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName());
+ return true;
+}
+//npc unfollow handling
+bool ChatHandler::HandleNpcUnFollowCommand(const char* /*args*/)
+{
+ Player *player = m_session->GetPlayer();
+ Creature *creature = getSelectedCreature();
- if(!pCreature || pCreature->isPet())
+ if(!creature)
{
- SendSysMessage(LANG_SELECT_CREATURE);
+ PSendSysMessage(LANG_SELECT_CREATURE);
SetSentErrorMessage(true);
return false;
}
- pCreature->SetDisplayId(displayId);
- pCreature->SetNativeDisplayId(displayId);
+ if (/*creature->GetMotionMaster()->empty() ||*/
+ creature->GetMotionMaster()->GetCurrentMovementGeneratorType ()!=TARGETED_MOTION_TYPE)
+ {
+ PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU);
+ SetSentErrorMessage(true);
+ return false;
+ }
- pCreature->SaveToDB();
+ TargetedMovementGenerator<Creature> const* mgen
+ = static_cast<TargetedMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
+
+ if(mgen->GetTarget()!=player)
+ {
+ PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // reset movement
+ creature->GetMotionMaster()->MovementExpired(true);
+ PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName());
return true;
}
+//npc tame handling
+bool ChatHandler::HandleNpcTameCommand(const char* /*args*/)
+{
+ Creature *creatureTarget = getSelectedCreature ();
+ if (!creatureTarget || creatureTarget->isPet ())
+ {
+ PSendSysMessage (LANG_SELECT_CREATURE);
+ SetSentErrorMessage (true);
+ return false;
+ }
-//morph creature or player
-bool ChatHandler::HandleMorphCommand(const char* args)
+ Player *player = m_session->GetPlayer ();
+
+ if(player->GetPetGUID ())
+ {
+ SendSysMessage (LANG_YOU_ALREADY_HAVE_PET);
+ SetSentErrorMessage (true);
+ return false;
+ }
+
+ CreatureInfo const* cInfo = creatureTarget->GetCreatureInfo();
+
+ if (!cInfo->isTameable ())
+ {
+ PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry);
+ SetSentErrorMessage (true);
+ return false;
+ }
+
+ // Everything looks OK, create new pet
+ Pet* pet = player->CreateTamedPetFrom (creatureTarget);
+ if (!pet)
+ {
+ PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry);
+ SetSentErrorMessage (true);
+ return false;
+ }
+
+ // place pet before player
+ float x,y,z;
+ player->GetClosePoint (x,y,z,creatureTarget->GetObjectSize (),CONTACT_DISTANCE);
+ pet->Relocate (x,y,z,M_PI-player->GetOrientation ());
+
+ // set pet to defensive mode by default (some classes can't control controlled pets in fact).
+ pet->SetReactState(REACT_DEFENSIVE);
+
+ // calculate proper level
+ uint32 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel();
+
+ // prepare visual effect for levelup
+ pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
+
+ // add to world
+ pet->GetMap()->Add((Creature*)pet);
+
+ // visual effect for levelup
+ pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
+
+ // caster have pet now
+ player->SetMinion(pet, true);
+
+ pet->SavePetToDB(PET_SAVE_AS_CURRENT);
+ player->PetSpellInitialize();
+
+ return true;
+}
+//npc phasemask handling
+//change phasemask of creature or pet
+bool ChatHandler::HandleNpcSetPhaseCommand(const char* args)
{
if (!*args)
return false;
- uint16 display_id = (uint16)atoi((char*)args);
+ uint32 phasemask = (uint32) atoi((char*)args);
+ if ( phasemask == 0 )
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
- Unit *target = getSelectedUnit();
- if(!target)
- target = m_session->GetPlayer();
+ Creature* pCreature = getSelectedCreature();
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
- target->SetDisplayId(display_id);
+ pCreature->SetPhaseMask(phasemask,true);
+
+ if(!pCreature->isPet())
+ pCreature->SaveToDB();
return true;
}
-
-//set faction of creature
-bool ChatHandler::HandleNpcFactionIdCommand(const char* args)
+//npc deathstate handling
+bool ChatHandler::HandleNpcSetDeathStateCommand(const char* args)
{
if (!*args)
return false;
- uint32 factionId = (uint32) atoi((char*)args);
+ Creature* pCreature = getSelectedCreature();
+ if(!pCreature || pCreature->isPet())
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
- if (!sFactionTemplateStore.LookupEntry(factionId))
+ if (strncmp(args, "on", 3) == 0)
+ pCreature->SetDeadByDefault(true);
+ else if (strncmp(args, "off", 4) == 0)
+ pCreature->SetDeadByDefault(false);
+ else
{
- PSendSysMessage(LANG_WRONG_FACTION, factionId);
+ SendSysMessage(LANG_USE_BOL);
SetSentErrorMessage(true);
return false;
}
- Creature* pCreature = getSelectedCreature();
+ pCreature->SaveToDB();
+ pCreature->Respawn();
+
+ return true;
+}
+
+//TODO: NpcCommands that need to be fixed :
+
+bool ChatHandler::HandleNpcNameCommand(const char* /*args*/)
+{
+ /* Temp. disabled
+ if(!*args)
+ return false;
+
+ if(strlen((char*)args)>75)
+ {
+ PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75);
+ return true;
+ }
+
+ for (uint8 i = 0; i < strlen(args); ++i)
+ {
+ if(!isalpha(args[i]) && args[i]!=' ')
+ {
+ SendSysMessage(LANG_CHARS_ONLY);
+ return false;
+ }
+ }
+
+ uint64 guid;
+ guid = m_session->GetPlayer()->GetSelection();
+ if (guid == 0)
+ {
+ SendSysMessage(LANG_NO_SELECTION);
+ return true;
+ }
+
+ Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
if(!pCreature)
{
SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
+ return true;
}
- pCreature->setFaction(factionId);
+ pCreature->SetName(args);
+ uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName());
+ pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
- // faction is set in creature_template - not inside creature
+ pCreature->SaveToDB();
+ */
- // update in memory
- if(CreatureInfo const *cinfo = pCreature->GetCreatureInfo())
+ return true;
+}
+
+bool ChatHandler::HandleNpcSubNameCommand(const char* /*args*/)
+{
+ /* Temp. disabled
+
+ if(!*args)
+ args = "";
+
+ if(strlen((char*)args)>75)
{
- const_cast<CreatureInfo*>(cinfo)->faction_A = factionId;
- const_cast<CreatureInfo*>(cinfo)->faction_H = factionId;
+
+ PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75);
+ return true;
}
- // and DB
- WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry());
+ for (uint8 i = 0; i < strlen(args); i++)
+ {
+ if(!isalpha(args[i]) && args[i]!=' ')
+ {
+ SendSysMessage(LANG_CHARS_ONLY);
+ return false;
+ }
+ }
+ uint64 guid;
+ guid = m_session->GetPlayer()->GetSelection();
+ if (guid == 0)
+ {
+ SendSysMessage(LANG_NO_SELECTION);
+ return true;
+ }
+
+ Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
+
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ return true;
+ }
+
+ uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID));
+ pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
+
+ pCreature->SaveToDB();
+ */
+ return true;
+}
+
+//move item to other slot
+bool ChatHandler::HandleItemMoveCommand(const char* args)
+{
+ if(!*args)
+ return false;
+ uint8 srcslot, dstslot;
+
+ char* pParam1 = strtok((char*)args, " ");
+ if (!pParam1)
+ return false;
+
+ char* pParam2 = strtok(NULL, " ");
+ if (!pParam2)
+ return false;
+
+ srcslot = (uint8)atoi(pParam1);
+ dstslot = (uint8)atoi(pParam2);
+
+ if(srcslot==dstslot)
+ return true;
+
+ if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot))
+ return false;
+
+ if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot))
+ return false;
+
+ uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot);
+ uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot);
+
+ m_session->GetPlayer()->SwapItem( src, dst );
+
+ return true;
+}
+
+//demorph player or unit
+bool ChatHandler::HandleDeMorphCommand(const char* /*args*/)
+{
+ Unit *target = getSelectedUnit();
+ if(!target)
+ target = m_session->GetPlayer();
+
+
+ // check online security
+ else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0))
+ return false;
+
+ target->DeMorph();
+
+ return true;
+}
+
+//morph creature or player
+bool ChatHandler::HandleModifyMorphCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint16 display_id = (uint16)atoi((char*)args);
+
+ Unit *target = getSelectedUnit();
+ if(!target)
+ target = m_session->GetPlayer();
+
+ // check online security
+ else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0))
+ return false;
+
+ target->SetDisplayId(display_id);
return true;
}
@@ -1721,7 +2112,7 @@ bool ChatHandler::HandleNpcFactionIdCommand(const char* args)
//kick player
bool ChatHandler::HandleKickPlayerCommand(const char *args)
{
- const char* kickName = strtok((char*)args, " ");
+/* const char* kickName = strtok((char*)args, " ");
char* kickReason = strtok(NULL, "\n");
std::string reason = "No Reason";
std::string kicker = "Console";
@@ -1731,7 +2122,7 @@ bool ChatHandler::HandleKickPlayerCommand(const char *args)
kicker = m_session->GetPlayer()->GetName();
if(!kickName)
- {
+ {
Player* player = getSelectedPlayer();
if(!player)
{
@@ -1747,14 +2138,16 @@ bool ChatHandler::HandleKickPlayerCommand(const char *args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(player, 0))
+ return false;
+
if(sWorld.getConfig(CONFIG_SHOW_KICK_IN_WORLD) == 1)
{
-
sWorld.SendWorldText(LANG_COMMAND_KICKMESSAGE, player->GetName(), kicker.c_str(), reason.c_str());
}
else
{
-
PSendSysMessage(LANG_COMMAND_KICKMESSAGE, player->GetName(), kicker.c_str(), reason.c_str());
}
@@ -1762,8 +2155,8 @@ bool ChatHandler::HandleKickPlayerCommand(const char *args)
}
else
{
- std::string name = kickName;
- if(!normalizePlayerName(name))
+ std::string name = extractPlayerNameFromLink((char*)kickName);
+ if(name.empty())
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
@@ -1785,83 +2178,82 @@ bool ChatHandler::HandleKickPlayerCommand(const char *args)
return false;
}
- if(m_session && player->GetSession()->GetSecurity() > m_session->GetSecurity())
+ if(HasLowerSecurity(player, 0))
{
SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); //maybe replacement string for this later on
SetSentErrorMessage(true);
return false;
}
- if(sWorld.KickPlayer(name.c_str()))
+ std::string nameLink = playerLink(name);
+
+ if(sWorld.KickPlayer(name))
{
if(sWorld.getConfig(CONFIG_SHOW_KICK_IN_WORLD) == 1)
{
-
- sWorld.SendWorldText(LANG_COMMAND_KICKMESSAGE, name.c_str(), kicker.c_str(), reason.c_str());
+ sWorld.SendWorldText(LANG_COMMAND_KICKMESSAGE, nameLink.c_str(), kicker.c_str(), reason.c_str());
}
else
{
- PSendSysMessage(LANG_COMMAND_KICKMESSAGE, name.c_str(), kicker.c_str(), reason.c_str());
+ PSendSysMessage(LANG_COMMAND_KICKMESSAGE,nameLink.c_str());
}
}
else
{
- PSendSysMessage(LANG_COMMAND_KICKNOTFOUNDPLAYER, name.c_str());
+ PSendSysMessage(LANG_COMMAND_KICKNOTFOUNDPLAYER,nameLink.c_str());
return false;
}
+ }*/
+ Player* target;
+ if(!extractPlayerTarget((char*)args,&target))
+ return false;
+
+ if (m_session && target==m_session->GetPlayer())
+ {
+ SendSysMessage(LANG_COMMAND_KICKSELF);
+ SetSentErrorMessage(true);
+ return false;
}
+
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
+ // send before target pointer invalidate
+ PSendSysMessage(LANG_COMMAND_KICKMESSAGE,GetNameLink(target).c_str());
+ target->GetSession()->KickPlayer();
return true;
}
-//show info of player
-bool ChatHandler::HandlePInfoCommand(const char* args)
+//set temporary phase mask for player
+bool ChatHandler::HandleModifyPhaseCommand(const char* args)
{
- Player* target = NULL;
- uint64 targetGUID = 0;
-
- char* px = strtok((char*)args, " ");
- char* py = NULL;
-
- std::string name;
+ if (!*args)
+ return false;
- if (px)
- {
- name = px;
+ uint32 phasemask = (uint32)atoi((char*)args);
- if(name.empty())
- return false;
+ Unit *target = getSelectedUnit();
+ if(!target)
+ target = m_session->GetPlayer();
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
+ // check online security
+ else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0))
+ return false;
- target = objmgr.GetPlayer(name.c_str());
- if (target)
- py = strtok(NULL, " ");
- else
- {
- targetGUID = objmgr.GetPlayerGUIDByName(name);
- if(targetGUID)
- py = strtok(NULL, " ");
- else
- py = px;
- }
- }
+ target->SetPhaseMask(phasemask,true);
- if(!target && !targetGUID)
- {
- target = getSelectedPlayer();
- }
+ return true;
+}
- if(!target && !targetGUID)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
+//show info of player
+bool ChatHandler::HandlePInfoCommand(const char* args)
+{
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
- }
uint32 accId = 0;
uint32 money = 0;
@@ -1872,8 +2264,10 @@ bool ChatHandler::HandlePInfoCommand(const char* args)
// get additional information from Player object
if(target)
{
- targetGUID = target->GetGUID();
- name = target->GetName(); // re-read for case getSelectedPlayer() target
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
accId = target->GetSession()->GetAccountId();
money = target->GetMoney();
total_player_time = target->GetTotalPlayedTime();
@@ -1883,28 +2277,26 @@ bool ChatHandler::HandlePInfoCommand(const char* args)
// get additional information from DB
else
{
- QueryResult *result = CharacterDatabase.PQuery("SELECT totaltime FROM characters WHERE guid = '%u'", GUID_LOPART(targetGUID));
+ // check offline security
+ if (HasLowerSecurity(NULL, target_guid))
+ return false;
+
+ // 0
+ QueryResult *result = CharacterDatabase.PQuery("SELECT totaltime FROM characters WHERE guid = '%u'", GUID_LOPART(target_guid));
if (!result)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
return false;
- }
+
Field *fields = result->Fetch();
total_player_time = fields[0].GetUInt32();
delete result;
Tokens data;
- if (!Player::LoadValuesArrayFromDB(data,targetGUID))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
+ if (!Player::LoadValuesArrayFromDB(data,target_guid))
return false;
- }
money = Player::GetUInt32ValueFromArray(data, PLAYER_FIELD_COINAGE);
level = Player::GetUInt32ValueFromArray(data, UNIT_FIELD_LEVEL);
- accId = objmgr.GetPlayerAccountIdByGUID(targetGUID);
+ accId = objmgr.GetPlayerAccountIdByGUID(target_guid);
}
std::string username = GetTrinityString(LANG_ERROR);
@@ -1933,7 +2325,9 @@ bool ChatHandler::HandlePInfoCommand(const char* args)
delete result;
}
- PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetTrinityString(LANG_OFFLINE)), name.c_str(), GUID_LOPART(targetGUID), username.c_str(), accId, security, last_ip.c_str(), last_login.c_str(), latency);
+ std::string nameLink = playerLink(target_name);
+
+ PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetMangosString(LANG_OFFLINE)), nameLink.c_str(), GUID_LOPART(target_guid), username.c_str(), accId, security, last_ip.c_str(), last_login.c_str(), latency);
std::string timeStr = secsToTimeString(total_player_time,true,true);
uint32 gold = money /GOLD;
@@ -1941,123 +2335,202 @@ bool ChatHandler::HandlePInfoCommand(const char* args)
uint32 copp = (money % GOLD) % SILVER;
PSendSysMessage(LANG_PINFO_LEVEL, timeStr.c_str(), level, gold,silv,copp );
- if ( py && strncmp(py, "rep", 3) == 0 )
+ return true;
+}
+
+/*//show tickets
+void ChatHandler::ShowTicket(uint64 guid, char const* text, char const* time)
+{
+ std::string name;
+ if(!objmgr.GetPlayerNameByGUID(guid,name))
+ name = GetTrinityString(LANG_UNKNOWN);
+
+ std::string nameLink = playerLink(name);
+
+ PSendSysMessage(LANG_COMMAND_TICKETVIEW, nameLink.c_str(),time,text);
+}
+
+//ticket commands
+bool ChatHandler::HandleTicketCommand(const char* args)
+{
+ char* px = strtok((char*)args, " ");
+
+ // ticket<end>
+ if (!px)
{
- if(!target)
+ if(!m_session)
{
- // rep option not implemented for offline case
- SendSysMessage(LANG_PINFO_NO_REP);
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
- char* FactionName;
- for(FactionStateList::const_iterator itr = target->m_factions.begin(); itr != target->m_factions.end(); ++itr)
+ size_t count = ticketmgr.GetTicketCount();
+
+ bool accept = m_session->GetPlayer()->isAcceptTickets();
+
+ PSendSysMessage(LANG_COMMAND_TICKETCOUNT, count, accept ? GetTrinityString(LANG_ON) : GetTrinityString(LANG_OFF));
+ return true;
+ }
+
+ // ticket on
+ if(strncmp(px,"on",3) == 0)
+ {
+ if(!m_session)
{
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID);
- if (factionEntry)
- FactionName = factionEntry->name[m_session->GetSessionDbcLocale()];
- else
- FactionName = "#Not found#";
- ReputationRank rank = target->GetReputationRank(factionEntry);
- std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]);
- std::ostringstream ss;
- ss << itr->second.ID << ": |cffffffff|Hfaction:" << itr->second.ID << "|h[" << FactionName << "]|h|r " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")";
-
- if(itr->second.Flags & FACTION_FLAG_VISIBLE)
- ss << GetTrinityString(LANG_FACTION_VISIBLE);
- if(itr->second.Flags & FACTION_FLAG_AT_WAR)
- ss << GetTrinityString(LANG_FACTION_ATWAR);
- if(itr->second.Flags & FACTION_FLAG_PEACE_FORCED)
- ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
- if(itr->second.Flags & FACTION_FLAG_HIDDEN)
- ss << GetTrinityString(LANG_FACTION_HIDDEN);
- if(itr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED)
- ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
- if(itr->second.Flags & FACTION_FLAG_INACTIVE)
- ss << GetTrinityString(LANG_FACTION_INACTIVE);
-
- SendSysMessage(ss.str().c_str());
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
}
- }
- return true;
-}
-//set spawn dist of creature
-bool ChatHandler::HandleNpcSpawnDistCommand(const char* args)
-{
- if(!*args)
- return false;
+ m_session->GetPlayer()->SetAcceptTicket(true);
+ SendSysMessage(LANG_COMMAND_TICKETON);
+ return true;
+ }
- float option = atof((char*)args);
- if (option < 0.0f)
+ // ticket off
+ if(strncmp(px,"off",4) == 0)
{
- SendSysMessage(LANG_BAD_VALUE);
- return false;
+ if(!m_session)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ m_session->GetPlayer()->SetAcceptTicket(false);
+ SendSysMessage(LANG_COMMAND_TICKETOFF);
+ return true;
}
- MovementGeneratorType mtype = IDLE_MOTION_TYPE;
- if (option >0.0f)
- mtype = RANDOM_MOTION_TYPE;
+ // ticket #num
+ int num = atoi(px);
+ if(num > 0)
+ {
+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid,ticket_text,ticket_lastchange FROM character_ticket ORDER BY ticket_id ASC "_OFFSET_, num-1);
- Creature *pCreature = getSelectedCreature();
- uint32 u_guidlow = 0;
+ if(!result)
+ {
+ PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num);
+ SetSentErrorMessage(true);
+ return false;
+ }
- if (pCreature)
- u_guidlow = pCreature->GetDBTableGUIDLow();
- else
- return false;
+ Field* fields = result->Fetch();
- pCreature->SetRespawnRadius((float)option);
- pCreature->SetDefaultMovementType(mtype);
- pCreature->GetMotionMaster()->Initialize();
- if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- pCreature->setDeathState(JUST_DIED);
- pCreature->Respawn();
+ uint32 guid = fields[0].GetUInt32();
+ char const* text = fields[1].GetString();
+ char const* time = fields[2].GetString();
+
+ ShowTicket(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER),text,time);
+ delete result;
+ return true;
}
- WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow);
- PSendSysMessage(LANG_COMMAND_SPAWNDIST,option);
+ uint64 target_guid;
+ if(!extractPlayerTarget(px,NULL,&target_guid))
+ return false;
+
+ // ticket $char_name
+ GMTicket* ticket = ticketmgr.GetGMTicket(GUID_LOPART(target_guid));
+ if(!ticket)
+ return false;
+
+ std::string time = TimeToTimestampStr(ticket->GetLastUpdate());
+
+ ShowTicket(target_guid, ticket->GetText(), time.c_str());
+
return true;
}
-bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args)
+//dell all tickets
+bool ChatHandler::HandleDelTicketCommand(const char *args)
{
- if(!*args)
+ char* px = strtok((char*)args, " ");
+ if (!px)
return false;
- char* stime = strtok((char*)args, " ");
-
- if (!stime)
- return false;
+ // delticket all
+ if(strncmp(px,"all",4) == 0)
+ {
+ ticketmgr.DeleteAll();
+ SendSysMessage(LANG_COMMAND_ALLTICKETDELETED);
+ return true;
+ }
- int i_stime = atoi((char*)stime);
+ int num = (uint32)atoi(px);
- if (i_stime < 0)
+ // delticket #num
+ if(num > 0)
{
- SendSysMessage(LANG_BAD_VALUE);
- SetSentErrorMessage(true);
- return false;
- }
+ QueryResult* result = CharacterDatabase.PQuery("SELECT guid FROM character_ticket ORDER BY ticket_id ASC "_OFFSET_,num-1);
+ if(!result)
+ {
+ PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ Field* fields = result->Fetch();
+ uint32 guid = fields[0].GetUInt32();
+ delete result;
- Creature *pCreature = getSelectedCreature();
- uint32 u_guidlow = 0;
+ ticketmgr.Delete(guid);
- if (pCreature)
- u_guidlow = pCreature->GetDBTableGUIDLow();
- else
+ //notify player
+ if(Player* pl = objmgr.GetPlayer(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)))
+ {
+ pl->GetSession()->SendGMTicketGetTicket(0x0A, 0);
+ PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL, GetNameLink(pl).c_str());
+ }
+ else
+ PSendSysMessage(LANG_COMMAND_TICKETDEL);
+
+ return true;
+ }
+
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget(px,&target,&target_guid,&target_name))
return false;
- WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow);
- pCreature->SetRespawnDelay((uint32)i_stime);
- PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime);
+ // delticket $char_name
+ ticketmgr.Delete(GUID_LOPART(target_guid));
+
+ // notify players about ticket deleting
+ if(target)
+ target->GetSession()->SendGMTicketGetTicket(0x0A,0);
+
+ std::string nameLink = playerLink(target_name);
+ PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL,nameLink.c_str());
return true;
-}
+}*/
+
/////WAYPOINT COMMANDS
+/**
+ * Add a waypoint to a creature.
+ *
+ * The user can either select an npc or provide its GUID.
+ *
+ * The user can even select a visual waypoint - then the new waypoint
+ * is placed *after* the selected one - this makes insertion of new
+ * waypoints possible.
+ *
+ * eg:
+ * .wp add 12345
+ * -> adds a waypoint to the npc with the GUID 12345
+ *
+ * .wp add
+ * -> adds a waypoint to the currently selected creature
+ *
+ *
+ * @param args if the user did not provide a GUID, it is NULL
+ *
+ * @return true - command did succeed, false - something went wrong
+ */
bool ChatHandler::HandleWpAddCommand(const char* args)
{
sLog.outDebug("DEBUG: HandleWpAddCommand");
@@ -2075,7 +2548,7 @@ bool ChatHandler::HandleWpAddCommand(const char* args)
if (!path_number)
{
if(target)
- pathid = target->GetWaypointPath();
+ pathid = target->GetWaypointPathId();
else
{
QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(id) FROM waypoint_data");
@@ -2130,7 +2603,6 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args)
if(*args)
path_number = strtok((char*)args, " ");
-
uint32 pathid = 0;
uint32 guidlow = 0;
Creature* target = getSelectedCreature();
@@ -2161,6 +2633,7 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args)
return true;
}
+ /*
guidlow = target->GetDBTableGUIDLow();
QueryResult *result = WorldDatabase.PQuery( "SELECT guid FROM creature_addon WHERE guid = '%u'",guidlow);
@@ -2171,31 +2644,31 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args)
}
else
WorldDatabase.PExecute("INSERT INTO creature_addon(guid,path_id) VALUES ('%u','%u')", guidlow, pathid);
+ */
WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE, guidlow);
- target->LoadPath(pathid);
+ target->SetWaypointPathId(pathid);
target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
target->GetMotionMaster()->Initialize();
- target->Say("Path loaded.",0,0);
+ target->MonsterSay("Path loaded.",0,0);
return true;
}
-
bool ChatHandler::HandleReloadAllPaths(const char* args)
{
-if(!*args)
- return false;
+ if(!*args)
+ return false;
-uint32 id = atoi(args);
+ uint32 id = atoi(args);
-if(!id)
- return false;
+ if(!id)
+ return false;
PSendSysMessage("%s%s|r|cff00ffff%u|r", "|cff00ff00", "Loading Path: ", id);
WaypointMgr.UpdatePath(id);
- return true;
+ return true;
}
bool ChatHandler::HandleWpUnLoadPathCommand(const char *args)
@@ -2209,24 +2682,39 @@ bool ChatHandler::HandleWpUnLoadPathCommand(const char *args)
return true;
}
- if(target->GetCreatureAddon())
+ if(target->GetWaypointPathId())
{
- if(target->GetCreatureAddon()->path_id != 0)
+ uint32 pathId = target->GetDBTableGUIDLow() * 10;
+ if(target->GetWaypointPathId() == pathId)
{
- WorldDatabase.PExecute("DELETE FROM creature_addon WHERE guid = %u", target->GetGUIDLow());
- target->UpdateWaypointID(0);
- WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow);
- target->LoadPath(0);
- target->SetDefaultMovementType(IDLE_MOTION_TYPE);
- target->GetMotionMaster()->MoveTargetedHome();
- target->GetMotionMaster()->Initialize();
- target->Say("Path unloaded.",0,0);
- return true;
+ for(uint32 i = 1; i < 11; ++i)
+ {
+ if(i == 10)
+ {
+ PSendSysMessage("%s%s|r", "|cffff33ff", "Target cannot have more than 9 script paths. Unloading failed.");
+ break;
+ }
+
+ if(WaypointMgr.GetPath(++pathId))
+ continue;
+
+ WorldDatabase.PExecute("UPDATE waypoint_data SET id = %u WHERE id = %u", pathId, target->GetDBTableGUIDLow() * 10);
+ WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow);
+ target->SetWaypointPathId(0);
+ target->UpdateWaypointID(0);
+ target->SetDefaultMovementType(IDLE_MOTION_TYPE);
+ target->GetMotionMaster()->Initialize();
+ target->GetMotionMaster()->MoveTargetedHome();
+ PSendSysMessage("Path unloaded.");
+ break;
+ }
}
- PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path.");
- return true;
+ else
+ PSendSysMessage("%s%s|r", "|cffff33ff", "Target has path but that path is not its default path. Unloading failed.");
}
- PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path.");
+ else
+ PSendSysMessage("%s%s|r", "|cffff33ff", "Target has no loaded path.");
+
return true;
}
@@ -2507,7 +2995,7 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
// Did the user select a visual spawnpoint?
if(wpGuid)
- wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
+ wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
// attempt check creature existence by DB data
else
{
@@ -2577,7 +3065,7 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
if( wpGuid != 0 )
{
- wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
+ wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
wpCreature->CombatStop();
wpCreature->DeleteFromDB();
wpCreature->AddObjectToRemoveList();
@@ -2606,13 +3094,13 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
// Respawn the owner of the waypoints
if( wpGuid != 0 )
{
- wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
+ wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
wpCreature->CombatStop();
wpCreature->DeleteFromDB();
wpCreature->AddObjectToRemoveList();
// re-create
Creature* wpCreature2 = new Creature;
- if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, VISUAL_WAYPOINT, 0))
+ if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, 0))
{
PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
delete wpCreature2;
@@ -2622,12 +3110,12 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
if(!wpCreature2->IsPositionValid())
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature2->GetGUIDLow(),wpCreature2->GetEntry(),wpCreature2->GetPositionX(),wpCreature2->GetPositionY());
+ sLog.outError("Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature2->GetGUIDLow(),wpCreature2->GetEntry(),wpCreature2->GetPositionX(),wpCreature2->GetPositionY());
delete wpCreature2;
return false;
}
- wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map);
map->Add(wpCreature2);
@@ -2661,7 +3149,6 @@ bool ChatHandler::HandleWpModifyCommand(const char* args)
}
PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str);
-
return true;
}
@@ -2701,7 +3188,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
return false;
}
- pathid = target->GetWaypointPath();
+ pathid = target->GetWaypointPathId();
}
else
@@ -2718,11 +3205,8 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
pathid = atoi((char*)guid_str);
}
-
sLog.outDebug("DEBUG: HandleWpShowCommand: danach");
-
-
std::string show = show_str;
uint32 Maxpoint;
@@ -2801,7 +3285,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
{
Field *fields = result2->Fetch();
uint32 wpguid = fields[0].GetUInt32();
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
+ Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
if(!pCreature)
{
@@ -2843,7 +3327,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
float o = chr->GetOrientation();
Creature* wpCreature = new Creature;
- if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0))
+ if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0))
{
PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
delete wpCreature;
@@ -2855,7 +3339,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
if(!wpCreature->IsPositionValid())
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY());
+ sLog.outError("Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY());
delete wpCreature;
delete result;
return false;
@@ -2865,7 +3349,8 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
// set "wpguid" column to the visual waypoint
WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), pathid, point);
- wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
+ // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map);
map->Add(wpCreature);
@@ -2906,7 +3391,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
Map *map = chr->GetMap();
Creature* pCreature = new Creature;
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, id, 0))
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, chr->GetPhaseMaskForSpawn(), id, 0))
{
PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
delete pCreature;
@@ -2918,13 +3403,13 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
if(!pCreature->IsPositionValid())
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ sLog.outError("Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
delete pCreature;
delete result;
return false;
}
- pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map);
map->Add(pCreature);
@@ -2971,7 +3456,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
Map *map = chr->GetMap();
Creature* pCreature = new Creature;
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0))
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0))
{
PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id);
delete pCreature;
@@ -2983,13 +3468,13 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
if(!pCreature->IsPositionValid())
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ sLog.outError("Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
delete pCreature;
delete result;
return false;
}
- pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map);
map->Add(pCreature);
@@ -3018,7 +3503,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
{
Field *fields = result->Fetch();
uint32 guid = fields[0].GetUInt32();
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
+ Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
if(!pCreature)
{
@@ -3061,143 +3546,108 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
//////////// WAYPOINT COMMANDS //
//rename characters
-bool ChatHandler::HandleRenameCommand(const char* args)
+bool ChatHandler::HandleCharacterRenameCommand(const char* args)
{
- Player* target = NULL;
- uint64 targetGUID = 0;
- std::string oldname;
-
- char* px = strtok((char*)args, " ");
-
- if(px)
- {
- oldname = px;
-
- if(!normalizePlayerName(oldname))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- target = objmgr.GetPlayer(oldname.c_str());
-
- if (!target)
- targetGUID = objmgr.GetPlayerGUIDByName(oldname);
- }
-
- if(!target && !targetGUID)
- {
- target = getSelectedPlayer();
- }
-
- if(!target && !targetGUID)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
- }
if(target)
{
- PSendSysMessage(LANG_RENAME_PLAYER, target->GetName());
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
+ PSendSysMessage(LANG_RENAME_PLAYER, GetNameLink(target).c_str());
target->SetAtLoginFlag(AT_LOGIN_RENAME);
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", target->GetGUIDLow());
}
else
{
- PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldname.c_str(), GUID_LOPART(targetGUID));
- CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", GUID_LOPART(targetGUID));
+ // check offline security
+ if (HasLowerSecurity(NULL, target_guid))
+ return false;
+
+ std::string oldNameLink = playerLink(target_name);
+
+ 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));
}
return true;
}
-//spawn go
-bool ChatHandler::HandleGameObjectCommand(const char* args)
+// customize characters
+bool ChatHandler::HandleCharacterCustomizeCommand(const char* args)
{
- if (!*args)
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
- char* pParam1 = strtok((char*)args, " ");
- if (!pParam1)
- return false;
-
- uint32 id = atoi((char*)pParam1);
- if(!id)
- return false;
-
- char* spawntimeSecs = strtok(NULL, " ");
-
- const GameObjectInfo *goI = objmgr.GetGameObjectInfo(id);
-
- if (!goI)
+ if(target)
{
- PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
- SetSentErrorMessage(true);
- return false;
+ 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());
}
-
- Player *chr = m_session->GetPlayer();
- float x = float(chr->GetPositionX());
- float y = float(chr->GetPositionY());
- float z = float(chr->GetPositionZ());
- float o = float(chr->GetOrientation());
- Map *map = chr->GetMap();
-
- float rot2 = sin(o/2);
- float rot3 = cos(o/2);
-
- GameObject* pGameObj = new GameObject;
- uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
-
- if(!pGameObj->Create(db_lowGUID, goI->id, map, x, y, z, o, 0, 0, rot2, rot3, 0, 1))
+ else
{
- delete pGameObj;
- return false;
- }
+ std::string oldNameLink = playerLink(target_name);
- if( spawntimeSecs )
- {
- uint32 value = atoi((char*)spawntimeSecs);
- pGameObj->SetRespawnTime(value);
- //sLog.outDebug("*** spawntimeSecs: %d", value);
+ 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));
}
- // fill the gameobject data and save to the db
- pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ return true;
+}
- // this will generate a new guid if the object is in an instance
- if(!pGameObj->LoadFromDB(db_lowGUID, map))
- {
- delete pGameObj;
+bool ChatHandler::HandleCharacterReputationCommand(const char* args)
+{
+ Player* target;
+ if(!extractPlayerTarget((char*)args,&target))
return false;
- }
- sLog.outDebug(GetTrinityString(LANG_GAMEOBJECT_CURRENT), goI->name, db_lowGUID, x, y, z, o);
+ LocaleConstant loc = GetSessionDbcLocale();
- map->Add(pGameObj);
-
- // TODO: is it really necessary to add both the real and DB table guid here ?
- objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID));
+ FactionStateList const& targetFSL = target->GetReputationMgr().GetStateList();
+ for(FactionStateList::const_iterator itr = targetFSL.begin(); itr != targetFSL.end(); ++itr)
+ {
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID);
+ char const* factionName = factionEntry ? factionEntry->name[loc] : "#Not found#";
+ ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry);
+ std::string rankName = GetMangosString(ReputationRankStrIndex[rank]);
+ std::ostringstream ss;
+ if (m_session)
+ ss << itr->second.ID << " - |cffffffff|Hfaction:" << itr->second.ID << "|h[" << factionName << " " << localeNames[loc] << "]|h|r";
+ else
+ ss << itr->second.ID << " - " << factionName << " " << localeNames[loc];
- PSendSysMessage(LANG_GAMEOBJECT_ADD,id,goI->name,db_lowGUID,x,y,z);
- return true;
-}
+ ss << " " << rankName << " (" << target->GetReputationMgr().GetReputation(factionEntry) << ")";
-//show animation
-bool ChatHandler::HandleAnimCommand(const char* args)
-{
- if (!*args)
- return false;
+ if(itr->second.Flags & FACTION_FLAG_VISIBLE)
+ ss << GetMangosString(LANG_FACTION_VISIBLE);
+ if(itr->second.Flags & FACTION_FLAG_AT_WAR)
+ ss << GetMangosString(LANG_FACTION_ATWAR);
+ if(itr->second.Flags & FACTION_FLAG_PEACE_FORCED)
+ ss << GetMangosString(LANG_FACTION_PEACE_FORCED);
+ if(itr->second.Flags & FACTION_FLAG_HIDDEN)
+ ss << GetMangosString(LANG_FACTION_HIDDEN);
+ if(itr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED)
+ ss << GetMangosString(LANG_FACTION_INVISIBLE_FORCED);
+ if(itr->second.Flags & FACTION_FLAG_INACTIVE)
+ ss << GetMangosString(LANG_FACTION_INACTIVE);
- uint32 anim_id = atoi((char*)args);
- m_session->GetPlayer()->HandleEmoteCommand(anim_id);
+ SendSysMessage(ss.str().c_str());
+ }
return true;
}
//change standstate
-bool ChatHandler::HandleStandStateCommand(const char* args)
+bool ChatHandler::HandleModifyStandStateCommand(const char* args)
{
if (!*args)
return false;
@@ -3208,7 +3658,7 @@ bool ChatHandler::HandleStandStateCommand(const char* args)
return true;
}
-bool ChatHandler::HandleAddHonorCommand(const char* args)
+bool ChatHandler::HandleHonorAddCommand(const char* args)
{
if (!*args)
return false;
@@ -3221,6 +3671,10 @@ bool ChatHandler::HandleAddHonorCommand(const char* args)
return false;
}
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
uint32 amount = (uint32)atoi(args);
target->RewardHonor(NULL, 1, amount);
return true;
@@ -3236,11 +3690,15 @@ bool ChatHandler::HandleHonorAddKillCommand(const char* /*args*/)
return false;
}
+ // check online security
+ if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0))
+ return false;
+
m_session->GetPlayer()->RewardHonor(target, 1);
return true;
}
-bool ChatHandler::HandleUpdateHonorFieldsCommand(const char* /*args*/)
+bool ChatHandler::HandleHonorUpdateCommand(const char* /*args*/)
{
Player *target = getSelectedPlayer();
if(!target)
@@ -3250,6 +3708,10 @@ bool ChatHandler::HandleUpdateHonorFieldsCommand(const char* /*args*/)
return false;
}
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
+
target->UpdateHonorFields();
return true;
}
@@ -3270,8 +3732,8 @@ bool ChatHandler::HandleLookupEventCommand(const char* args)
uint32 counter = 0;
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
for(uint32 id = 0; id < events.size(); ++id )
{
@@ -3304,12 +3766,12 @@ bool ChatHandler::HandleEventActiveListCommand(const char* args)
{
uint32 counter = 0;
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
char const* active = GetTrinityString(LANG_ACTIVE);
- for(GameEvent::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr )
+ for(GameEventMgr::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr )
{
uint32 event_id = *itr;
GameEventData const& eventData = events[event_id];
@@ -3340,7 +3802,7 @@ bool ChatHandler::HandleEventInfoCommand(const char* args)
uint32 event_id = atoi(cId);
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
if(event_id >=events.size())
{
@@ -3357,7 +3819,7 @@ bool ChatHandler::HandleEventInfoCommand(const char* args)
return false;
}
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+ GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
bool active = activeEvents.find(event_id) != activeEvents.end();
char const* activeStr = active ? GetTrinityString(LANG_ACTIVE) : "";
@@ -3389,7 +3851,7 @@ bool ChatHandler::HandleEventStartCommand(const char* args)
int32 event_id = atoi(cId);
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
if(event_id < 1 || event_id >=events.size())
{
@@ -3406,7 +3868,7 @@ bool ChatHandler::HandleEventStartCommand(const char* args)
return false;
}
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+ GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
if(activeEvents.find(event_id) != activeEvents.end())
{
PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE,event_id);
@@ -3430,7 +3892,7 @@ bool ChatHandler::HandleEventStopCommand(const char* args)
int32 event_id = atoi(cId);
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
if(event_id < 1 || event_id >=events.size())
{
@@ -3447,7 +3909,7 @@ bool ChatHandler::HandleEventStopCommand(const char* args)
return false;
}
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+ GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
if(activeEvents.find(event_id) == activeEvents.end())
{
@@ -3462,38 +3924,16 @@ bool ChatHandler::HandleEventStopCommand(const char* args)
bool ChatHandler::HandleCombatStopCommand(const char* args)
{
- Player *player;
-
- if(*args)
- {
- std::string playername = args;
-
- if(!normalizePlayerName(playername))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- player = objmgr.GetPlayer(playername.c_str());
-
- if(!player)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
- }
- else
- {
- player = getSelectedPlayer();
+ Player* target;
+ if(!extractPlayerTarget((char*)args,&target))
+ return false;
- if (!player)
- player = m_session->GetPlayer();
- }
+ // check online security
+ if (HasLowerSecurity(target, 0))
+ return false;
- player->CombatStop();
- player->getHostilRefManager().deleteReferences();
+ target->CombatStop();
+ target->getHostilRefManager().deleteReferences();
return true;
}
@@ -3530,7 +3970,7 @@ bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/)
if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
continue;
- m_session->GetPlayer()->learnSpell(skillLine->spellId);
+ m_session->GetPlayer()->learnSpell(skillLine->spellId,false);
}
}
}
@@ -3576,7 +4016,7 @@ bool ChatHandler::HandleLearnAllRecipesCommand(const char* args)
skillInfo->categoryId != SKILL_CATEGORY_SECONDARY )
continue;
- int loc = m_session->GetSessionDbcLocale();
+ int loc = GetSessionDbcLocale();
std::string name = skillInfo->name[loc];
if(Utf8FitTo(name, wnamepart))
@@ -3603,7 +4043,7 @@ bool ChatHandler::HandleLearnAllRecipesCommand(const char* args)
continue;
if( !target->HasSpell(spellInfo->Id) )
- m_session->GetPlayer()->learnSpell(skillLine->spellId);
+ m_session->GetPlayer()->learnSpell(skillLine->spellId,false);
}
uint16 maxLevel = target->GetPureMaxSkillValue(skillInfo->id);
@@ -3642,7 +4082,7 @@ bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args)
char* limit_str = strtok (NULL, " ");
int32 limit = limit_str ? atoi (limit_str) : -1;
- if (!AccountMgr::normilizeString (account))
+ if (!AccountMgr::normalizeString (account))
return false;
LoginDatabase.escape_string (account);
@@ -3710,6 +4150,13 @@ bool ChatHandler::LookupPlayerSearchCommand(QueryResult* result, int32 limit)
delete result;
+ if(i==0) // empty accounts only
+ {
+ PSendSysMessage(LANG_NO_PLAYERS_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
return true;
}
@@ -3720,79 +4167,56 @@ bool ChatHandler::HandleServerCorpsesCommand(const char* /*args*/)
return true;
}
-bool ChatHandler::HandleRepairitemsCommand(const char* /*args*/)
+bool ChatHandler::HandleRepairitemsCommand(const char* args)
{
- Player *target = getSelectedPlayer();
+ Player* target;
+ if(!extractPlayerTarget((char*)args,&target))
+ return false;
- if(!target)
- {
- PSendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
+ // check online security
+ if (HasLowerSecurity(target, 0))
return false;
- }
// Repair items
target->DurabilityRepairAll(false, 0, false);
- PSendSysMessage(LANG_YOU_REPAIR_ITEMS, target->GetName());
+ PSendSysMessage(LANG_YOU_REPAIR_ITEMS, GetNameLink(target).c_str());
if(needReportToTarget(target))
- ChatHandler(target).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, GetName());
+ ChatHandler(target).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, GetNameLink().c_str());
return true;
}
-bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/)
+bool ChatHandler::HandleWaterwalkCommand(const char* args)
{
- Player *player = m_session->GetPlayer();
- Creature *creature = getSelectedCreature();
-
- if(!creature)
- {
- PSendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
+ if(!*args)
return false;
- }
- // Follow player - Using pet's default dist and angle
- creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
-
- PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName());
- return true;
-}
-
-bool ChatHandler::HandleNpcUnFollowCommand(const char* /*args*/)
-{
- Player *player = m_session->GetPlayer();
- Creature *creature = getSelectedCreature();
+ Player *player = getSelectedPlayer();
- if(!creature)
+ if(!player)
{
- PSendSysMessage(LANG_SELECT_CREATURE);
+ PSendSysMessage(LANG_NO_CHAR_SELECTED);
SetSentErrorMessage(true);
return false;
}
- if (/*creature->GetMotionMaster()->empty() ||*/
- creature->GetMotionMaster()->GetCurrentMovementGeneratorType ()!=TARGETED_MOTION_TYPE)
- {
- PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU);
- SetSentErrorMessage(true);
+ // check online security
+ if (HasLowerSecurity(player, 0))
return false;
- }
- TargetedMovementGenerator<Creature> const* mgen
- = static_cast<TargetedMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
-
- if(mgen->GetTarget()!=player)
+ if (strncmp(args, "on", 3) == 0)
+ player->SetMovement(MOVE_WATER_WALK); // ON
+ else if (strncmp(args, "off", 4) == 0)
+ player->SetMovement(MOVE_LAND_WALK); // OFF
+ else
{
- PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU);
- SetSentErrorMessage(true);
+ SendSysMessage(LANG_USE_BOL);
return false;
}
- // reset movement
- creature->GetMotionMaster()->MovementExpired(true);
-
- PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName());
+ PSendSysMessage(LANG_YOU_SET_WATERWALK, args, GetNameLink(player).c_str());
+ if(needReportToTarget(player))
+ ChatHandler(player).PSendSysMessage(LANG_YOUR_WATERWALK_SET, args, GetNameLink().c_str());
return true;
}
@@ -3825,7 +4249,7 @@ bool ChatHandler::HandleCreatePetCommand(const char* args)
}
// Everything looks OK, create new pet
- Pet* pet = new Pet(HUNTER_PET);
+ Pet* pet = new Pet(player, HUNTER_PET);
if(!pet)
return false;
@@ -3841,7 +4265,6 @@ bool ChatHandler::HandleCreatePetCommand(const char* args)
creatureTarget->RemoveCorpse();
creatureTarget->SetHealth(0); // just for nice GM-mode view
- pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, player->GetGUID());
pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, player->GetGUID());
pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, player->getFaction());
@@ -3858,16 +4281,15 @@ bool ChatHandler::HandleCreatePetCommand(const char* args)
pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
// this enables pet details window (Shift+P)
- pet->AIM_Initialize();
pet->InitPetCreateSpells();
pet->SetHealth(pet->GetMaxHealth());
- MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet);
+ pet->GetMap()->Add((Creature*)pet);
// visual effect for levelup
pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel());
- player->SetPet(pet);
+ player->SetMinion(pet, true);
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
player->PetSpellInitialize();
@@ -3935,7 +4357,7 @@ bool ChatHandler::HandlePetUnlearnCommand(const char *args)
uint32 spellId = extractSpellIdFromLink((char*)args);
if(pet->HasSpell(spellId))
- pet->removeSpell(spellId);
+ pet->removeSpell(spellId, false);
else
PSendSysMessage("Pet doesn't have that spell");
@@ -3959,7 +4381,7 @@ bool ChatHandler::HandlePetTpCommand(const char *args)
uint32 tp = atol(args);
- pet->SetTP(tp);
+ //pet->SetTP(tp);
PSendSysMessage("Pet's tp changed to %u", tp);
return true;
@@ -4084,13 +4506,13 @@ bool ChatHandler::HandleNpcAddFormationCommand(const char* args)
FormationInfo *group_member;
group_member = new FormationInfo;
- group_member->follow_angle = pCreature->GetAngle(chr) - chr->GetOrientation();
+ group_member->follow_angle = (pCreature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
group_member->follow_dist = sqrtf(pow(chr->GetPositionX() - pCreature->GetPositionX(),int(2))+pow(chr->GetPositionY()-pCreature->GetPositionY(),int(2)));
group_member->leaderGUID = leaderGUID;
group_member->groupAI = 0;
CreatureGroupMap[lowguid] = group_member;
- pCreature->SearchFormation();
+ pCreature->SearchFormationAndPath();
WorldDatabase.PExecuteLog("INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES ('%u','%u','%f', '%f', '%u')",
leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI);
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index 128971f0153..724dfe24a36 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -36,7 +36,6 @@
#include "Guild.h"
#include "ObjectAccessor.h"
#include "MapManager.h"
-#include "SpellAuras.h"
#include "ScriptCalls.h"
#include "Language.h"
#include "GridNotifiersImpl.h"
@@ -54,6 +53,7 @@
#include "InstanceSaveMgr.h"
#include "InstanceData.h"
#include "AuctionHouseBot.h"
+#include "CreatureEventAIMgr.h"
bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
{
@@ -526,20 +526,13 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
}
//reload commands
-bool ChatHandler::HandleReloadCommand(const char* arg)
-{
- // this is error catcher for wrong table name in .reload commands
- PSendSysMessage("Db table with name starting from '%s' not found and can't be reloaded.",arg);
- SetSentErrorMessage(true);
- return false;
-}
-
bool ChatHandler::HandleReloadAllCommand(const char*)
{
- HandleReloadAreaTriggerTeleportCommand("");
HandleReloadSkillFishingBaseLevelCommand("");
+ HandleReloadAllAchievementCommand("");
HandleReloadAllAreaCommand("");
+ HandleReloadAllEventAICommand("");
HandleReloadAllLootCommand("");
HandleReloadAllNpcCommand("");
HandleReloadAllQuestCommand("");
@@ -554,6 +547,13 @@ bool ChatHandler::HandleReloadAllCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadAllAchievementCommand(const char*)
+{
+ HandleReloadAchievementCriteriaDataCommand("");
+ HandleReloadAchievementRewardCommand("");
+ return true;
+}
+
bool ChatHandler::HandleReloadAllAreaCommand(const char*)
{
//HandleReloadQuestAreaTriggersCommand(""); -- reloaded in HandleReloadAllQuestCommand
@@ -577,6 +577,8 @@ bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/)
HandleReloadNpcOptionCommand("a");
HandleReloadNpcTrainerCommand("a");
HandleReloadNpcVendorCommand("a");
+ HandleReloadPointsOfInterestCommand("a");
+ HandleReloadSpellClickSpellsCommand("a");
return true;
}
@@ -612,16 +614,26 @@ bool ChatHandler::HandleReloadAllScriptsCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadAllEventAICommand(const char*)
+{
+ HandleReloadEventAITextsCommand("a");
+ HandleReloadEventAISummonsCommand("a");
+ HandleReloadEventAIScriptsCommand("a");
+ return true;
+}
+
bool ChatHandler::HandleReloadAllSpellCommand(const char*)
{
HandleReloadSkillDiscoveryTemplateCommand("a");
HandleReloadSkillExtraItemTemplateCommand("a");
HandleReloadSpellAffectCommand("a");
HandleReloadSpellRequiredCommand("a");
+ HandleReloadSpellAreaCommand("a");
HandleReloadSpellElixirCommand("a");
HandleReloadSpellLearnSpellCommand("a");
HandleReloadSpellLinkedSpellCommand("a");
HandleReloadSpellProcEventCommand("a");
+ HandleReloadSpellBonusesCommand("a");
HandleReloadSpellScriptTargetCommand("a");
HandleReloadSpellTargetPositionCommand("a");
HandleReloadSpellThreatsCommand("a");
@@ -639,11 +651,13 @@ bool ChatHandler::HandleReloadAllItemCommand(const char*)
bool ChatHandler::HandleReloadAllLocalesCommand(const char* /*args*/)
{
+ HandleReloadLocalesAchievementRewardCommand("a");
HandleReloadLocalesCreatureCommand("a");
HandleReloadLocalesGameobjectCommand("a");
HandleReloadLocalesItemCommand("a");
HandleReloadLocalesNpcTextCommand("a");
HandleReloadLocalesPageTextCommand("a");
+ HandleReloadLocalesPointsOfInterestCommand("a");
HandleReloadLocalesQuestCommand("a");
return true;
}
@@ -656,6 +670,22 @@ bool ChatHandler::HandleReloadConfigCommand(const char* /*args*/)
return true;
}
+bool ChatHandler::HandleReloadAchievementCriteriaDataCommand(const char*)
+{
+ sLog.outString( "Re-Loading Additional Achievement Criteria Data..." );
+ achievementmgr.LoadAchievementCriteriaData();
+ SendGlobalSysMessage("DB table `achievement_criteria_data` reloaded.");
+ return true;
+}
+
+bool ChatHandler::HandleReloadAchievementRewardCommand(const char*)
+{
+ sLog.outString( "Re-Loading Achievement Reward Data..." );
+ achievementmgr.LoadRewards();
+ SendGlobalSysMessage("DB table `achievement_reward` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadAreaTriggerTavernCommand(const char*)
{
sLog.outString( "Re-Loading Tavern Area Triggers..." );
@@ -740,6 +770,11 @@ bool ChatHandler::HandleReloadQuestTemplateCommand(const char*)
sLog.outString( "Re-Loading Quest Templates..." );
objmgr.LoadQuests();
SendGlobalGMSysMessage("DB table `quest_template` (quest definitions) reloaded.");
+
+ /// dependent also from `gameobject` but this table not reloaded anyway
+ sLog.outString( "Re-Loading GameObjects for quests..." );
+ objmgr.LoadGameObjectForQuests();
+ SendGlobalGMSysMessage("Data GameObjects for quests reloaded.");
return true;
}
@@ -788,6 +823,15 @@ bool ChatHandler::HandleReloadLootTemplatesItemCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadLootTemplatesMillingCommand(const char*)
+{
+ sLog.outString( "Re-Loading Loot Tables... (`milling_loot_template`)" );
+ LoadLootTemplates_Milling();
+ LootTemplates_Milling.CheckLootRefs();
+ SendGlobalSysMessage("DB table `milling_loot_template` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadLootTemplatesPickpocketingCommand(const char*)
{
sLog.outString( "Re-Loading Loot Tables... (`pickpocketing_loot_template`)" );
@@ -832,6 +876,15 @@ bool ChatHandler::HandleReloadLootTemplatesSkinningCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadLootTemplatesSpellCommand(const char*)
+{
+ sLog.outString( "Re-Loading Loot Tables... (`spell_loot_template`)" );
+ LoadLootTemplates_Spell();
+ LootTemplates_Spell.CheckLootRefs();
+ SendGlobalSysMessage("DB table `spell_loot_template` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadTrinityStringCommand(const char*)
{
sLog.outString( "Re-Loading trinity_string Table!" );
@@ -872,6 +925,22 @@ bool ChatHandler::HandleReloadNpcVendorCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadPointsOfInterestCommand(const char*)
+{
+ sLog.outString( "Re-Loading `points_of_interest` Table!" );
+ objmgr.LoadPointsOfInterest();
+ SendGlobalSysMessage("DB table `points_of_interest` reloaded.");
+ return true;
+}
+
+bool ChatHandler::HandleReloadSpellClickSpellsCommand(const char*)
+{
+ sLog.outString( "Re-Loading `npc_spellclick_spells` Table!" );
+ objmgr.LoadNPCSpellClickSpells();
+ SendGlobalSysMessage("DB table `npc_spellclick_spells` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadReservedNameCommand(const char*)
{
sLog.outString( "Loading ReservedNames... (`reserved_name`)" );
@@ -912,6 +981,14 @@ bool ChatHandler::HandleReloadSpellAffectCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadSpellAreaCommand(const char*)
+{
+ sLog.outString( "Re-Loading SpellArea Data..." );
+ spellmgr.LoadSpellAreas();
+ SendGlobalSysMessage("DB table `spell_area` (spell dependences from area/quest/auras state) reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadSpellRequiredCommand(const char*)
{
sLog.outString( "Re-Loading Spell Required Data... " );
@@ -952,6 +1029,14 @@ bool ChatHandler::HandleReloadSpellProcEventCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadSpellBonusesCommand(const char*)
+{
+ sLog.outString( "Re-Loading Spell Bonus Data..." );
+ spellmgr.LoadSpellBonusess();
+ SendGlobalSysMessage("DB table `spell_bonus_data` (spell damage/healing coefficients) reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadSpellScriptTargetCommand(const char*)
{
sLog.outString( "Re-Loading SpellsScriptTarget..." );
@@ -1060,6 +1145,31 @@ bool ChatHandler::HandleReloadWpScriptsCommand(const char* arg)
return true;
}
+bool ChatHandler::HandleReloadEventAITextsCommand(const char* arg)
+{
+
+ sLog.outString( "Re-Loading Texts from `creature_ai_texts`...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Texts();
+ SendGlobalSysMessage("DB table `creature_ai_texts` reloaded.");
+ return true;
+}
+
+bool ChatHandler::HandleReloadEventAISummonsCommand(const char* arg)
+{
+ sLog.outString( "Re-Loading Summons from `creature_ai_summons`...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Summons();
+ SendGlobalSysMessage("DB table `creature_ai_summons` reloaded.");
+ return true;
+}
+
+bool ChatHandler::HandleReloadEventAIScriptsCommand(const char* arg)
+{
+ sLog.outString( "Re-Loading Scripts from `creature_ai_scripts`...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Scripts();
+ SendGlobalSysMessage("DB table `creature_ai_scripts` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadQuestEndScriptsCommand(const char* arg)
{
if(sWorld.IsScriptScheduled())
@@ -1120,7 +1230,7 @@ bool ChatHandler::HandleReloadSpellScriptsCommand(const char* arg)
return true;
}
-bool ChatHandler::HandleReloadDbScriptStringCommand(const char* arg)
+bool ChatHandler::HandleReloadDbScriptStringCommand(const char* /*arg*/)
{
sLog.outString( "Re-Loading Script strings from `db_script_string`...");
objmgr.LoadDbScriptStrings();
@@ -1161,6 +1271,14 @@ bool ChatHandler::HandleReloadSpellDisabledCommand(const char* /*arg*/)
return true;
}
+bool ChatHandler::HandleReloadLocalesAchievementRewardCommand(const char*)
+{
+ sLog.outString( "Re-Loading Locales Achievement Reward Data..." );
+ achievementmgr.LoadRewardLocales();
+ SendGlobalSysMessage("DB table `locales_achievement_reward` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadLocalesCreatureCommand(const char* /*arg*/)
{
sLog.outString( "Re-Loading Locales Creature ...");
@@ -1201,6 +1319,14 @@ bool ChatHandler::HandleReloadLocalesPageTextCommand(const char* /*arg*/)
return true;
}
+bool ChatHandler::HandleReloadLocalesPointsOfInterestCommand(const char* /*arg*/)
+{
+ sLog.outString( "Re-Loading Locales Points Of Interest ... ");
+ objmgr.LoadPointOfInterestLocales();
+ SendGlobalSysMessage("DB table `locales_points_of_interest` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadLocalesQuestCommand(const char* /*arg*/)
{
sLog.outString( "Re-Loading Locales Quest ... ");
@@ -1281,7 +1407,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args)
// Check for account
targetAccountName = arg1;
- if(!AccountMgr::normilizeString(targetAccountName))
+ if(!AccountMgr::normalizeString(targetAccountName))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,targetAccountName.c_str());
SetSentErrorMessage(true);
@@ -1332,7 +1458,7 @@ bool ChatHandler::HandleAccountSetPasswordCommand(const char* args)
return false;
std::string account_name = szAccount;
- if(!AccountMgr::normilizeString(account_name))
+ if(!AccountMgr::normalizeString(account_name))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
SetSentErrorMessage(true);
@@ -1347,19 +1473,10 @@ bool ChatHandler::HandleAccountSetPasswordCommand(const char* args)
return false;
}
- uint32 targetSecurity = accmgr.GetSecurity(targetAccountId);
-
- /// m_session==NULL only for console
- uint32 plSecurity = m_session ? m_session->GetSecurity() : SEC_CONSOLE;
-
/// can set password only for target with less security
/// This is also reject self apply in fact
- if (targetSecurity >= plSecurity)
- {
- SendSysMessage (LANG_YOURS_SECURITY_IS_LOW);
- SetSentErrorMessage (true);
+ if(HasLowerSecurityAccount (NULL,targetAccountId,true))
return false;
- }
if (strcmp(szPassword1,szPassword2))
{
@@ -1392,21 +1509,6 @@ bool ChatHandler::HandleAccountSetPasswordCommand(const char* args)
return true;
}
-bool ChatHandler::HandleAllowMovementCommand(const char* /*args*/)
-{
- if(sWorld.getAllowMovement())
- {
- sWorld.SetAllowMovement(false);
- SendSysMessage(LANG_CREATURE_MOVE_DISABLED);
- }
- else
- {
- sWorld.SetAllowMovement(true);
- SendSysMessage(LANG_CREATURE_MOVE_ENABLED);
- }
- return true;
-}
-
bool ChatHandler::HandleMaxSkillCommand(const char* /*args*/)
{
Player* SelectedPlayer = getSelectedPlayer();
@@ -1437,7 +1539,6 @@ bool ChatHandler::HandleSetSkillCommand(const char* args)
char *max_p = strtok (NULL, " ");
int32 skill = atoi(skill_p);
-
if (skill <= 0)
{
PSendSysMessage(LANG_INVALID_SKILL_ID, skill);
@@ -1463,9 +1564,11 @@ bool ChatHandler::HandleSetSkillCommand(const char* args)
return false;
}
+ std::string tNameLink = GetNameLink(target);
+
if(!target->GetSkillValue(skill))
{
- PSendSysMessage(LANG_SET_SKILL_ERROR, target->GetName(), skill, sl->name[0]);
+ PSendSysMessage(LANG_SET_SKILL_ERROR, tNameLink.c_str(), skill, sl->name[0]);
SetSentErrorMessage(true);
return false;
}
@@ -1476,7 +1579,7 @@ bool ChatHandler::HandleSetSkillCommand(const char* args)
return false;
target->SetSkill(skill, level, max);
- PSendSysMessage(LANG_SET_SKILL, skill, sl->name[0], target->GetName(), level, max);
+ PSendSysMessage(LANG_SET_SKILL, skill, sl->name[0], tNameLink.c_str(), level, max);
return true;
}
@@ -1487,27 +1590,12 @@ bool ChatHandler::HandleUnLearnCommand(const char* args)
return false;
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r
- uint32 min_id = extractSpellIdFromLink((char*)args);
- if(!min_id)
+ uint32 spell_id = extractSpellIdFromLink((char*)args);
+ if(!spell_id)
return false;
- // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r
- char* tail = strtok(NULL,"");
-
- uint32 max_id = extractSpellIdFromLink(tail);
-
- if (!max_id)
- {
- // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r
- max_id = min_id+1;
- }
- else
- {
- if (max_id < min_id)
- std::swap(min_id,max_id);
-
- max_id=max_id+1;
- }
+ char const* allStr = strtok(NULL," ");
+ bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false;
Player* target = getSelectedPlayer();
if(!target)
@@ -1517,13 +1605,13 @@ bool ChatHandler::HandleUnLearnCommand(const char* args)
return false;
}
- for(uint32 spell=min_id;spell<max_id;spell++)
- {
- if (target->HasSpell(spell))
- target->removeSpell(spell);
- else
- SendSysMessage(LANG_FORGET_SPELL);
- }
+ if(allRanks)
+ spell_id = spellmgr.GetFirstSpellInChain (spell_id);
+
+ if (target->HasSpell(spell_id))
+ target->removeSpell(spell_id,false,!allRanks);
+ else
+ SendSysMessage(LANG_FORGET_SPELL);
return true;
}
@@ -1538,10 +1626,12 @@ bool ChatHandler::HandleCooldownCommand(const char* args)
return false;
}
+ std::string tNameLink = GetNameLink(target);
+
if (!*args)
{
target->RemoveAllSpellCooldown();
- PSendSysMessage(LANG_REMOVEALL_COOLDOWN, target->GetName());
+ PSendSysMessage(LANG_REMOVEALL_COOLDOWN, tNameLink.c_str());
}
else
{
@@ -1552,18 +1642,14 @@ bool ChatHandler::HandleCooldownCommand(const char* args)
if(!sSpellStore.LookupEntry(spell_id))
{
- PSendSysMessage(LANG_UNKNOWN_SPELL, target==m_session->GetPlayer() ? GetTrinityString(LANG_YOU) : target->GetName());
+ PSendSysMessage(LANG_UNKNOWN_SPELL, target==m_session->GetPlayer() ? GetMangosString(LANG_YOU) : tNameLink.c_str());
SetSentErrorMessage(true);
return false;
}
- WorldPacket data( SMSG_CLEAR_COOLDOWN, (4+8) );
- data << uint32(spell_id);
- data << uint64(target->GetGUID());
- target->GetSession()->SendPacket(&data);
- target->RemoveSpellCooldown(spell_id);
- PSendSysMessage(LANG_REMOVE_COOLDOWN, spell_id, target==m_session->GetPlayer() ? GetTrinityString(LANG_YOU) : target->GetName());
- }
+ target->RemoveSpellCooldown(spell_id,true);
+ PSendSysMessage(LANG_REMOVE_COOLDOWN, spell_id, target==m_session->GetPlayer() ? GetMangosString(LANG_YOU) : tNameLink.c_str());
+ }
return true;
}
@@ -2188,7 +2274,7 @@ bool ChatHandler::HandleLearnAllCommand(const char* /*args*/)
continue;
}
- m_session->GetPlayer()->learnSpell(spell);
+ m_session->GetPlayer()->learnSpell(spell,false);
}
SendSysMessage(LANG_COMMAND_LEARN_MANY_SPELLS);
@@ -2228,7 +2314,7 @@ bool ChatHandler::HandleLearnAllGMCommand(const char* /*args*/)
continue;
}
- m_session->GetPlayer()->learnSpell(spell);
+ m_session->GetPlayer()->learnSpell(spell,false);
}
SendSysMessage(LANG_LEARNING_GM_SKILLS);
@@ -2249,12 +2335,16 @@ bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/)
return true;
uint32 family = clsEntry->spellfamily;
- for (uint32 i = 0; i < sSpellStore.GetNumRows(); i++)
+ for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(i);
if(!spellInfo)
continue;
+ // skip server-side/triggered spells
+ if(spellInfo->spellLevel==0)
+ continue;
+
// skip wrong class/race skills
if(!m_session->GetPlayer()->IsSpellFitByClassAndRace(spellInfo->Id))
continue;
@@ -2263,8 +2353,6 @@ bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/)
if( spellInfo->SpellFamilyName != family)
continue;
- //TODO: skip triggered spells
-
// skip spells with first rank learned as talent (and all talents then also)
uint32 first_rank = spellmgr.GetFirstSpellInChain(spellInfo->Id);
if(GetTalentSpellCost(first_rank) > 0 )
@@ -2274,33 +2362,94 @@ bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/)
if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
continue;
- m_session->GetPlayer()->learnSpell(i);
+ m_session->GetPlayer()->learnSpell(i,false);
}
SendSysMessage(LANG_COMMAND_LEARN_CLASS_SPELLS);
return true;
}
-static void learnAllHighRanks(Player* player, uint32 spellid)
+bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/)
{
- SpellChainNode const* node;
- do
+ Player* player = m_session->GetPlayer();
+ uint32 classMask = player->getClassMask();
+
+ for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{
- node = spellmgr.GetSpellChainNode(spellid);
- player->learnSpell(spellid);
- if (!node)
- break;
- spellid=node->next;
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
+ if(!talentInfo)
+ continue;
+
+ TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
+ if(!talentTabInfo)
+ continue;
+
+ if( (classMask & talentTabInfo->ClassMask) == 0 )
+ continue;
+
+ // search highest talent rank
+ uint32 spellid = 0;
+
+ for(int rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
+ {
+ if(talentInfo->RankID[rank]!=0)
+ {
+ spellid = talentInfo->RankID[rank];
+ break;
+ }
+ }
+
+ if(!spellid) // ??? none spells in talent
+ continue;
+
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid);
+ if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
+ continue;
+
+ // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
+ player->learnSpellHighRank(spellid);
}
- while (node->next);
+
+ SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
+ return true;
}
-bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/)
+bool ChatHandler::HandleLearnAllMyPetTalentsCommand(const char* /*args*/)
{
Player* player = m_session->GetPlayer();
- uint32 classMask = player->getClassMask();
- for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++)
+ Pet* pet = player->GetPet();
+ if(!pet)
+ {
+ SendSysMessage(LANG_NO_PET_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ CreatureInfo const *ci = pet->GetCreatureInfo();
+ if(!ci)
+ {
+ SendSysMessage(LANG_WRONG_PET_TYPE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
+ if(!pet_family)
+ {
+ SendSysMessage(LANG_WRONG_PET_TYPE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(pet_family->petTalentType < 0) // not hunter pet
+ {
+ SendSysMessage(LANG_WRONG_PET_TYPE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{
TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
if(!talentInfo)
@@ -2310,13 +2459,14 @@ bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/)
if(!talentTabInfo)
continue;
- if( (classMask & talentTabInfo->ClassMask) == 0 )
+ // prevent learn talent for different family (cheating)
+ if(((1 << pet_family->petTalentType) & talentTabInfo->petTalentMask)==0)
continue;
// search highest talent rank
uint32 spellid = 0;
- int rank = 4;
- for(; rank >= 0; --rank)
+
+ for(int rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
{
if(talentInfo->RankID[rank]!=0)
{
@@ -2332,14 +2482,11 @@ bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/)
if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
continue;
- // learn highest rank of talent
- player->learnSpell(spellid);
-
- // and learn all non-talent spell ranks (recursive by tree)
- learnAllHighRanks(player,spellid);
+ // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
+ pet->learnSpellHighRank(spellid);
}
- SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
+ SendSysMessage(LANG_COMMAND_LEARN_PET_TALENTS);
return true;
}
@@ -2347,7 +2494,7 @@ bool ChatHandler::HandleLearnAllLangCommand(const char* /*args*/)
{
// skipping UNIVERSAL language (0)
for(int i = 1; i < LANGUAGES_COUNT; ++i)
- m_session->GetPlayer()->learnSpell(lang_description[i].spell_id);
+ m_session->GetPlayer()->learnSpell(lang_description[i].spell_id,false);
SendSysMessage(LANG_COMMAND_LEARN_ALL_LANG);
return true;
@@ -2355,35 +2502,14 @@ bool ChatHandler::HandleLearnAllLangCommand(const char* /*args*/)
bool ChatHandler::HandleLearnAllDefaultCommand(const char* args)
{
- char* pName = strtok((char*)args, "");
- Player *player = NULL;
- if (pName)
- {
- std::string name = pName;
-
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- player = objmgr.GetPlayer(name.c_str());
- }
- else
- player = getSelectedPlayer();
-
- if(!player)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
+ Player* target;
+ if(!extractPlayerTarget((char*)args,&target))
return false;
- }
- player->learnDefaultSpells();
- player->learnQuestRewardedSpells();
+ target->learnDefaultSpells();
+ target->learnQuestRewardedSpells();
- PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST,player->GetName());
+ PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST,GetNameLink(target).c_str());
return true;
}
@@ -2403,25 +2529,31 @@ bool ChatHandler::HandleLearnCommand(const char* args)
if(!spell || !sSpellStore.LookupEntry(spell))
return false;
- if (targetPlayer->HasSpell(spell))
+ char const* allStr = strtok(NULL," ");
+ bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false;
+
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
+ if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer()))
{
- if(targetPlayer == m_session->GetPlayer())
- SendSysMessage(LANG_YOU_KNOWN_SPELL);
- else
- PSendSysMessage(LANG_TARGET_KNOWN_SPELL,targetPlayer->GetName());
+ PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell);
SetSentErrorMessage(true);
return false;
}
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
- if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer()))
+ if (!allRanks && targetPlayer->HasSpell(spell))
{
- PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell);
+ if(targetPlayer == m_session->GetPlayer())
+ SendSysMessage(LANG_YOU_KNOWN_SPELL);
+ else
+ PSendSysMessage(LANG_TARGET_KNOWN_SPELL,GetNameLink(targetPlayer).c_str());
SetSentErrorMessage(true);
return false;
}
- targetPlayer->learnSpell(spell);
+ if(allRanks)
+ targetPlayer->learnSpellHighRank(spell);
+ else
+ targetPlayer->learnSpell(spell,false);
return true;
}
@@ -2435,7 +2567,7 @@ bool ChatHandler::HandleAddItemCommand(const char* args)
if(args[0]=='[') // [name] manual form
{
- char* citemName = citemName = strtok((char*)args, "]");
+ char* citemName = strtok((char*)args, "]");
if(citemName && citemName[0])
{
@@ -2491,7 +2623,7 @@ bool ChatHandler::HandleAddItemCommand(const char* args)
if (count < 0)
{
plTarget->DestroyItemCount(itemId, -count, true, false);
- PSendSysMessage(LANG_REMOVEITEM, itemId, -count, plTarget->GetName());
+ PSendSysMessage(LANG_REMOVEITEM, itemId, -count, GetNameLink(plTarget).c_str());
return true;
}
@@ -2901,48 +3033,7 @@ bool ChatHandler::HandleListObjectCommand(const char* args)
return true;
}
-bool ChatHandler::HandleNearObjectCommand(const char* args)
-{
- float distance = (!*args) ? 10 : atol(args);
- uint32 count = 0;
-
- Player* pl = m_session->GetPlayer();
- QueryResult *result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, "
- "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ "
- "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' ORDER BY order_",
- pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),
- pl->GetMapId(),pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),distance*distance);
-
- if (result)
- {
- do
- {
- Field *fields = result->Fetch();
- uint32 guid = fields[0].GetUInt32();
- uint32 entry = fields[1].GetUInt32();
- float x = fields[2].GetFloat();
- float y = fields[3].GetFloat();
- float z = fields[4].GetFloat();
- int mapid = fields[5].GetUInt16();
-
- GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(entry);
-
- if(!gInfo)
- continue;
-
- PSendSysMessage(LANG_GO_LIST_CHAT, guid, guid, gInfo->name, x, y, z, mapid);
-
- ++count;
- } while (result->NextRow());
-
- delete result;
- }
-
- PSendSysMessage(LANG_COMMAND_NEAROBJMESSAGE,distance,count);
- return true;
-}
-
-bool ChatHandler::HandleObjectStateCommand(const char* args)
+bool ChatHandler::HandleGameObjectStateCommand(const char* args)
{
// number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r
char* cId = extractKeyFromLink((char*)args, "Hgameobject");
@@ -2965,17 +3056,40 @@ bool ChatHandler::HandleObjectStateCommand(const char* args)
return false;
}
+ char* ctype = strtok(NULL, " ");
+ if(!ctype)
+ return false;
+
+ int32 type = atoi(ctype);
+ if(type < 0)
+ {
+ if(type == -1)
+ gobj->SendObjectDeSpawnAnim(gobj->GetGUID());
+ else if(type == -2)
+ {
+ WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
+ data << gobj->GetGUID();
+ gobj->SendMessageToSet(&data,true);
+ }
+ return true;
+ }
+
char* cstate = strtok(NULL, " ");
if(!cstate)
return false;
int32 state = atoi(cstate);
- if(state < 0)
- gobj->SendObjectDeSpawnAnim(gobj->GetGUID());
- else
- gobj->SetGoState(state);
- return true;
+ if(type < 4)
+ gobj->SetByteValue(GAMEOBJECT_BYTES_1, type, state);
+ else if(type == 4)
+ {
+ WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4);
+ data << gobj->GetGUID();
+ data << (uint32)(state);
+ gobj->SendMessageToSet(&data, true);
+ }
+ PSendSysMessage("Set gobject type %d state %d", type, state);
return true;
}
@@ -3079,7 +3193,7 @@ bool ChatHandler::HandleLookupItemCommand(const char* args)
if(!pProto)
continue;
- int loc_idx = m_session ? m_session->GetSessionDbLocaleIndex() : objmgr.GetDBCLocaleIndex();
+ int loc_idx = GetSessionDbLocaleIndex();
if ( loc_idx >= 0 )
{
ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId);
@@ -3144,7 +3258,7 @@ bool ChatHandler::HandleLookupItemSetCommand(const char* args)
ItemSetEntry const *set = sItemSetStore.LookupEntry(id);
if(set)
{
- int loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale();
+ int loc = GetSessionDbcLocale();
std::string name = set->name[loc];
if(name.empty())
continue;
@@ -3154,7 +3268,7 @@ bool ChatHandler::HandleLookupItemSetCommand(const char* args)
loc = 0;
for(; loc < MAX_LOCALE; ++loc)
{
- if(m_session && loc==m_session->GetSessionDbcLocale())
+ if(loc==GetSessionDbcLocale())
continue;
name = set->name[loc];
@@ -3207,7 +3321,7 @@ bool ChatHandler::HandleLookupSkillCommand(const char* args)
SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(id);
if(skillInfo)
{
- int loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale();
+ int loc = GetSessionDbcLocale();
std::string name = skillInfo->name[loc];
if(name.empty())
continue;
@@ -3217,7 +3331,7 @@ bool ChatHandler::HandleLookupSkillCommand(const char* args)
loc = 0;
for(; loc < MAX_LOCALE; ++loc)
{
- if(m_session && loc==m_session->GetSessionDbcLocale())
+ if(loc==GetSessionDbcLocale())
continue;
name = skillInfo->name[loc];
@@ -3231,15 +3345,25 @@ bool ChatHandler::HandleLookupSkillCommand(const char* args)
if(loc < MAX_LOCALE)
{
+ char valStr[50] = "";
char const* knownStr = "";
if(target && target->HasSkill(id))
+ {
knownStr = GetTrinityString(LANG_KNOWN);
+ uint32 curValue = target->GetPureSkillValue(id);
+ uint32 maxValue = target->GetPureMaxSkillValue(id);
+ uint32 permValue = target->GetSkillPermBonusValue(id);
+ uint32 tempValue = target->GetSkillTempBonusValue(id);
+
+ char const* valFormat = GetTrinityString(LANG_SKILL_VALUES);
+ snprintf(valStr,50,valFormat,curValue,maxValue,permValue,tempValue);
+ }
// send skill in "id - [namedlink locale]" format
if (m_session)
- PSendSysMessage(LANG_SKILL_LIST_CHAT,id,id,name.c_str(),localeNames[loc],knownStr);
+ PSendSysMessage(LANG_SKILL_LIST_CHAT,id,id,name.c_str(),localeNames[loc],knownStr,valStr);
else
- PSendSysMessage(LANG_SKILL_LIST_CONSOLE,id,name.c_str(),localeNames[loc],knownStr);
+ PSendSysMessage(LANG_SKILL_LIST_CONSOLE,id,name.c_str(),localeNames[loc],knownStr,valStr);
++counter;
}
@@ -3275,7 +3399,7 @@ bool ChatHandler::HandleLookupSpellCommand(const char* args)
SpellEntry const *spellInfo = sSpellStore.LookupEntry(id);
if(spellInfo)
{
- int loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale();
+ int loc = GetSessionDbcLocale();
std::string name = spellInfo->SpellName[loc];
if(name.empty())
continue;
@@ -3285,7 +3409,7 @@ bool ChatHandler::HandleLookupSpellCommand(const char* args)
loc = 0;
for(; loc < MAX_LOCALE; ++loc)
{
- if(m_session && loc==m_session->GetSessionDbcLocale())
+ if(loc==GetSessionDbcLocale())
continue;
name = spellInfo->SpellName[loc];
@@ -3306,7 +3430,7 @@ bool ChatHandler::HandleLookupSpellCommand(const char* args)
bool talent = (talentCost > 0);
bool passive = IsPassiveSpell(id);
- bool active = target && (target->HasAura(id,0) || target->HasAura(id,1) || target->HasAura(id,2));
+ bool active = target && target->HasAura(id);
// unit32 used to prevent interpreting uint8 as char at output
// find rank of learned spell for learning spell, or talent rank
@@ -3374,7 +3498,7 @@ bool ChatHandler::HandleLookupQuestCommand(const char* args)
{
Quest * qinfo = iter->second;
- int loc_idx = m_session ? m_session->GetSessionDbLocaleIndex() : objmgr.GetDBCLocaleIndex();
+ int loc_idx = GetSessionDbLocaleIndex();
if ( loc_idx >= 0 )
{
QuestLocale const *il = objmgr.GetQuestLocale(qinfo->GetQuestId());
@@ -3474,7 +3598,7 @@ bool ChatHandler::HandleLookupCreatureCommand(const char* args)
if(!cInfo)
continue;
- int loc_idx = m_session ? m_session->GetSessionDbLocaleIndex() : objmgr.GetDBCLocaleIndex();
+ int loc_idx = GetSessionDbLocaleIndex();
if (loc_idx >= 0)
{
CreatureLocale const *cl = objmgr.GetCreatureLocale (id);
@@ -3539,7 +3663,7 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args)
if(!gInfo)
continue;
- int loc_idx = m_session ? m_session->GetSessionDbLocaleIndex() : objmgr.GetDBCLocaleIndex();
+ int loc_idx = GetSessionDbLocaleIndex();
if ( loc_idx >= 0 )
{
GameObjectLocale const *gl = objmgr.GetGameObjectLocale(id);
@@ -3582,6 +3706,68 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args)
return true;
}
+bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args)
+{
+ if(!*args)
+ return false;
+
+ std::string namepart = args;
+ std::wstring wnamepart;
+
+ if(!Utf8toWStr(namepart,wnamepart))
+ return false;
+
+ // converting string that we try to find to lower case
+ wstrToLower( wnamepart );
+
+ uint32 counter = 0; // Counter for figure out that we found smth.
+
+ // Search in TaxiNodes.dbc
+ for (uint32 id = 0; id < sTaxiNodesStore.GetNumRows(); id++)
+ {
+ TaxiNodesEntry const *nodeEntry = sTaxiNodesStore.LookupEntry(id);
+ if(nodeEntry)
+ {
+ int loc = GetSessionDbcLocale();
+ std::string name = nodeEntry->name[loc];
+ if(name.empty())
+ continue;
+
+ if (!Utf8FitTo(name, wnamepart))
+ {
+ loc = 0;
+ for(; loc < MAX_LOCALE; ++loc)
+ {
+ if(loc==GetSessionDbcLocale())
+ continue;
+
+ name = nodeEntry->name[loc];
+ if(name.empty())
+ continue;
+
+ if (Utf8FitTo(name, wnamepart))
+ break;
+ }
+ }
+
+ if(loc < MAX_LOCALE)
+ {
+ // send taxinode in "id - [name] (Map:m X:x Y:y Z:z)" format
+ if (m_session)
+ PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CHAT, id, id, name.c_str(),localeNames[loc],
+ nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z);
+ else
+ PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CONSOLE, id, name.c_str(), localeNames[loc],
+ nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z);
+ ++counter;
+ }
+ }
+ }
+ if (counter == 0) // if counter == 0 then we found nth
+ SendSysMessage(LANG_COMMAND_NOSPELLFOUND);
+ return true;
+}
+
/** \brief GM command level 3 - Create a guild.
*
* This command allows a GM (level 3) to create a guild.
@@ -3592,41 +3778,26 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args)
*/
bool ChatHandler::HandleGuildCreateCommand(const char* args)
{
-
- if (!*args)
+ char* nameStr;
+ char* guildStr;
+ extractOptFirstArg((char*)args,&nameStr,&guildStr);
+ if(!guildStr)
return false;
- char *lname = strtok ((char*)args, " ");
- char *gname = strtok (NULL, "");
-
- if (!lname)
+ Player* target;
+ if(!extractPlayerTarget(nameStr,&target))
return false;
- if (!gname)
- {
- SendSysMessage (LANG_INSERT_GUILD_NAME);
- SetSentErrorMessage (true);
- return false;
- }
+ std::string guildname = guildStr;
- std::string guildname = gname;
-
- Player* player = ObjectAccessor::Instance ().FindPlayerByName (lname);
- if (!player)
- {
- SendSysMessage (LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage (true);
- return false;
- }
-
- if (player->GetGuildId())
+ if (target->GetGuildId())
{
SendSysMessage (LANG_PLAYER_IN_GUILD);
return true;
}
Guild *guild = new Guild;
- if (!guild->create (player->GetGUID (),guildname))
+ if (!guild->create (target,guildname))
{
delete guild;
SendSysMessage (LANG_GUILD_NOT_CREATED);
@@ -3640,38 +3811,23 @@ bool ChatHandler::HandleGuildCreateCommand(const char* args)
bool ChatHandler::HandleGuildInviteCommand(const char *args)
{
- if (!*args)
+ char* nameStr;
+ char* guildNameStr;
+ extractOptFirstArg((char*)args,&nameStr,&guildNameStr);
+ if(!guildNameStr)
return false;
- char* par1 = strtok ((char*)args, " ");
- char* par2 = strtok (NULL, "");
- if(!par1 || !par2)
+ uint64 target_guid;
+ if(!extractPlayerTarget(nameStr,NULL,&target_guid))
return false;
- std::string glName = par2;
+ std::string glName = guildNameStr;
Guild* targetGuild = objmgr.GetGuildByName (glName);
if (!targetGuild)
return false;
- std::string plName = par1;
- if (!normalizePlayerName (plName))
- {
- SendSysMessage (LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage (true);
- return false;
- }
-
- uint64 plGuid = 0;
- if (Player* targetPlayer = ObjectAccessor::Instance ().FindPlayerByName (plName.c_str ()))
- plGuid = targetPlayer->GetGUID ();
- else
- plGuid = objmgr.GetPlayerGUIDByName (plName.c_str ());
-
- if (!plGuid)
- false;
-
// player's guild membership checked in AddMember before add
- if (!targetGuild->AddMember (plGuid,targetGuild->GetLowestRank ()))
+ if (!targetGuild->AddMember (target_guid,targetGuild->GetLowestRank ()))
return false;
return true;
@@ -3679,89 +3835,50 @@ bool ChatHandler::HandleGuildInviteCommand(const char *args)
bool ChatHandler::HandleGuildUninviteCommand(const char *args)
{
- if (!*args)
+ Player* target;
+ uint64 target_guid;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid))
return false;
- char* par1 = strtok ((char*)args, " ");
- if(!par1)
- return false;
-
- std::string plName = par1;
- if (!normalizePlayerName (plName))
- {
- SendSysMessage (LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage (true);
- return false;
- }
-
- uint64 plGuid = 0;
- uint32 glId = 0;
- if (Player* targetPlayer = ObjectAccessor::Instance ().FindPlayerByName (plName.c_str ()))
- {
- plGuid = targetPlayer->GetGUID ();
- glId = targetPlayer->GetGuildId ();
- }
- else
- {
- plGuid = objmgr.GetPlayerGUIDByName (plName.c_str ());
- glId = Player::GetGuildIdFromDB (plGuid);
- }
-
- if (!plGuid || !glId)
+ uint32 glId = target ? target->GetGuildId () : Player::GetGuildIdFromDB (target_guid);
+ if (!glId)
return false;
Guild* targetGuild = objmgr.GetGuildById (glId);
if (!targetGuild)
return false;
- targetGuild->DelMember (plGuid);
-
+ targetGuild->DelMember (target_guid);
return true;
}
bool ChatHandler::HandleGuildRankCommand(const char *args)
{
- if (!*args)
+ char* nameStr;
+ char* rankStr;
+ extractOptFirstArg((char*)args,&nameStr,&rankStr);
+ if(!rankStr)
return false;
- char* par1 = strtok ((char*)args, " ");
- char* par2 = strtok (NULL, " ");
- if (!par1 || !par2)
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name))
return false;
- std::string plName = par1;
- if (!normalizePlayerName (plName))
- {
- SendSysMessage (LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage (true);
- return false;
- }
-
- uint64 plGuid = 0;
- uint32 glId = 0;
- if (Player* targetPlayer = ObjectAccessor::Instance ().FindPlayerByName (plName.c_str ()))
- {
- plGuid = targetPlayer->GetGUID ();
- glId = targetPlayer->GetGuildId ();
- }
- else
- {
- plGuid = objmgr.GetPlayerGUIDByName (plName.c_str ());
- glId = Player::GetGuildIdFromDB (plGuid);
- }
- if (!plGuid || !glId)
+ uint32 glId = target ? target->GetGuildId () : Player::GetGuildIdFromDB (target_guid);
+ if (!glId)
return false;
Guild* targetGuild = objmgr.GetGuildById (glId);
if (!targetGuild)
return false;
- uint32 newrank = uint32 (atoi (par2));
+ uint32 newrank = uint32 (atoi (rankStr));
if (newrank > targetGuild->GetLowestRank ())
return false;
- targetGuild->ChangeRank (plGuid,newrank);
-
+ targetGuild->ChangeRank (target_guid,newrank);
return true;
}
@@ -3785,90 +3902,37 @@ bool ChatHandler::HandleGuildDeleteCommand(const char* args)
return true;
}
-bool ChatHandler::HandleGetDistanceCommand(const char* /*args*/)
-{
- Unit* pUnit = getSelectedUnit();
-
- if(!pUnit)
- {
- SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(pUnit),m_session->GetPlayer()->GetDistance2d(pUnit));
-
- return true;
-}
-
-// FIX-ME!!!
-
-bool ChatHandler::HandleAddWeaponCommand(const char* /*args*/)
+bool ChatHandler::HandleGetDistanceCommand(const char* args)
{
- /*if (!*args)
- return false;
-
- uint64 guid = m_session->GetPlayer()->GetSelection();
- if (guid == 0)
- {
- SendSysMessage(LANG_NO_SELECTION);
- return true;
- }
-
- Creature *pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
+ WorldObject* obj = NULL;
- if(!pCreature)
+ if (*args)
{
- SendSysMessage(LANG_SELECT_CREATURE);
- return true;
- }
-
- char* pSlotID = strtok((char*)args, " ");
- if (!pSlotID)
- return false;
+ uint64 guid = extractGuidFromLink((char*)args);
+ if(guid)
+ obj = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*m_session->GetPlayer(),guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
- char* pItemID = strtok(NULL, " ");
- if (!pItemID)
- return false;
-
- uint32 ItemID = atoi(pItemID);
- uint32 SlotID = atoi(pSlotID);
-
- ItemPrototype* tmpItem = objmgr.GetItemPrototype(ItemID);
-
- bool added = false;
- if(tmpItem)
- {
- switch(SlotID)
+ if(!obj)
{
- case 1:
- pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID);
- added = true;
- break;
- case 2:
- pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID);
- added = true;
- break;
- case 3:
- pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID);
- added = true;
- break;
- default:
- PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID);
- added = false;
- break;
- }
- if(added)
- {
- PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID);
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
}
}
else
{
- PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID);
- return true;
+ obj = getSelectedUnit();
+
+ if(!obj)
+ {
+ SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
}
- */
+
+ PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(obj),m_session->GetPlayer()->GetDistance2d(obj));
+
return true;
}
@@ -3883,6 +3947,12 @@ bool ChatHandler::HandleDieCommand(const char* /*args*/)
return false;
}
+ if(target->GetTypeId()==TYPEID_PLAYER)
+ {
+ if(HasLowerSecurity((Player*)target,0,false))
+ return false;
+ }
+
if( target->isAlive() )
{
//m_session->GetPlayer()->DealDamage(target, target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
@@ -3899,31 +3969,34 @@ bool ChatHandler::HandleDamageCommand(const char * args)
Unit* target = getSelectedUnit();
- if(!target || !m_session->GetPlayer()->GetSelection())
+ if (!target || !m_session->GetPlayer()->GetSelection())
{
SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
SetSentErrorMessage(true);
return false;
}
- if( !target->isAlive() )
+ if (!target->isAlive())
return true;
char* damageStr = strtok((char*)args, " ");
- if(!damageStr)
+ if (!damageStr)
return false;
- int32 damage = atoi((char*)damageStr);
- if(damage <=0)
+ int32 damage_int = atoi((char*)damageStr);
+ if(damage_int <=0)
return true;
+ uint32 damage = damage_int;
+
char* schoolStr = strtok((char*)NULL, " ");
// flat melee damage without resistence/etc reduction
- if(!schoolStr)
+ if (!schoolStr)
{
m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0);
+ if (target != m_session->GetPlayer())
+ m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0);
return true;
}
@@ -3934,12 +4007,12 @@ bool ChatHandler::HandleDamageCommand(const char * args)
SpellSchoolMask schoolmask = SpellSchoolMask(1 << school);
if ( schoolmask & SPELL_SCHOOL_MASK_NORMAL )
- damage = m_session->GetPlayer()->CalcArmorReducedDamage(target, damage);
+ damage = m_session->GetPlayer()->CalcArmorReducedDamage(target, damage, NULL, BASE_ATTACK);
char* spellStr = strtok((char*)NULL, " ");
// melee damage by specific school
- if(!spellStr)
+ if (!spellStr)
{
uint32 absorb = 0;
uint32 resist = 0;
@@ -3951,6 +4024,7 @@ bool ChatHandler::HandleDamageCommand(const char * args)
damage -= absorb + resist;
+ m_session->GetPlayer()->DealDamageMods(target,damage,&absorb);
m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false);
m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_NORMAL, 0);
return true;
@@ -3960,10 +4034,10 @@ bool ChatHandler::HandleDamageCommand(const char * args)
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
uint32 spellid = extractSpellIdFromLink((char*)args);
- if(!spellid || !sSpellStore.LookupEntry(spellid))
+ if (!spellid || !sSpellStore.LookupEntry(spellid))
return false;
- m_session->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage, false);
+ m_session->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage);
return true;
}
@@ -3984,49 +4058,33 @@ bool ChatHandler::HandleModifyArenaCommand(const char * args)
target->ModifyArenaPoints(amount);
- PSendSysMessage(LANG_COMMAND_MODIFY_ARENA, target->GetName(), target->GetArenaPoints());
+ PSendSysMessage(LANG_COMMAND_MODIFY_ARENA, GetNameLink(target).c_str(), target->GetArenaPoints());
return true;
}
bool ChatHandler::HandleReviveCommand(const char* args)
{
- Player* SelectedPlayer = NULL;
+ Player* target;
+ uint64 target_guid;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid))
+ return false;
- if (*args)
+ if (target)
{
- std::string name = args;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- SelectedPlayer = objmgr.GetPlayer(name.c_str());
+ target->ResurrectPlayer(0.5f);
+ target->SpawnCorpseBones();
+ target->SaveToDB();
}
else
- SelectedPlayer = getSelectedPlayer();
-
- if(!SelectedPlayer)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
- return false;
- }
+ // will resurrected at login without corpse
+ ObjectAccessor::Instance().ConvertCorpseForPlayer(target_guid);
- SelectedPlayer->ResurrectPlayer(0.5f);
- SelectedPlayer->SpawnCorpseBones();
- SelectedPlayer->SaveToDB();
return true;
}
bool ChatHandler::HandleAuraCommand(const char* args)
{
- char* px = strtok((char*)args, " ");
- if (!px)
- return false;
-
Unit *target = getSelectedUnit();
if(!target)
{
@@ -4035,11 +4093,14 @@ bool ChatHandler::HandleAuraCommand(const char* args)
return false;
}
- uint32 spellID = (uint32)atoi(px);
+ // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
+ uint32 spellID = extractSpellIdFromLink((char*)args);
+
SpellEntry const *spellInfo = sSpellStore.LookupEntry( spellID );
+ uint8 eff_mask=0;
if(spellInfo)
{
- for(uint32 i = 0;i<3;i++)
+ for(uint32 i = 0;i<3;++i)
{
uint8 eff = spellInfo->Effect[i];
if (eff>=TOTAL_SPELL_EFFECTS)
@@ -4048,10 +4109,11 @@ bool ChatHandler::HandleAuraCommand(const char* args)
eff == SPELL_EFFECT_APPLY_AURA ||
eff == SPELL_EFFECT_PERSISTENT_AREA_AURA )
{
- Aura *Aur = CreateAura(spellInfo, i, NULL, target);
- target->AddAura(Aur);
+ eff_mask|=1<<i;
}
}
+ Aura *Aur = new Aura(spellInfo, eff_mask, NULL, target);
+ target->AddAura(Aur);
}
return true;
@@ -4059,10 +4121,6 @@ bool ChatHandler::HandleAuraCommand(const char* args)
bool ChatHandler::HandleUnAuraCommand(const char* args)
{
- char* px = strtok((char*)args, " ");
- if (!px)
- return false;
-
Unit *target = getSelectedUnit();
if(!target)
{
@@ -4078,7 +4136,11 @@ bool ChatHandler::HandleUnAuraCommand(const char* args)
return true;
}
- uint32 spellID = (uint32)atoi(px);
+ // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
+ uint32 spellID = extractSpellIdFromLink((char*)args);
+ if(!spellID)
+ return false;
+
target->RemoveAurasDueToSpell(spellID);
return true;
@@ -4129,7 +4191,7 @@ bool ChatHandler::HandleLinkGraveCommand(const char* args)
return false;
}
- if(objmgr.AddGraveYardLink(g_id,player->GetZoneId(),g_team))
+ if(objmgr.AddGraveYardLink(g_id,zoneId,g_team))
PSendSysMessage(LANG_COMMAND_GRAVEYARDLINKED, g_id,zoneId);
else
PSendSysMessage(LANG_COMMAND_GRAVEYARDALRLINKED, g_id,zoneId);
@@ -4153,6 +4215,7 @@ bool ChatHandler::HandleNearGraveCommand(const char* args)
return false;
Player* player = m_session->GetPlayer();
+ uint32 zone_id = player->GetZoneId();
WorldSafeLocsEntry const* graveyard = objmgr.GetClosestGraveYard(
player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(),player->GetMapId(),g_team);
@@ -4161,7 +4224,7 @@ bool ChatHandler::HandleNearGraveCommand(const char* args)
{
uint32 g_id = graveyard->ID;
- GraveYardData const* data = objmgr.FindGraveYardData(g_id,player->GetZoneId());
+ GraveYardData const* data = objmgr.FindGraveYardData(g_id,zone_id);
if (!data)
{
PSendSysMessage(LANG_COMMAND_GRAVEYARDERROR,g_id);
@@ -4180,7 +4243,7 @@ bool ChatHandler::HandleNearGraveCommand(const char* args)
else if(g_team == ALLIANCE)
team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE);
- PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, g_id,team_name.c_str(),player->GetZoneId());
+ PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, g_id,team_name.c_str(),zone_id);
}
else
{
@@ -4194,29 +4257,51 @@ bool ChatHandler::HandleNearGraveCommand(const char* args)
team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE);
if(g_team == ~uint32(0))
- PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, player->GetZoneId());
+ PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, zone_id);
else
- PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, player->GetZoneId(),team_name.c_str());
+ PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, zone_id,team_name.c_str());
}
return true;
}
-//play npc emote
-bool ChatHandler::HandleNpcPlayEmoteCommand(const char* args)
+//-----------------------Npc Commands-----------------------
+bool ChatHandler::HandleNpcAllowMovementCommand(const char* /*args*/)
{
- uint32 emote = atoi((char*)args);
+ if(sWorld.getAllowMovement())
+ {
+ sWorld.SetAllowMovement(false);
+ SendSysMessage(LANG_CREATURE_MOVE_DISABLED);
+ }
+ else
+ {
+ sWorld.SetAllowMovement(true);
+ SendSysMessage(LANG_CREATURE_MOVE_ENABLED);
+ }
+ return true;
+}
- Creature* target = getSelectedCreature();
- if(!target)
+bool ChatHandler::HandleNpcChangeEntryCommand(const char *args)
+{
+ if (!*args)
+ return false;
+
+ uint32 newEntryNum = atoi(args);
+ if(!newEntryNum)
+ return false;
+
+ Unit* unit = getSelectedUnit();
+ if(!unit || unit->GetTypeId() != TYPEID_UNIT)
{
SendSysMessage(LANG_SELECT_CREATURE);
SetSentErrorMessage(true);
return false;
}
-
- target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote);
-
+ Creature* creature = (Creature*)unit;
+ if(creature->UpdateEntry(newEntryNum))
+ SendSysMessage(LANG_DONE);
+ else
+ SendSysMessage(LANG_ERROR);
return true;
}
@@ -4268,6 +4353,95 @@ bool ChatHandler::HandleNpcInfoCommand(const char* /*args*/)
return true;
}
+//play npc emote
+bool ChatHandler::HandleNpcPlayEmoteCommand(const char* args)
+{
+ uint32 emote = atoi((char*)args);
+
+ Creature* target = getSelectedCreature();
+ if(!target)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote);
+
+ return true;
+}
+
+//TODO: NpcCommands that needs to be fixed :
+
+bool ChatHandler::HandleNpcAddWeaponCommand(const char* /*args*/)
+{
+ /*if (!*args)
+ return false;
+
+ uint64 guid = m_session->GetPlayer()->GetSelection();
+ if (guid == 0)
+ {
+ SendSysMessage(LANG_NO_SELECTION);
+ return true;
+ }
+
+ Creature *pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
+
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ return true;
+ }
+
+ char* pSlotID = strtok((char*)args, " ");
+ if (!pSlotID)
+ return false;
+
+ char* pItemID = strtok(NULL, " ");
+ if (!pItemID)
+ return false;
+
+ uint32 ItemID = atoi(pItemID);
+ uint32 SlotID = atoi(pSlotID);
+
+ ItemPrototype* tmpItem = objmgr.GetItemPrototype(ItemID);
+
+ bool added = false;
+ if(tmpItem)
+ {
+ switch(SlotID)
+ {
+ case 1:
+ pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID);
+ added = true;
+ break;
+ case 2:
+ pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID);
+ added = true;
+ break;
+ case 3:
+ pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID);
+ added = true;
+ break;
+ default:
+ PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID);
+ added = false;
+ break;
+ }
+
+ if(added)
+ PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID);
+ }
+ else
+ {
+ PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID);
+ return true;
+ }
+ */
+ return true;
+}
+//----------------------------------------------------------
+
bool ChatHandler::HandleExploreCheatCommand(const char* args)
{
if (!*args)
@@ -4285,18 +4459,18 @@ bool ChatHandler::HandleExploreCheatCommand(const char* args)
if (flag != 0)
{
- PSendSysMessage(LANG_YOU_SET_EXPLORE_ALL, chr->GetName());
+ PSendSysMessage(LANG_YOU_SET_EXPLORE_ALL, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_ALL,GetName());
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_ALL,GetNameLink().c_str());
}
else
{
- PSendSysMessage(LANG_YOU_SET_EXPLORE_NOTHING, chr->GetName());
+ PSendSysMessage(LANG_YOU_SET_EXPLORE_NOTHING, GetNameLink(chr).c_str());
if (needReportToTarget(chr))
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_NOTHING,GetName());
+ ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_NOTHING,GetNameLink().c_str());
}
- for (uint8 i=0; i<128; i++)
+ for (uint8 i=0; i<128; ++i)
{
if (flag != 0)
{
@@ -4330,137 +4504,113 @@ bool ChatHandler::HandleHoverCommand(const char* args)
return true;
}
-bool ChatHandler::HandleWaterwalkCommand(const char* args)
+void ChatHandler::HandleCharacterLevel(Player* player, uint64 player_guid, uint32 oldlevel, uint32 newlevel)
{
- if(!args)
- return false;
-
- Player *player = getSelectedPlayer();
- if(!player)
+ if(player)
{
- PSendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
- return false;
- }
+ player->GiveLevel(newlevel);
+ player->InitTalentForLevel();
+ player->SetUInt32Value(PLAYER_XP,0);
- if (strncmp(args, "on", 3) == 0)
- player->SetMovement(MOVE_WATER_WALK); // ON
- else if (strncmp(args, "off", 4) == 0)
- player->SetMovement(MOVE_LAND_WALK); // OFF
+ if(needReportToTarget(player))
+ {
+ 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_DOWN,GetNameLink().c_str(),newlevel);
+ }
+ }
else
{
- SendSysMessage(LANG_USE_BOL);
- return false;
+ // update level and XP at level, all other will be updated at loading
+ Tokens values;
+ Player::LoadValuesArrayFromDB(values,player_guid);
+ Player::SetUInt32ValueInArray(values,UNIT_FIELD_LEVEL,newlevel);
+ Player::SetUInt32ValueInArray(values,PLAYER_XP,0);
+ Player::SaveValuesArrayInDB(values,player_guid);
}
-
- PSendSysMessage(LANG_YOU_SET_WATERWALK, args, player->GetName());
- if(needReportToTarget(player))
- ChatHandler(player).PSendSysMessage(LANG_YOUR_WATERWALK_SET, args, GetName());
- return true;
-
}
-bool ChatHandler::HandleLevelUpCommand(const char* args)
+bool ChatHandler::HandleCharacterLevelCommand(const char* args)
{
- char* px = strtok((char*)args, " ");
- char* py = strtok((char*)NULL, " ");
-
- // command format parsing
- char* pname = (char*)NULL;
- int addlevel = 1;
+ char* nameStr;
+ char* levelStr;
+ extractOptFirstArg((char*)args,&nameStr,&levelStr);
+ if(!levelStr)
+ return false;
- if(px && py) // .levelup name level
+ // exception opt second arg: .character level $name
+ if(isalpha(levelStr[0]))
{
- addlevel = atoi(py);
- pname = px;
+ nameStr = levelStr;
+ levelStr = NULL; // current level will used
}
- else if(px && !py) // .levelup name OR .levelup level
- {
- if(isalpha(px[0])) // .levelup name
- pname = px;
- else // .levelup level
- addlevel = atoi(px);
- }
- // else .levelup - nothing do for preparing
- // player
- Player *chr = NULL;
- uint64 chr_guid = 0;
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name))
+ return false;
- std::string name;
+ int32 oldlevel = target ? target->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,target_guid);
+ int32 newlevel = levelStr ? atoi(levelStr) : oldlevel;
- if(pname) // player by name
- {
- name = pname;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
+ if(newlevel < 1)
+ return false; // invalid level
- chr = objmgr.GetPlayer(name.c_str());
- if(!chr) // not in game
- {
- chr_guid = objmgr.GetPlayerGUIDByName(name);
- if (chr_guid == 0)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
- }
- }
- else // player by selection
+ if(newlevel > STRONG_MAX_LEVEL) // hardcoded maximum level
+ newlevel = STRONG_MAX_LEVEL;
+
+ HandleCharacterLevel(target,target_guid,oldlevel,newlevel);
+
+ if(!m_session || m_session->GetPlayer() != target) // including player==NULL
{
- chr = getSelectedPlayer();
+ std::string nameLink = playerLink(target_name);
+ PSendSysMessage(LANG_YOU_CHANGE_LVL,nameLink.c_str(),newlevel);
+ }
- if (chr == NULL)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
- return false;
- }
+ return true;
+}
- name = chr->GetName();
+bool ChatHandler::HandleLevelUpCommand(const char* args)
+{
+ char* nameStr;
+ char* levelStr;
+ extractOptFirstArg((char*)args,&nameStr,&levelStr);
+
+ // exception opt second arg: .character level $name
+ if(levelStr && isalpha(levelStr[0]))
+ {
+ nameStr = levelStr;
+ levelStr = NULL; // current level will used
}
- assert(chr || chr_guid);
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name))
+ return false;
- int32 oldlevel = chr ? chr->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,chr_guid);
+ int32 oldlevel = target ? target->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,target_guid);
+ int32 addlevel = levelStr ? atoi(levelStr) : 1;
int32 newlevel = oldlevel + addlevel;
+
if(newlevel < 1)
newlevel = 1;
+
if(newlevel > STRONG_MAX_LEVEL) // hardcoded maximum level
newlevel = STRONG_MAX_LEVEL;
- if(chr)
- {
- chr->GiveLevel(newlevel);
- chr->InitTalentForLevel();
- chr->SetUInt32Value(PLAYER_XP,0);
+ HandleCharacterLevel(target,target_guid,oldlevel,newlevel);
- if(oldlevel == newlevel)
- ChatHandler(chr).SendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET);
- else
- if(oldlevel < newlevel)
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_LEVEL_UP,newlevel-oldlevel);
- else
- if(oldlevel > newlevel)
- ChatHandler(chr).PSendSysMessage(LANG_YOURS_LEVEL_DOWN,newlevel-oldlevel);
- }
- else
+ if(!m_session || m_session->GetPlayer() != target) // including chr==NULL
{
- // update level and XP at level, all other will be updated at loading
- Tokens values;
- Player::LoadValuesArrayFromDB(values,chr_guid);
- Player::SetUInt32ValueInArray(values,UNIT_FIELD_LEVEL,newlevel);
- Player::SetUInt32ValueInArray(values,PLAYER_XP,0);
- Player::SaveValuesArrayInDB(values,chr_guid);
+ std::string nameLink = playerLink(target_name);
+ PSendSysMessage(LANG_YOU_CHANGE_LVL,nameLink.c_str(),newlevel);
}
- if(m_session->GetPlayer() != chr) // including chr==NULL
- PSendSysMessage(LANG_YOU_CHANGE_LVL,name.c_str(),newlevel);
return true;
}
@@ -4469,8 +4619,6 @@ bool ChatHandler::HandleShowAreaCommand(const char* args)
if (!*args)
return false;
- int area = atoi((char*)args);
-
Player *chr = getSelectedPlayer();
if (chr == NULL)
{
@@ -4479,10 +4627,11 @@ bool ChatHandler::HandleShowAreaCommand(const char* args)
return false;
}
+ int area = GetAreaFlagByAreaID(atoi((char*)args));
int offset = area / 32;
uint32 val = (uint32)(1 << (area % 32));
- if(offset >= 128)
+ if(area<0 || offset >= 128)
{
SendSysMessage(LANG_BAD_VALUE);
SetSentErrorMessage(true);
@@ -4501,8 +4650,6 @@ bool ChatHandler::HandleHideAreaCommand(const char* args)
if (!*args)
return false;
- int area = atoi((char*)args);
-
Player *chr = getSelectedPlayer();
if (chr == NULL)
{
@@ -4511,10 +4658,11 @@ bool ChatHandler::HandleHideAreaCommand(const char* args)
return false;
}
+ int area = GetAreaFlagByAreaID(atoi((char*)args));
int offset = area / 32;
uint32 val = (uint32)(1 << (area % 32));
- if(offset >= 128)
+ if(area<0 || offset >= 128)
{
SendSysMessage(LANG_BAD_VALUE);
SetSentErrorMessage(true);
@@ -4528,7 +4676,7 @@ bool ChatHandler::HandleHideAreaCommand(const char* args)
return true;
}
-bool ChatHandler::HandleUpdate(const char* args)
+bool ChatHandler::HandleDebugUpdate(const char* args)
{
if(!*args)
return false;
@@ -4628,7 +4776,7 @@ bool ChatHandler::HandleChangeWeather(const char* args)
return true;
}
-bool ChatHandler::HandleSetValue(const char* args)
+bool ChatHandler::HandleDebugSetValue(const char* args)
{
if(!*args)
return false;
@@ -4640,7 +4788,7 @@ bool ChatHandler::HandleSetValue(const char* args)
if (!px || !py)
return false;
- Unit* target = getSelectedUnit();
+ WorldObject* target = getSelectedObject();
if(!target)
{
SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
@@ -4679,7 +4827,7 @@ bool ChatHandler::HandleSetValue(const char* args)
return true;
}
-bool ChatHandler::HandleGetValue(const char* args)
+bool ChatHandler::HandleDebugGetValue(const char* args)
{
if(!*args)
return false;
@@ -4728,11 +4876,19 @@ bool ChatHandler::HandleGetValue(const char* args)
return true;
}
-bool ChatHandler::HandleSet32Bit(const char* args)
+bool ChatHandler::HandleDebugSet32Bit(const char* args)
{
if(!*args)
return false;
+ WorldObject* target = getSelectedObject();
+ if(!target)
+ {
+ SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
char* px = strtok((char*)args, " ");
char* py = strtok(NULL, " ");
@@ -4746,13 +4902,14 @@ bool ChatHandler::HandleSet32Bit(const char* args)
sLog.outDebug(GetTrinityString(LANG_SET_32BIT), Opcode, Value);
- m_session->GetPlayer( )->SetUInt32Value( Opcode , 2^Value );
+ uint32 iValue = Value ? 1 << (Value - 1) : 0;
+ target->SetUInt32Value( Opcode , iValue);
- PSendSysMessage(LANG_SET_32BIT_FIELD, Opcode,1);
+ PSendSysMessage(LANG_SET_32BIT_FIELD, Opcode, iValue);
return true;
}
-bool ChatHandler::HandleMod32Value(const char* args)
+bool ChatHandler::HandleDebugMod32Value(const char* args)
{
if(!*args)
return false;
@@ -4784,7 +4941,7 @@ bool ChatHandler::HandleMod32Value(const char* args)
return true;
}
-bool ChatHandler::HandleAddTeleCommand(const char * args)
+bool ChatHandler::HandleTeleAddCommand(const char * args)
{
if(!*args)
return false;
@@ -4824,7 +4981,7 @@ bool ChatHandler::HandleAddTeleCommand(const char * args)
return true;
}
-bool ChatHandler::HandleDelTeleCommand(const char * args)
+bool ChatHandler::HandleTeleDelCommand(const char * args)
{
if(!*args)
return false;
@@ -4860,59 +5017,79 @@ bool ChatHandler::HandleListAurasCommand (const char * /*args*/)
for (Unit::AuraMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr)
{
bool talent = GetTalentSpellCost(itr->second->GetId()) > 0;
- PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(),
- itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(),
- itr->second->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()],
- (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""),
- IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID()));
+
+ char const* name = itr->second->GetSpellProto()->SpellName[GetSessionDbcLocale()];
+
+ if (m_session)
+ {
+ std::ostringstream ss_name;
+ ss_name << "|cffffffff|Hspell:" << itr->second->GetId() << "|h[" << name << "]|h|r";
+
+ PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffectMask(),
+ itr->second->GetAuraCharges(), itr->second->GetStackAmount(),itr->second->GetAuraSlot(),
+ itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(),
+ ss_name.str().c_str(),
+ (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""),
+ IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID()));
+ }
+ else
+ {
+ PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffectMask(),
+ itr->second->GetAuraCharges(), itr->second->GetStackAmount(),itr->second->GetAuraSlot(),
+ itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(),
+ name,
+ (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""),
+ IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID()));
+ }
}
- for (int i = 0; i < TOTAL_AURAS; i++)
+ for (int i = 0; i < TOTAL_AURAS; ++i)
{
- Unit::AuraList const& uAuraList = unit->GetAurasByType(AuraType(i));
+ Unit::AuraEffectList const& uAuraList = unit->GetAurasByType(AuraType(i));
if (uAuraList.empty()) continue;
PSendSysMessage(LANG_COMMAND_TARGET_LISTAURATYPE, uAuraList.size(), i);
- for (Unit::AuraList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr)
+ for (Unit::AuraEffectList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr)
{
bool talent = GetTalentSpellCost((*itr)->GetId()) > 0;
+
+ char const* name = (*itr)->GetSpellProto()->SpellName[GetSessionDbcLocale()];
+
+ std::ostringstream ss_name;
+ ss_name << "|cffffffff|Hspell:" << (*itr)->GetId() << "|h[" << name << "]|h|r";
+
PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(),
- (*itr)->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()],((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""),
- IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID()));
+ (*itr)->GetAmount());
}
}
return true;
}
-bool ChatHandler::HandleResetHonorCommand (const char * args)
+bool ChatHandler::HandleResetAchievementsCommand (const char * args)
{
- char* pName = strtok((char*)args, "");
- Player *player = NULL;
- if (pName)
- {
- std::string name = pName;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
+ Player* target;
+ uint64 target_guid;
+ if (!extractPlayerTarget((char*)args,&target,&target_guid))
+ return false;
- uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str());
- player = objmgr.GetPlayer(guid);
- }
+ if(target)
+ target->GetAchievementMgr().Reset();
else
- player = getSelectedPlayer();
+ AchievementMgr::DeleteFromDB(GUID_LOPART(target_guid));
- if(!player)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- return true;
- }
+ return true;
+}
+
+bool ChatHandler::HandleResetHonorCommand (const char * args)
+{
+ Player* target;
+ if (!extractPlayerTarget((char*)args,&target))
+ return false;
- player->SetUInt32Value(PLAYER_FIELD_KILLS, 0);
- player->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 0);
- player->SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, 0);
- player->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0);
- player->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
+ target->SetUInt32Value(PLAYER_FIELD_KILLS, 0);
+ target->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 0);
+ target->SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, 0);
+ target->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0);
+ target->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
+ target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL);
return true;
}
@@ -4931,19 +5108,6 @@ static bool HandleResetStatsOrLevelHelper(Player* player)
uint8 powertype = cEntry->powerType;
- uint32 unitfield;
- if(powertype == POWER_RAGE)
- unitfield = 0x1100EE00;
- else if(powertype == POWER_ENERGY)
- unitfield = 0x00000000;
- else if(powertype == POWER_MANA)
- unitfield = 0x0000EE00;
- else
- {
- sLog.outError("Invalid default powertype %u for player (class %u)",powertype,player->getClass());
- return false;
- }
-
// reset m_form if no aura
if(!player->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT))
player->m_form = FORM_NONE;
@@ -4973,9 +5137,7 @@ static bool HandleResetStatsOrLevelHelper(Player* player)
}
}
- // set UNIT_FIELD_BYTES_1 to init state but preserve m_form value
- player->SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield);
- player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY | UNIT_BYTE2_FLAG_UNK5 );
+ player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP );
player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form);
player->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
@@ -4989,128 +5151,71 @@ static bool HandleResetStatsOrLevelHelper(Player* player)
bool ChatHandler::HandleResetLevelCommand(const char * args)
{
- char* pName = strtok((char*)args, "");
- Player *player = NULL;
- if (pName)
- {
- std::string name = pName;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str());
- player = objmgr.GetPlayer(guid);
- }
- else
- player = getSelectedPlayer();
-
- if(!player)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
+ Player* target;
+ if(!extractPlayerTarget((char*)args,&target))
return false;
- }
- if(!HandleResetStatsOrLevelHelper(player))
+ if(!HandleResetStatsOrLevelHelper(target))
return false;
- player->SetLevel(1);
- player->InitStatsForLevel(true);
- player->InitTaxiNodesForLevel();
- player->InitTalentForLevel();
- player->SetUInt32Value(PLAYER_XP,0);
+ // set starting level
+ uint32 start_level = target->getClass() != CLASS_DEATH_KNIGHT
+ ? sWorld.getConfig(CONFIG_START_PLAYER_LEVEL)
+ : sWorld.getConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
- // reset level to summoned pet
- Pet* pet = player->GetPet();
- if(pet && pet->getPetType()==SUMMON_PET)
- pet->InitStatsForLevel(1);
+ target->SetLevel(start_level);
+ target->InitRunes();
+ target->InitStatsForLevel(true);
+ target->InitTaxiNodesForLevel();
+ target->InitGlyphsForLevel();
+ target->InitTalentForLevel();
+ target->SetUInt32Value(PLAYER_XP,0);
+
+ // reset level for pet
+ if(Pet* pet = target->GetPet())
+ pet->SynchronizeLevelWithOwner();
return true;
}
bool ChatHandler::HandleResetStatsCommand(const char * args)
{
- char* pName = strtok((char*)args, "");
- Player *player = NULL;
- if (pName)
- {
- std::string name = pName;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str());
- player = objmgr.GetPlayer(guid);
- }
- else
- player = getSelectedPlayer();
-
- if(!player)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
+ Player* target;
+ if (!extractPlayerTarget((char*)args,&target))
return false;
- }
- if(!HandleResetStatsOrLevelHelper(player))
+ if (!HandleResetStatsOrLevelHelper(target))
return false;
- player->InitStatsForLevel(true);
- player->InitTaxiNodesForLevel();
- player->InitTalentForLevel();
+ target->InitRunes();
+ target->InitStatsForLevel(true);
+ target->InitTaxiNodesForLevel();
+ target->InitGlyphsForLevel();
+ target->InitTalentForLevel();
return true;
}
bool ChatHandler::HandleResetSpellsCommand(const char * args)
{
- char* pName = strtok((char*)args, "");
- Player *player = NULL;
- uint64 playerGUID = 0;
- if (pName)
- {
- std::string name = pName;
-
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- player = objmgr.GetPlayer(name.c_str());
- if(!player)
- playerGUID = objmgr.GetPlayerGUIDByName(name.c_str());
- }
- else
- player = getSelectedPlayer();
-
- if(!player && !playerGUID)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
- }
- if(player)
+ if(target)
{
- player->resetSpells();
+ target->resetSpells();
- ChatHandler(player).SendSysMessage(LANG_RESET_SPELLS);
-
- if(m_session->GetPlayer()!=player)
- PSendSysMessage(LANG_RESET_SPELLS_ONLINE,player->GetName());
+ ChatHandler(target).SendSysMessage(LANG_RESET_SPELLS);
+ if(!m_session || m_session->GetPlayer()!=target)
+ PSendSysMessage(LANG_RESET_SPELLS_ONLINE,GetNameLink(target).c_str());
}
else
{
- CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_SPELLS), GUID_LOPART(playerGUID));
- PSendSysMessage(LANG_RESET_SPELLS_OFFLINE,pName);
+ 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());
}
return true;
@@ -5118,49 +5223,49 @@ bool ChatHandler::HandleResetSpellsCommand(const char * args)
bool ChatHandler::HandleResetTalentsCommand(const char * args)
{
- char* pName = strtok((char*)args, "");
- Player *player = NULL;
- uint64 playerGUID = 0;
- if (pName)
- {
- std::string name = pName;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- player = objmgr.GetPlayer(name.c_str());
- if(!player)
- playerGUID = objmgr.GetPlayerGUIDByName(name.c_str());
- }
- else
- player = getSelectedPlayer();
-
- if(!player && !playerGUID)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
+ Player* target;
+ uint64 target_guid;
+ std::string target_name;
+ if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
return false;
- }
- if(player)
+ if (target)
{
- player->resetTalents(true);
+ target->resetTalents(true);
- ChatHandler(player).SendSysMessage(LANG_RESET_TALENTS);
+ ChatHandler(target).SendSysMessage(LANG_RESET_TALENTS);
+ if (!m_session || m_session->GetPlayer()!=target)
+ PSendSysMessage(LANG_RESET_TALENTS_ONLINE,GetNameLink(target).c_str());
- if(m_session->GetPlayer()!=player)
- PSendSysMessage(LANG_RESET_TALENTS_ONLINE,player->GetName());
+ return true;
}
- else
+ else if (target_guid)
{
- CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_TALENTS), GUID_LOPART(playerGUID) );
- PSendSysMessage(LANG_RESET_TALENTS_OFFLINE,pName);
+ CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_TALENTS), GUID_LOPART(target_guid) );
+ std::string nameLink = playerLink(target_name);
+ PSendSysMessage(LANG_RESET_TALENTS_OFFLINE,nameLink.c_str());
+ return true;
}
- return true;
+ // Try reset talenents as Hunter Pet
+ Creature* creature = getSelectedCreature();
+ if (creature && creature->isPet() && ((Pet *)creature)->getPetType() == HUNTER_PET)
+ {
+ ((Pet *)creature)->resetTalents(true);
+ Unit *owner = creature->GetOwner();
+ if (owner && owner->GetTypeId() == TYPEID_PLAYER)
+ {
+ Player* owner_player = (Player *)owner;
+ ChatHandler(owner_player).SendSysMessage(LANG_RESET_PET_TALENTS);
+ if(!m_session || m_session->GetPlayer()!=owner_player)
+ PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE,GetNameLink(owner_player).c_str());
+ }
+ return true;
+ }
+
+ SendSysMessage(LANG_NO_CHAR_SELECTED);
+ SetSentErrorMessage(true);
+ return false;
}
bool ChatHandler::HandleResetAllCommand(const char * args)
@@ -5177,11 +5282,25 @@ bool ChatHandler::HandleResetAllCommand(const char * args)
{
atLogin = AT_LOGIN_RESET_SPELLS;
sWorld.SendWorldText(LANG_RESETALL_SPELLS);
+ if(!m_session)
+ SendSysMessage(LANG_RESETALL_SPELLS);
}
else if(casename=="talents")
{
atLogin = AT_LOGIN_RESET_TALENTS;
sWorld.SendWorldText(LANG_RESETALL_TALENTS);
+ if(!m_session)
+ SendSysMessage(LANG_RESETALL_TALENTS);
+ }
+ else if(casename=="pet_spells")
+ {
+ CharacterDatabase.PExecute("UPDATE character_pet SET load_flags = load_flags | '%u' WHERE (load_flags & '%u') = '0'",uint32(AT_LOAD_RESET_SPELLS),uint32(AT_LOAD_RESET_SPELLS));
+ HashMapHolder<Player>::MapType const& plist = ObjectAccessor::Instance().GetPlayers();
+ for(HashMapHolder<Player>::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr)
+ if (itr->second->GetPet())
+ itr->second->SetPetAtLoginFlag(AT_LOAD_RESET_SPELLS);
+ sWorld.SendWorldText(LANG_RESETALL_PET_SPELLS);
+ return true;
}
else
{
@@ -5198,7 +5317,7 @@ bool ChatHandler::HandleResetAllCommand(const char * args)
return true;
}
-bool ChatHandler::HandleServerShutDownCancelCommand(const char* args)
+bool ChatHandler::HandleServerShutDownCancelCommand(const char* /*args*/)
{
sWorld.ShutdownCancel();
return true;
@@ -5215,7 +5334,7 @@ bool ChatHandler::HandleServerShutDownCommand(const char* args)
int32 time = atoi (time_str);
///- Prevent interpret wrong arg value as 0 secs shutdown time
- if(time == 0 && (time_str[0]!='0' || time_str[1]!='\0') || time < 0)
+ if ((time == 0 && (time_str[0]!='0' || time_str[1]!='\0')) || time < 0)
return false;
if (exitcode_str)
@@ -5344,7 +5463,7 @@ bool ChatHandler::HandleServerIdleShutDownCommand(const char* args)
return true;
}
-bool ChatHandler::HandleAddQuest(const char* args)
+bool ChatHandler::HandleQuestAdd(const char* args)
{
Player* player = getSelectedPlayer();
if(!player)
@@ -5398,7 +5517,7 @@ bool ChatHandler::HandleAddQuest(const char* args)
return true;
}
-bool ChatHandler::HandleRemoveQuest(const char* args)
+bool ChatHandler::HandleQuestRemove(const char* args)
{
Player* player = getSelectedPlayer();
if(!player)
@@ -5448,7 +5567,7 @@ bool ChatHandler::HandleRemoveQuest(const char* args)
return true;
}
-bool ChatHandler::HandleCompleteQuest(const char* args)
+bool ChatHandler::HandleQuestComplete(const char* args)
{
Player* player = getSelectedPlayer();
if(!player)
@@ -5496,7 +5615,7 @@ bool ChatHandler::HandleCompleteQuest(const char* args)
}
// All creature/GO slain/casted (not required, but otherwise it will display "Creature slain 0/10")
- for(uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
+ for(uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
{
uint32 creature = pQuest->ReqCreatureOrGOId[i];
uint32 creaturecount = pQuest->ReqCreatureOrGOCount[i];
@@ -5522,12 +5641,10 @@ bool ChatHandler::HandleCompleteQuest(const char* args)
if(uint32 repFaction = pQuest->GetRepObjectiveFaction())
{
uint32 repValue = pQuest->GetRepObjectiveValue();
- uint32 curRep = player->GetReputation(repFaction);
+ uint32 curRep = player->GetReputationMgr().GetReputation(repFaction);
if(curRep < repValue)
- {
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(repFaction);
- player->SetFactionReputation(factionEntry,repValue);
- }
+ if(FactionEntry const *factionEntry = sFactionStore.LookupEntry(repFaction))
+ player->GetReputationMgr().SetReputation(factionEntry,repValue);
}
// If the quest requires money
@@ -5556,7 +5673,7 @@ bool ChatHandler::HandleBanIPCommand(const char* args)
bool ChatHandler::HandleBanHelper(BanMode mode, const char* args)
{
- if(!args)
+ if (!*args)
return false;
char* cnameOrIP = strtok ((char*)args, " ");
@@ -5576,7 +5693,7 @@ bool ChatHandler::HandleBanHelper(BanMode mode, const char* args)
switch(mode)
{
case BAN_ACCOUNT:
- if(!AccountMgr::normilizeString(nameOrIP))
+ if(!AccountMgr::normalizeString(nameOrIP))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,nameOrIP.c_str());
SetSentErrorMessage(true);
@@ -5644,7 +5761,7 @@ bool ChatHandler::HandleUnBanIPCommand(const char* args)
bool ChatHandler::HandleUnBanHelper(BanMode mode, const char* args)
{
- if(!args)
+ if (!*args)
return false;
char* cnameOrIP = strtok ((char*)args, " ");
@@ -5656,7 +5773,7 @@ bool ChatHandler::HandleUnBanHelper(BanMode mode, const char* args)
switch(mode)
{
case BAN_ACCOUNT:
- if(!AccountMgr::normilizeString(nameOrIP))
+ if(!AccountMgr::normalizeString(nameOrIP))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,nameOrIP.c_str());
SetSentErrorMessage(true);
@@ -5687,7 +5804,7 @@ bool ChatHandler::HandleUnBanHelper(BanMode mode, const char* args)
bool ChatHandler::HandleBanInfoAccountCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
char* cname = strtok((char*)args, "");
@@ -5695,7 +5812,7 @@ bool ChatHandler::HandleBanInfoAccountCommand(const char* args)
return false;
std::string account_name = cname;
- if(!AccountMgr::normilizeString(account_name))
+ if(!AccountMgr::normalizeString(account_name))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
SetSentErrorMessage(true);
@@ -5714,28 +5831,12 @@ bool ChatHandler::HandleBanInfoAccountCommand(const char* args)
bool ChatHandler::HandleBanInfoCharacterCommand(const char* args)
{
- if(!args)
+ Player* target;
+ uint64 target_guid;
+ if(!extractPlayerTarget((char*)args,&target,&target_guid))
return false;
- char* cname = strtok ((char*)args, "");
- if(!cname)
- return false;
-
- std::string name = cname;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 accountid = objmgr.GetPlayerAccountIdByPlayerName(name);
- if(!accountid)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
+ uint32 accountid = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid);
std::string accountname;
if(!accmgr.GetName(accountid,accountname))
@@ -5777,7 +5878,7 @@ bool ChatHandler::HandleBanInfoHelper(uint32 accountid, char const* accountname)
bool ChatHandler::HandleBanInfoIPCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
char* cIP = strtok ((char*)args, "");
@@ -6034,8 +6135,8 @@ bool ChatHandler::HandleRespawnCommand(const char* /*args*/)
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
- Trinity::RespawnDo u_do;
- Trinity::WorldObjectWorker<Trinity::RespawnDo> worker(u_do);
+ MaNGOS::RespawnDo u_do;
+ MaNGOS::WorldObjectWorker<MaNGOS::RespawnDo> worker(pl,u_do);
TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::RespawnDo>, GridTypeMapContainer > obj_worker(worker);
CellLock<GridReadGuard> cell_lock(cell, p);
@@ -6044,14 +6145,14 @@ bool ChatHandler::HandleRespawnCommand(const char* /*args*/)
return true;
}
-bool ChatHandler::HandleFlyModeCommand(const char* args)
+bool ChatHandler::HandleGMFlyCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
- Unit *unit = getSelectedUnit();
- if (!unit || (unit->GetTypeId() != TYPEID_PLAYER))
- unit = m_session->GetPlayer();
+ Player *target = getSelectedPlayer();
+ if (!target)
+ target = m_session->GetPlayer();
WorldPacket data(12);
if (strncmp(args, "on", 3) == 0)
@@ -6063,16 +6164,16 @@ bool ChatHandler::HandleFlyModeCommand(const char* args)
SendSysMessage(LANG_USE_BOL);
return false;
}
- data.append(unit->GetPackGUID());
+ data.append(target->GetPackGUID());
data << uint32(0); // unknown
- unit->SendMessageToSet(&data, true);
- PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, unit->GetName(), args);
+ target->SendMessageToSet(&data, true);
+ PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, GetNameLink(target).c_str(), args);
return true;
}
-bool ChatHandler::HandleLoadPDumpCommand(const char *args)
+bool ChatHandler::HandlePDumpLoadCommand(const char *args)
{
- if(!args)
+ if (!*args)
return false;
char * file = strtok((char*)args, " ");
@@ -6084,7 +6185,7 @@ bool ChatHandler::HandleLoadPDumpCommand(const char *args)
return false;
std::string account_name = account;
- if(!AccountMgr::normilizeString(account_name))
+ if(!AccountMgr::normalizeString(account_name))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
SetSentErrorMessage(true);
@@ -6181,33 +6282,9 @@ bool ChatHandler::HandleLoadPDumpCommand(const char *args)
return true;
}
-bool ChatHandler::HandleNpcChangeEntryCommand(const char *args)
+bool ChatHandler::HandlePDumpWriteCommand(const char *args)
{
- if(!args)
- return false;
-
- uint32 newEntryNum = atoi(args);
- if(!newEntryNum)
- return false;
-
- Unit* unit = getSelectedUnit();
- if(!unit || unit->GetTypeId() != TYPEID_UNIT)
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
- Creature* creature = (Creature*)unit;
- if(creature->UpdateEntry(newEntryNum))
- SendSysMessage(LANG_DONE);
- else
- SendSysMessage(LANG_ERROR);
- return true;
-}
-
-bool ChatHandler::HandleWritePDumpCommand(const char *args)
-{
- if(!args)
+ if (!*args)
return false;
char* file = strtok((char*)args, " ");
@@ -6222,12 +6299,11 @@ bool ChatHandler::HandleWritePDumpCommand(const char *args)
guid = atoi(p2);
else
{
- std::string name = p2;
-
- if (!normalizePlayerName (name))
+ std::string name = extractPlayerNameFromLink(p2);
+ if(name.empty())
{
- SendSysMessage (LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage (true);
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
return false;
}
@@ -6337,7 +6413,7 @@ bool ChatHandler::HandleMovegensCommand(const char* /*args*/)
return true;
}
-bool ChatHandler::HandlePLimitCommand(const char *args)
+bool ChatHandler::HandleServerPLimitCommand(const char *args)
{
if(*args)
{
@@ -6644,10 +6720,10 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/)
Player* player = getSelectedPlayer();
if (!player) player = m_session->GetPlayer();
uint32 counter = 0;
- for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+ for(uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i)
{
Player::BoundInstancesMap &binds = player->GetBoundInstances(i);
- for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end(); ++itr)
+ for(Player::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr)
{
InstanceSave *save = itr->second.save;
std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL));
@@ -6660,10 +6736,10 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/)
Group *group = player->GetGroup();
if(group)
{
- for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+ for(uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i)
{
Group::BoundInstancesMap &binds = group->GetBoundInstances(i);
- for(Group::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end(); ++itr)
+ for(Group::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr)
{
InstanceSave *save = itr->second.save;
std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL));
@@ -6688,7 +6764,7 @@ bool ChatHandler::HandleInstanceUnbindCommand(const char* args)
Player* player = getSelectedPlayer();
if (!player) player = m_session->GetPlayer();
uint32 counter = 0;
- for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+ for(uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i)
{
Player::BoundInstancesMap &binds = player->GetBoundInstances(i);
for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();)
@@ -6778,6 +6854,29 @@ bool ChatHandler::HandleServerSetMotdCommand(const char* args)
return true;
}
+/// Set whether we accept new clients
+bool ChatHandler::HandleServerSetClosedCommand(const char* args)
+{
+ std::string arg = args;
+
+ if(args == "on")
+ {
+ SendSysMessage(LANG_WORLD_CLOSED);
+ sWorld.SetClosed(true);
+ return true;
+ }
+ if(args == "off")
+ {
+ SendSysMessage(LANG_WORLD_OPENED);
+ sWorld.SetClosed(false);
+ return true;
+ }
+
+ SendSysMessage(LANG_USE_BOL);
+ SetSentErrorMessage(true);
+ return false;
+}
+
/// Set/Unset the expansion level for an account
bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
{
@@ -6805,7 +6904,7 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
{
///- Convert Account name to Upper Format
account_name = szAcc;
- if(!AccountMgr::normilizeString(account_name))
+ if(!AccountMgr::normalizeString(account_name))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
SetSentErrorMessage(true);
@@ -6819,8 +6918,15 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
SetSentErrorMessage(true);
return false;
}
+
}
+ // Let set addon state only for lesser (strong) security level
+ // or to self account
+ if (m_session && m_session->GetAccountId () != account_id &&
+ HasLowerSecurityAccount (NULL,account_id,true))
+ return false;
+
int lev=atoi(szExp); //get int anyway (0 if error)
if(lev < 0)
return false;
@@ -6834,13 +6940,11 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
//Send items by mail
bool ChatHandler::HandleSendItemsCommand(const char* args)
{
- if(!*args)
- return false;
-
// format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12]
-
- char* pName = strtok((char*)args, " ");
- if(!pName)
+ Player* receiver;
+ uint64 receiver_guid;
+ std::string receiver_name;
+ if(!extractPlayerTarget((char*)args,&receiver,&receiver_guid,&receiver_name))
return false;
char* tail1 = strtok(NULL, "");
@@ -6879,8 +6983,7 @@ bool ChatHandler::HandleSendItemsCommand(const char* args)
if (!msgText)
return false;
- // pName, msgSubject, msgText isn't NUL after prev. check
- std::string name = pName;
+ // msgSubject, msgText isn't NUL after prev. check
std::string subject = msgSubject;
std::string text = msgText;
@@ -6915,17 +7018,17 @@ bool ChatHandler::HandleSendItemsCommand(const char* args)
}
uint32 item_count = itemCountStr ? atoi(itemCountStr) : 1;
- if(item_count < 1 || item_proto->MaxCount && item_count > item_proto->MaxCount)
+ if(item_count < 1 || item_proto->MaxCount > 0 && item_count > uint32(item_proto->MaxCount))
{
PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, item_count,item_id);
SetSentErrorMessage(true);
return false;
}
- while(item_count > item_proto->Stackable)
+ while(item_count > item_proto->GetMaxStackSize())
{
- items.push_back(ItemPair(item_id,item_proto->Stackable));
- item_count -= item_proto->Stackable;
+ items.push_back(ItemPair(item_id,item_proto->GetMaxStackSize()));
+ item_count -= item_proto->GetMaxStackSize();
}
items.push_back(ItemPair(item_id,item_count));
@@ -6938,21 +7041,6 @@ bool ChatHandler::HandleSendItemsCommand(const char* args)
}
}
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 receiver_guid = objmgr.GetPlayerGUIDByName(name);
- if(!receiver_guid)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
// from console show not existed sender
uint32 sender_guidlo = m_session ? m_session->GetPlayer()->GetGUIDLow() : 0;
@@ -6960,8 +7048,6 @@ bool ChatHandler::HandleSendItemsCommand(const char* args)
uint32 stationery = MAIL_STATIONERY_GM;
uint32 itemTextId = !text.empty() ? objmgr.CreateItemText( text ) : 0;
- Player *receiver = objmgr.GetPlayer(receiver_guid);
-
// fill mail
MailItemsInfo mi; // item list preparing
@@ -6976,20 +7062,20 @@ bool ChatHandler::HandleSendItemsCommand(const char* args)
WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
- PSendSysMessage(LANG_MAIL_SENT, name.c_str());
+ std::string nameLink = playerLink(receiver_name);
+ PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str());
return true;
}
///Send money by mail
bool ChatHandler::HandleSendMoneyCommand(const char* args)
{
- if (!*args)
- return false;
-
/// format: name "subject text" "mail text" money
- char* pName = strtok((char*)args, " ");
- if (!pName)
+ Player* receiver;
+ uint64 receiver_guid;
+ std::string receiver_name;
+ if(!extractPlayerTarget((char*)args,&receiver,&receiver_guid,&receiver_name))
return false;
char* tail1 = strtok(NULL, "");
@@ -7033,28 +7119,10 @@ bool ChatHandler::HandleSendMoneyCommand(const char* args)
if (money <= 0)
return false;
- // pName, msgSubject, msgText isn't NUL after prev. check
- std::string name = pName;
+ // msgSubject, msgText isn't NUL after prev. check
std::string subject = msgSubject;
std::string text = msgText;
- if (!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 receiver_guid = objmgr.GetPlayerGUIDByName(name);
- if (!receiver_guid)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 mailId = objmgr.GenerateMailID();
-
// from console show not existed sender
uint32 sender_guidlo = m_session ? m_session->GetPlayer()->GetGUIDLow() : 0;
@@ -7062,38 +7130,27 @@ bool ChatHandler::HandleSendMoneyCommand(const char* args)
uint32 stationery = MAIL_STATIONERY_GM;
uint32 itemTextId = !text.empty() ? objmgr.CreateItemText( text ) : 0;
- Player *receiver = objmgr.GetPlayer(receiver_guid);
-
WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, NULL, money, 0, MAIL_CHECK_MASK_NONE);
- PSendSysMessage(LANG_MAIL_SENT, name.c_str());
+ std::string nameLink = playerLink(receiver_name);
+ PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str());
return true;
}
/// Send a message to a player in game
bool ChatHandler::HandleSendMessageCommand(const char* args)
{
- ///- Get the command line arguments
- char* name_str = strtok((char*)args, " ");
- char* msg_str = strtok(NULL, "");
-
- if(!name_str || !msg_str)
- return false;
-
- std::string name = name_str;
-
- if(!normalizePlayerName(name))
+ ///- Find the player
+ Player *rPlayer;
+ std::string rName;
+ if(!extractPlayerTarget((char*)args,&rPlayer,NULL,&rName))
return false;
- ///- Find the player and check that he is not logging out.
- Player *rPlayer = objmgr.GetPlayer(name.c_str());
- if(!rPlayer)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
+ char* msg_str = strtok(NULL, "");
+ if(!msg_str)
return false;
- }
+ ///- Check that he is not logging out.
if(rPlayer->GetSession()->isLogingOut())
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -7107,7 +7164,8 @@ bool ChatHandler::HandleSendMessageCommand(const char* args)
rPlayer->GetSession()->SendAreaTriggerMessage("|cffff0000[Message from administrator]:|r");
//Confirmation message
- PSendSysMessage(LANG_SENDMESSAGE,name.c_str(),msg_str);
+ std::string nameLink = playerLink(rName);
+ PSendSysMessage(LANG_SENDMESSAGE,nameLink.c_str(),msg_str);
return true;
}
@@ -7126,35 +7184,32 @@ bool ChatHandler::HandleModifyGenderCommand(const char *args)
if(!player)
{
- PSendSysMessage(LANG_NO_PLAYER);
+ PSendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
+ PlayerInfo const* info = objmgr.GetPlayerInfo(player->getRace(), player->getClass());
+ if(!info)
+ return false;
+
char const* gender_str = (char*)args;
int gender_len = strlen(gender_str);
- uint32 displayId = player->GetNativeDisplayId();
- char const* gender_full = NULL;
- uint32 new_displayId = displayId;
Gender gender;
- if(!strncmp(gender_str,"male",gender_len)) // MALE
+ if(!strncmp(gender_str, "male", gender_len)) // MALE
{
if(player->getGender() == GENDER_MALE)
return true;
- gender_full = "male";
- new_displayId = player->getRace() == RACE_BLOODELF ? displayId+1 : displayId-1;
gender = GENDER_MALE;
}
- else if (!strncmp(gender_str,"female",gender_len)) // FEMALE
+ else if (!strncmp(gender_str, "female", gender_len)) // FEMALE
{
if(player->getGender() == GENDER_FEMALE)
return true;
- gender_full = "female";
- new_displayId = player->getRace() == RACE_BLOODELF ? displayId-1 : displayId+1;
gender = GENDER_FEMALE;
}
else
@@ -7169,12 +7224,16 @@ bool ChatHandler::HandleModifyGenderCommand(const char *args)
player->SetByteValue(PLAYER_BYTES_3, 0, gender);
// Change display ID
- player->SetDisplayId(new_displayId);
- player->SetNativeDisplayId(new_displayId);
+ player->SetDisplayId(gender ? info->displayId_f : info->displayId_m);
+ player->SetNativeDisplayId(gender ? info->displayId_f : info->displayId_m);
+
+ char const* gender_full = gender ? "female" : "male";
+
+ PSendSysMessage(LANG_YOU_CHANGE_GENDER, GetNameLink(player).c_str(), gender_full);
- PSendSysMessage(LANG_YOU_CHANGE_GENDER, player->GetName(),gender_full);
if (needReportToTarget(player))
- ChatHandler(player).PSendSysMessage(LANG_YOUR_GENDER_CHANGED, gender_full,GetName());
+ ChatHandler(player).PSendSysMessage(LANG_YOUR_GENDER_CHANGED, gender_full, GetNameLink().c_str());
+
return true;
}
@@ -7262,26 +7321,10 @@ bool ChatHandler::HandleFreezeCommand(const char *args)
}
}
- //stop movement and disable spells
- uint32 spellID = 9454;
//m_session->GetPlayer()->CastSpell(player,spellID,false);
- SpellEntry const *spellInfo = sSpellStore.LookupEntry( spellID );
- if(spellInfo) //TODO: Change the duration of the aura to -1 instead of 5000000
- {
- for(uint32 i = 0;i<3;i++)
- {
- uint8 eff = spellInfo->Effect[i];
- if (eff>=TOTAL_SPELL_EFFECTS)
- continue;
- if( eff == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || eff == SPELL_EFFECT_APPLY_AURA ||
- eff == SPELL_EFFECT_PERSISTENT_AREA_AURA || eff == SPELL_EFFECT_APPLY_AREA_AURA_FRIEND ||
- eff == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY)
- {
- Aura *Aur = CreateAura(spellInfo, i, NULL, player);
- player->AddAura(Aur);
- }
- }
- }
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry( 9454 );
+ Aura *Aur = new Aura(spellInfo, 1, NULL, player);
+ player->AddAura(Aur);
//save player
player->SaveToDB();
@@ -7320,8 +7363,7 @@ bool ChatHandler::HandleUnFreezeCommand(const char *args)
player->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
//allow movement and spells
- uint32 spellID = 9454;
- player->RemoveAurasDueToSpell(spellID);
+ player->RemoveAurasDueToSpell(9454);
//save player
player->SaveToDB();
@@ -7437,9 +7479,9 @@ bool ChatHandler::HandleUnPossessCommand(const char* args)
Unit* pUnit = getSelectedUnit();
if(!pUnit) pUnit = m_session->GetPlayer();
- pUnit->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM);
- pUnit->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS_PET);
- pUnit->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS);
+ pUnit->RemoveAurasByType(SPELL_AURA_MOD_CHARM);
+ pUnit->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET);
+ pUnit->RemoveAurasByType(SPELL_AURA_MOD_POSSESS);
return true;
}
diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp
index 6ca7ae1c535..172a6ef46c2 100644
--- a/src/game/LootHandler.cpp
+++ b/src/game/LootHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,8 +46,7 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
if (IS_GAMEOBJECT_GUID(lguid))
{
- GameObject *go =
- ObjectAccessor::GetGameObject(*player, lguid);
+ GameObject *go = player->GetMap()->GetGameObject(lguid);
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
if (!go || (go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))
@@ -82,8 +81,7 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
}
else
{
- Creature* pCreature =
- ObjectAccessor::GetCreature(*player, lguid);
+ Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid);
bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed);
@@ -154,6 +152,8 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
--loot->unlootedCount;
player->SendNewItem(newitem, uint32(item->count), false, false, true);
+ player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count);
+ player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count);
}
else
player->SendEquipError( msg, NULL, NULL );
@@ -174,7 +174,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
{
case HIGHGUID_GAMEOBJECT:
{
- GameObject *pGameObject = ObjectAccessor::GetGameObject(*GetPlayer(), guid);
+ GameObject *pGameObject = GetPlayer()->GetMap()->GetGameObject(guid);
// not check distance for GO in case owned GO (fishing bobber case, for example)
if( pGameObject && (pGameObject->GetOwnerGUID()==_player->GetGUID() || pGameObject->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) )
@@ -199,7 +199,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
}
case HIGHGUID_UNIT:
{
- Creature* pCreature = ObjectAccessor::GetCreature(*GetPlayer(), guid);
+ Creature* pCreature = GetPlayer()->GetMap()->GetCreature(guid);
bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed);
@@ -224,15 +224,16 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
Player* playerGroup = itr->getSource();
if(!playerGroup)
continue;
- if (player->GetDistance2d(playerGroup) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if (player->IsWithinDist(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
playersNear.push_back(playerGroup);
}
uint32 money_per_player = uint32((pLoot->gold)/(playersNear.size()));
- for (std::vector<Player*>::iterator i = playersNear.begin(); i != playersNear.end(); ++i)
+ for (std::vector<Player*>::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i)
{
(*i)->ModifyMoney( money_per_player );
+ (*i)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, money_per_player);
//Offset surely incorrect, but works
WorldPacket data( SMSG_LOOT_MONEY_NOTIFY, 4 );
data << uint32(money_per_player);
@@ -240,7 +241,10 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
}
}
else
+ {
player->ModifyMoney( pLoot->gold );
+ player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold);
+ }
pLoot->gold = 0;
pLoot->NotifyMoneyRemoved();
}
@@ -283,10 +287,12 @@ void WorldSession::DoLootRelease( uint64 lguid )
player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING);
+ if(!player->IsInWorld())
+ return;
+
if (IS_GAMEOBJECT_GUID(lguid))
{
- GameObject *go =
- ObjectAccessor::GetGameObject(*player, lguid);
+ GameObject *go = GetPlayer()->GetMap()->GetGameObject(lguid);
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
if (!go || (go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))
@@ -326,7 +332,7 @@ void WorldSession::DoLootRelease( uint64 lguid )
int32 ReqValue = 175;
LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId);
if(lockInfo)
- ReqValue = lockInfo->requiredminingskill;
+ ReqValue = lockInfo->Skill[0];
float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25);
double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses));
if(roll_chance_f(100*chance+skill))
@@ -383,14 +389,22 @@ void WorldSession::DoLootRelease( uint64 lguid )
Item *pItem = player->GetItemByGuid(lguid );
if(!pItem)
return;
- if( (pItem->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) &&
- pItem->GetProto()->Class == ITEM_CLASS_TRADE_GOODS &&
- pItem->GetCount() >= 5)
+
+ ItemPrototype const* proto = pItem->GetProto();
+
+ // destroy only 5 items from stack in case prospecting and milling
+ if( (proto->BagFamily & (BAG_FAMILY_MASK_MINING_SUPP|BAG_FAMILY_MASK_HERBS)) &&
+ proto->Class == ITEM_CLASS_TRADE_GOODS)
{
pItem->m_lootGenerated = false;
pItem->loot.clear();
- uint32 count = 5;
+ uint32 count = pItem->GetCount();
+
+ // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks.
+ if(count > 5)
+ count = 5;
+
player->DestroyItemCount(pItem, count, true);
}
else
@@ -400,7 +414,7 @@ void WorldSession::DoLootRelease( uint64 lguid )
}
else
{
- Creature* pCreature = ObjectAccessor::GetCreature(*player, lguid);
+ Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid);
bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed);
if ( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) )
@@ -457,7 +471,7 @@ void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data )
if(IS_CREATURE_GUID(GetPlayer()->GetLootGUID()))
{
- Creature *pCreature = ObjectAccessor::GetCreature(*GetPlayer(), lootguid);
+ Creature *pCreature = GetPlayer()->GetMap()->GetCreature(lootguid);
if(!pCreature)
return;
@@ -465,7 +479,7 @@ void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data )
}
else if(IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID()))
{
- GameObject *pGO = ObjectAccessor::GetGameObject(*GetPlayer(), lootguid);
+ GameObject *pGO = GetPlayer()->GetMap()->GetGameObject(lootguid);
if(!pGO)
return;
@@ -477,7 +491,7 @@ void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data )
if (slotid > pLoot->items.size())
{
- sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %d)",GetPlayer()->GetName(), slotid, pLoot->items.size());
+ sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size());
return;
}
@@ -495,6 +509,8 @@ void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data )
// not move item from loot to target inventory
Item * newitem = target->StoreNewItem( dest, item.itemid, true, item.randomPropertyId );
target->SendNewItem(newitem, uint32(item.count), false, false, true );
+ target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count);
+ target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, pLoot->loot_type, item.count);
// mark as looted
item.count=0;
diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp
index c8511c3deeb..86cbeb75b0b 100644
--- a/src/game/LootMgr.cpp
+++ b/src/game/LootMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include "World.h"
#include "Util.h"
#include "SharedDefines.h"
+#include "SpellMgr.h"
static Rates const qualityToRate[MAX_ITEM_QUALITY] = {
RATE_DROP_ITEM_POOR, // ITEM_QUALITY_POOR
@@ -36,16 +37,18 @@ static Rates const qualityToRate[MAX_ITEM_QUALITY] = {
RATE_DROP_ITEM_ARTIFACT, // ITEM_QUALITY_ARTIFACT
};
-LootStore LootTemplates_Creature( "creature_loot_template", "creature entry");
-LootStore LootTemplates_Disenchant( "disenchant_loot_template", "item disenchant id");
-LootStore LootTemplates_Fishing( "fishing_loot_template", "area id");
-LootStore LootTemplates_Gameobject( "gameobject_loot_template", "gameobject entry");
-LootStore LootTemplates_Item( "item_loot_template", "item entry");
-LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid");
-LootStore LootTemplates_Prospecting( "prospecting_loot_template", "item entry");
-LootStore LootTemplates_QuestMail( "quest_mail_loot_template", "quest id");
-LootStore LootTemplates_Reference( "reference_loot_template", "reference id");
-LootStore LootTemplates_Skinning( "skinning_loot_template", "creature skinning id");
+LootStore LootTemplates_Creature( "creature_loot_template", "creature entry", true);
+LootStore LootTemplates_Disenchant( "disenchant_loot_template", "item disenchant id", true);
+LootStore LootTemplates_Fishing( "fishing_loot_template", "area id", true);
+LootStore LootTemplates_Gameobject( "gameobject_loot_template", "gameobject entry", true);
+LootStore LootTemplates_Item( "item_loot_template", "item entry", true);
+LootStore LootTemplates_Milling( "milling_loot_template", "item entry (herb)", true);
+LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid", true);
+LootStore LootTemplates_Prospecting( "prospecting_loot_template", "item entry (ore)", true);
+LootStore LootTemplates_QuestMail( "quest_mail_loot_template", "quest id (with mail template)",false);
+LootStore LootTemplates_Reference( "reference_loot_template", "reference id", false);
+LootStore LootTemplates_Skinning( "skinning_loot_template", "creature skinning id", true);
+LootStore LootTemplates_Spell( "spell_loot_template", "spell id (explicitly discovering ability)",false);
class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed)
@@ -89,7 +92,7 @@ void LootStore::Verify() const
// All checks of the loaded template are called from here, no error reports at loot generation required
void LootStore::LoadLootTable()
{
- LootTemplateMap::iterator tab;
+ LootTemplateMap::const_iterator tab;
uint32 count = 0;
// Clearing store (for reloading case)
@@ -114,11 +117,18 @@ void LootStore::LoadLootTable()
float chanceOrQuestChance = fields[2].GetFloat();
uint8 group = fields[3].GetUInt8();
int32 mincountOrRef = fields[4].GetInt32();
- uint8 maxcount = fields[5].GetUInt8();
+ uint32 maxcount = fields[5].GetUInt32();
ConditionType condition = (ConditionType)fields[6].GetUInt8();
uint32 cond_value1 = fields[7].GetUInt32();
uint32 cond_value2 = fields[8].GetUInt32();
+ if(maxcount > std::numeric_limits<uint8>::max())
+ {
+ sLog.outErrorDb("Table '%s' entry %d item %d: maxcount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount,std::numeric_limits<uint8>::max());
+ continue; // error already printed to log/console.
+ }
+
+
if(!PlayerCondition::IsValid(condition,cond_value1, cond_value2))
{
sLog.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry, item);
@@ -159,7 +169,7 @@ void LootStore::LoadLootTable()
Verify(); // Checks validity of the loot store
sLog.outString();
- sLog.outString( ">> Loaded %u loot definitions (%d templates)", count, m_LootTemplates.size());
+ sLog.outString( ">> Loaded %u loot definitions (%lu templates)", count, (unsigned long)m_LootTemplates.size());
}
else
{
@@ -230,17 +240,17 @@ void LootStore::ReportNotExistedId(uint32 id) const
// Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
// RATE_DROP_ITEMS is no longer used for all types of entries
-bool LootStoreItem::Roll() const
+bool LootStoreItem::Roll(bool rate) const
{
- if(chance>=100.f)
+ if(chance>=100.0f)
return true;
if(mincountOrRef < 0) // reference case
- return roll_chance_f(chance*sWorld.getRate(RATE_DROP_ITEM_REFERENCED));
+ return roll_chance_f(chance* (rate ? sWorld.getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
- float qualityModifier = pProto ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
+ float qualityModifier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f;
return roll_chance_f(chance*qualityModifier);
}
@@ -248,6 +258,12 @@ bool LootStoreItem::Roll() const
// Checks correctness of values
bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
{
+ if(group >= 1 << 7) // it stored in 7 bit field
+ {
+ sLog.outErrorDb("Table '%s' entry %d item %d: group (%u) must be less %u - skipped", store.GetName(), entry, itemid, group, 1 << 7);
+ return false;
+ }
+
if (mincountOrRef == 0)
{
sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef);
@@ -275,6 +291,13 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
store.GetName(), entry, itemid, chance);
return false;
}
+
+ if( maxcount < mincountOrRef) // wrong max count
+ {
+ sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, uint32(maxcount), mincountOrRef);
+ return false;
+ }
+
}
else // mincountOrRef < 0
{
@@ -366,8 +389,12 @@ void Loot::AddItem(LootStoreItem const & item)
}
// Calls processor of corresponding LootTemplate (which handles everything including references)
-void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner)
+void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal)
{
+ // Must be provided
+ if(!loot_owner)
+ return;
+
LootTemplate const* tab = store.GetLootFor(loot_id);
if (!tab)
@@ -379,44 +406,43 @@ void Loot::FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner)
items.reserve(MAX_NR_LOOT_ITEMS);
quest_items.reserve(MAX_NR_QUEST_ITEMS);
- tab->Process(*this, store); // Processing is done there, callback via Loot::AddItem()
+ tab->Process(*this, store,store.IsRatesAllowed ()); // Processing is done there, callback via Loot::AddItem()
- // Setting access rights fow group-looting case
- if(!loot_owner)
- return;
+ // Setting access rights for group loot case
Group * pGroup=loot_owner->GetGroup();
- if(!pGroup)
- return;
- for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ if(!personal && pGroup)
{
- //fill the quest item map for every player in the recipient's group
- Player* pl = itr->getSource();
- if(!pl)
- continue;
- uint32 plguid = pl->GetGUIDLow();
- QuestItemMap::iterator qmapitr = PlayerQuestItems.find(plguid);
- if (qmapitr == PlayerQuestItems.end())
- {
- FillQuestLoot(pl);
- }
- qmapitr = PlayerFFAItems.find(plguid);
- if (qmapitr == PlayerFFAItems.end())
- {
- FillFFALoot(pl);
- }
- qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
- if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
- {
- FillNonQuestNonFFAConditionalLoot(pl);
- }
+ for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ if(Player* pl = itr->getSource())
+ FillNotNormalLootFor(pl);
}
+ // ... for personal loot
+ else
+ FillNotNormalLootFor(loot_owner);
+}
+
+void Loot::FillNotNormalLootFor(Player* pl)
+{
+ uint32 plguid = pl->GetGUIDLow();
+
+ QuestItemMap::const_iterator qmapitr = PlayerQuestItems.find(plguid);
+ if (qmapitr == PlayerQuestItems.end())
+ FillQuestLoot(pl);
+
+ qmapitr = PlayerFFAItems.find(plguid);
+ if (qmapitr == PlayerFFAItems.end())
+ FillFFALoot(pl);
+
+ qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid);
+ if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
+ FillNonQuestNonFFAConditionalLoot(pl);
}
QuestItemList* Loot::FillFFALoot(Player* player)
{
QuestItemList *ql = new QuestItemList();
- for(uint8 i = 0; i < items.size(); i++)
+ for(uint8 i = 0; i < items.size(); ++i)
{
LootItem &item = items[i];
if(!item.is_looted && item.freeforall && item.AllowedForPlayer(player) )
@@ -440,7 +466,7 @@ QuestItemList* Loot::FillQuestLoot(Player* player)
if (items.size() == MAX_NR_LOOT_ITEMS) return NULL;
QuestItemList *ql = new QuestItemList();
- for(uint8 i = 0; i < quest_items.size(); i++)
+ for(uint8 i = 0; i < quest_items.size(); ++i)
{
LootItem &item = quest_items[i];
if(!item.is_looted && item.AllowedForPlayer(player) )
@@ -544,7 +570,7 @@ void Loot::NotifyQuestItemRemoved(uint8 questIndex)
++i_next;
if(Player* pl = ObjectAccessor::FindPlayer(*i))
{
- QuestItemMap::iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
+ QuestItemMap::const_iterator pq = PlayerQuestItems.find(pl->GetGUIDLow());
if (pq != PlayerQuestItems.end() && pq->second)
{
// find where/if the player has the given item in it's vector
@@ -603,7 +629,7 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qite
QuestItemMap::const_iterator itr = PlayerFFAItems.find(player->GetGUIDLow());
if (itr != PlayerFFAItems.end())
{
- for(QuestItemList::iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
+ for(QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
if(iter->index==lootSlot)
{
QuestItem *ffaitem2 = (QuestItem*)&(*iter);
@@ -619,7 +645,7 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qite
QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
if (itr != PlayerNonQuestNonFFAConditionalItems.end())
{
- for(QuestItemList::iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
+ for(QuestItemList::const_iterator iter=itr->second->begin(); iter!= itr->second->end(); ++iter)
{
if(iter->index==lootSlot)
{
@@ -640,6 +666,12 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qite
return item;
}
+uint32 Loot::GetMaxSlotInLootFor(Player* player) const
+{
+ QuestItemMap::const_iterator itr = PlayerQuestItems.find(player->GetGUIDLow());
+ return items.size() + (itr != PlayerQuestItems.end() ? itr->second->size() : 0);
+}
+
ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
{
b << uint32(li.itemid);
@@ -653,12 +685,19 @@ ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
{
+ if (lv.permission == NONE_PERMISSION)
+ {
+ b << uint32(0); //gold
+ b << uint8(0); // item count
+ return b; // nothing output more
+ }
+
Loot &l = lv.loot;
uint8 itemsShown = 0;
//gold
- b << uint32(lv.permission!=NONE_PERMISSION ? l.gold : 0);
+ b << uint32(l.gold);
size_t count_pos = b.wpos(); // pos of item count byte
b << uint8(0); // item count placeholder
@@ -697,19 +736,21 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
}
break;
}
- case NONE_PERMISSION:
default:
return b; // nothing output more
}
- if (lv.qlist)
+ QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
+ QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUIDLow());
+ if (q_itr != lootPlayerQuestItems.end())
{
- for (QuestItemList::iterator qi = lv.qlist->begin() ; qi != lv.qlist->end(); ++qi)
+ QuestItemList *q_list = q_itr->second;
+ for (QuestItemList::const_iterator qi = q_list->begin() ; qi != q_list->end(); ++qi)
{
LootItem &item = l.quest_items[qi->index];
if (!qi->is_looted && !item.is_looted)
{
- b << uint8(l.items.size() + (qi - lv.qlist->begin()));
+ b << uint8(l.items.size() + (qi - q_list->begin()));
b << item;
b << uint8(0); // allow loot
++itemsShown;
@@ -717,9 +758,12 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
}
}
- if (lv.ffalist)
+ QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
+ QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUIDLow());
+ if (ffa_itr != lootPlayerFFAItems.end())
{
- for (QuestItemList::iterator fi = lv.ffalist->begin() ; fi != lv.ffalist->end(); ++fi)
+ QuestItemList *ffa_list = ffa_itr->second;
+ for (QuestItemList::const_iterator fi = ffa_list->begin() ; fi != ffa_list->end(); ++fi)
{
LootItem &item = l.items[fi->index];
if (!fi->is_looted && !item.is_looted)
@@ -731,9 +775,12 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
}
}
- if (lv.conditionallist)
+ QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
+ QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUIDLow());
+ if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
{
- for (QuestItemList::iterator ci = lv.conditionallist->begin() ; ci != lv.conditionallist->end(); ++ci)
+ QuestItemList *conditional_list = nn_itr->second;
+ for (QuestItemList::const_iterator ci = conditional_list->begin() ; ci != conditional_list->end(); ++ci)
{
LootItem &item = l.items[ci->index];
if (!ci->is_looted && !item.is_looted)
@@ -773,10 +820,9 @@ LootStoreItem const * LootTemplate::LootGroup::Roll() const
for (uint32 i=0; i<ExplicitlyChanced.size(); ++i) //check each explicitly chanced entry in the template and modify its chance based on quality.
{
- if(ExplicitlyChanced[i].chance>=100.f)
+ if(ExplicitlyChanced[i].chance>=100.0f)
return &ExplicitlyChanced[i];
- ItemPrototype const *pProto = objmgr.GetItemPrototype(ExplicitlyChanced[i].itemid);
Roll -= ExplicitlyChanced[i].chance;
if (Roll < 0)
return &ExplicitlyChanced[i];
@@ -900,7 +946,7 @@ void LootTemplate::AddEntry(LootStoreItem& item)
}
// Rolls for every item in the template and adds the rolled items the the loot
-void LootTemplate::Process(Loot& loot, LootStore const& store, uint8 groupId) const
+void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 groupId) const
{
if (groupId) // Group reference uses own processing of the group
{
@@ -914,7 +960,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint8 groupId) co
// Rolling non-grouped items
for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i )
{
- if ( !i->Roll() )
+ if (!i->Roll(rate))
continue; // Bad luck for the entry
if (i->mincountOrRef < 0) // References processing
@@ -925,7 +971,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint8 groupId) co
continue; // Error message already printed at loading stage
for (uint32 loop=0; loop < i->maxcount; ++loop )// Ref multiplicator
- Referenced->Process(loot, store, i->group); // Ref processing
+ Referenced->Process(loot, store, rate, i->group);
}
else // Plain entries (not a reference, not grouped)
loot.AddItem(*i); // Chance is already checked, just add
@@ -995,7 +1041,7 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co
// Now checking groups
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i )
- if (i->HasQuestDrop())
+ if (i->HasQuestDropForPlayer(player))
return true;
return false;
@@ -1137,6 +1183,29 @@ void LoadLootTemplates_Item()
LootTemplates_Item.ReportUnusedIds(ids_set);
}
+void LoadLootTemplates_Milling()
+{
+ LootIdSet ids_set;
+ LootTemplates_Milling.LoadAndCollectLootIds(ids_set);
+
+ // remove real entries and check existence loot
+ for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
+ {
+ ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
+ if(!proto)
+ continue;
+
+ if((proto->BagFamily & BAG_FAMILY_MASK_HERBS)==0)
+ continue;
+
+ if(ids_set.count(proto->ItemId))
+ ids_set.erase(proto->ItemId);
+ }
+
+ // output error for any still listed (not referenced from appropriate table) ids
+ LootTemplates_Milling.ReportUnusedIds(ids_set);
+}
+
void LoadLootTemplates_Pickpocketing()
{
LootIdSet ids_set, ids_setUsed;
@@ -1170,9 +1239,17 @@ void LoadLootTemplates_Prospecting()
// remove real entries and check existence loot
for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
- if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
- if(ids_set.count(proto->ItemId))
- ids_set.erase(proto->ItemId);
+ {
+ ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
+ if(!proto)
+ continue;
+
+ if((proto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)==0)
+ continue;
+
+ if(ids_set.count(proto->ItemId))
+ ids_set.erase(proto->ItemId);
+ }
// output error for any still listed (not referenced from appropriate table) ids
LootTemplates_Prospecting.ReportUnusedIds(ids_set);
@@ -1186,8 +1263,17 @@ void LoadLootTemplates_QuestMail()
// remove real entries and check existence loot
ObjectMgr::QuestMap const& questMap = objmgr.GetQuestTemplates();
for(ObjectMgr::QuestMap::const_iterator itr = questMap.begin(); itr != questMap.end(); ++itr )
+ {
+ if(!itr->second->GetRewMailTemplateId())
+ continue;
+
if(ids_set.count(itr->first))
ids_set.erase(itr->first);
+ /* disabled reporting: some quest mails not include items
+ else
+ LootTemplates_QuestMail.ReportNotExistedId(itr->first);
+ */
+ }
// output error for any still listed (not referenced from appropriate table) ids
LootTemplates_QuestMail.ReportUnusedIds(ids_set);
@@ -1219,6 +1305,37 @@ void LoadLootTemplates_Skinning()
LootTemplates_Skinning.ReportUnusedIds(ids_set);
}
+void LoadLootTemplates_Spell()
+{
+ LootIdSet ids_set;
+ LootTemplates_Spell.LoadAndCollectLootIds(ids_set);
+
+ // remove real entries and check existence loot
+ for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry (spell_id);
+ if(!spellInfo)
+ continue;
+
+ // possible cases
+ if( !IsLootCraftingSpell(spellInfo))
+ continue;
+
+ if(!ids_set.count(spell_id))
+ {
+ // not report about not trainable spells (optionally supported by DB) except with SPELL_ATTR_EX2_UNK14 (clams)
+ // 61756 (Northrend Inscription Research (FAST QA VERSION) for example
+ if ((spellInfo->Attributes & SPELL_ATTR_UNK5) || (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK14))
+ LootTemplates_Spell.ReportNotExistedId(spell_id);
+ }
+ else
+ ids_set.erase(spell_id);
+ }
+
+ // output error for any still listed (not referenced from appropriate table) ids
+ LootTemplates_QuestMail.ReportUnusedIds(ids_set);
+}
+
void LoadLootTemplates_Reference()
{
LootIdSet ids_set;
@@ -1229,6 +1346,7 @@ void LoadLootTemplates_Reference()
LootTemplates_Fishing.CheckLootRefs(&ids_set);
LootTemplates_Gameobject.CheckLootRefs(&ids_set);
LootTemplates_Item.CheckLootRefs(&ids_set);
+ LootTemplates_Milling.CheckLootRefs(&ids_set);
LootTemplates_Pickpocketing.CheckLootRefs(&ids_set);
LootTemplates_Skinning.CheckLootRefs(&ids_set);
LootTemplates_Disenchant.CheckLootRefs(&ids_set);
diff --git a/src/game/LootMgr.h b/src/game/LootMgr.h
index 8c64531bf4a..c629977ea67 100644
--- a/src/game/LootMgr.h
+++ b/src/game/LootMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,6 +57,21 @@ enum PermissionTypes
NONE_PERMISSION = 3
};
+enum LootType
+{
+ LOOT_CORPSE = 1,
+ LOOT_PICKPOCKETING = 2,
+ LOOT_FISHING = 3,
+ LOOT_DISENCHANTING = 4,
+ // ignored always by client
+ LOOT_SKINNING = 6,
+ LOOT_PROSPECTING = 7,
+ LOOT_MILLING = 8,
+
+ LOOT_FISHINGHOLE = 20, // unsupported by client, sending LOOT_FISHING instead
+ LOOT_INSIGNIA = 21 // unsupported by client, sending LOOT_CORPSE instead
+};
+
class Player;
class LootStore;
@@ -65,19 +80,19 @@ struct LootStoreItem
uint32 itemid; // id of the item
float chance; // always positive, chance to drop for both quest and non-quest items, chance to be used for refs
int32 mincountOrRef; // mincount for drop items (positive) or minus referenced TemplateleId (negative)
- uint8 group :8;
+ uint8 group :7;
+ bool needs_quest :1; // quest drop (negative ChanceOrQuestChance in DB)
uint8 maxcount :8; // max drop count for the item (mincountOrRef positive) or Ref multiplicator (mincountOrRef negative)
uint16 conditionId :16; // additional loot condition Id
- bool needs_quest :1; // quest drop (negative ChanceOrQuestChance in DB)
// Constructor, converting ChanceOrQuestChance -> (chance, needs_quest)
// displayid is filled in IsValid() which must be called after
LootStoreItem(uint32 _itemid, float _chanceOrQuestChance, int8 _group, uint8 _conditionId, int32 _mincountOrRef, uint8 _maxcount)
: itemid(_itemid), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef),
- group(_group), maxcount(_maxcount), conditionId(_conditionId),
- needs_quest(_chanceOrQuestChance < 0) {}
+ group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount), conditionId(_conditionId)
+ {}
- bool Roll() const; // Checks if the entry takes it's chance (at loot generation)
+ bool Roll(bool rate) const; // Checks if the entry takes it's chance (at loot generation)
bool IsValid(LootStore const& store, uint32 entry) const;
// Checks correctness of values
};
@@ -129,7 +144,8 @@ typedef std::set<uint32> LootIdSet;
class LootStore
{
public:
- explicit LootStore(char const* name, char const* entryName) : m_name(name), m_entryName(entryName) {}
+ explicit LootStore(char const* name, char const* entryName, bool ratesAllowed)
+ : m_name(name), m_entryName(entryName), m_ratesAllowed(ratesAllowed) {}
virtual ~LootStore() { Clear(); }
void Verify() const;
@@ -147,6 +163,7 @@ class LootStore
char const* GetName() const { return m_name; }
char const* GetEntryName() const { return m_entryName; }
+ bool IsRatesAllowed() const { return m_ratesAllowed; }
protected:
void LoadLootTable();
void Clear();
@@ -154,6 +171,7 @@ class LootStore
LootTemplateMap m_LootTemplates;
char const* m_name;
char const* m_entryName;
+ bool m_ratesAllowed;
};
class LootTemplate
@@ -165,7 +183,7 @@ class LootTemplate
// Adds an entry to the group (at loading stage)
void AddEntry(LootStoreItem& item);
// Rolls for every item in the template and adds the rolled items the the loot
- void Process(Loot& loot, LootStore const& store, uint8 GroupId = 0) const;
+ void Process(Loot& loot, LootStore const& store, bool rate, uint8 GroupId = 0) const;
// True if template includes at least 1 quest drop entry
bool HasQuestDrop(LootTemplateMap const& store, uint8 GroupId = 0) const;
@@ -207,23 +225,25 @@ class LootValidatorRefManager : public RefManager<Loot, LootValidatorRef>
};
//=====================================================
+struct LootView;
+
+ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li);
+ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv);
struct Loot
{
+ friend ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv);
+
QuestItemMap const& GetPlayerQuestItems() const { return PlayerQuestItems; }
QuestItemMap const& GetPlayerFFAItems() const { return PlayerFFAItems; }
QuestItemMap const& GetPlayerNonQuestNonFFAConditionalItems() const { return PlayerNonQuestNonFFAConditionalItems; }
- QuestItemList* FillFFALoot(Player* player);
- QuestItemList* FillQuestLoot(Player* player);
- QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player);
-
std::vector<LootItem> items;
- std::vector<LootItem> quest_items;
uint32 gold;
uint8 unlootedCount;
+ LootType loot_type; // required for achievement system
- Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0) {}
+ Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), loot_type(LOOT_CORPSE) {}
~Loot() { clear(); }
// if loot becomes invalid this reference is used to inform the listener
@@ -235,18 +255,19 @@ struct Loot
// void clear();
void clear()
{
- items.clear(); gold = 0; PlayersLooting.clear();
- for (QuestItemMap::iterator itr = PlayerQuestItems.begin(); itr != PlayerQuestItems.end(); ++itr)
- delete itr->second;
- for (QuestItemMap::iterator itr = PlayerFFAItems.begin(); itr != PlayerFFAItems.end(); ++itr)
- delete itr->second;
- for (QuestItemMap::iterator itr = PlayerNonQuestNonFFAConditionalItems.begin(); itr != PlayerNonQuestNonFFAConditionalItems.end(); ++itr)
+ for (QuestItemMap::const_iterator itr = PlayerQuestItems.begin(); itr != PlayerQuestItems.end(); ++itr)
delete itr->second;
-
PlayerQuestItems.clear();
+
+ for (QuestItemMap::const_iterator itr = PlayerFFAItems.begin(); itr != PlayerFFAItems.end(); ++itr)
+ delete itr->second;
PlayerFFAItems.clear();
+
+ for (QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.begin(); itr != PlayerNonQuestNonFFAConditionalItems.end(); ++itr)
+ delete itr->second;
PlayerNonQuestNonFFAConditionalItems.clear();
+ PlayersLooting.clear();
items.clear();
quest_items.clear();
gold = 0;
@@ -264,13 +285,21 @@ struct Loot
void RemoveLooter(uint64 GUID) { PlayersLooting.erase(GUID); }
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount);
- void FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner);
+ void FillLoot(uint32 loot_id, LootStore const& store, Player* loot_owner, bool personal);
// Inserts the item into the loot (called by LootTemplate processors)
void AddItem(LootStoreItem const & item);
LootItem* LootItemInSlot(uint32 lootslot, Player* player, QuestItem** qitem = NULL, QuestItem** ffaitem = NULL, QuestItem** conditem = NULL);
+ uint32 GetMaxSlotInLootFor(Player* player) const;
+
private:
+ void FillNotNormalLootFor(Player* player);
+ QuestItemList* FillFFALoot(Player* player);
+ QuestItemList* FillQuestLoot(Player* player);
+ QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player);
+
+ std::vector<LootItem> quest_items;
std::set<uint64> PlayersLooting;
QuestItemMap PlayerQuestItems;
QuestItemMap PlayerFFAItems;
@@ -278,40 +307,41 @@ struct Loot
// All rolls are registered here. They need to know, when the loot is not valid anymore
LootValidatorRefManager i_LootValidatorRefManager;
-
};
struct LootView
{
Loot &loot;
- QuestItemList *qlist;
- QuestItemList *ffalist;
- QuestItemList *conditionallist;
Player *viewer;
PermissionTypes permission;
- LootView(Loot &_loot, QuestItemList *_qlist, QuestItemList *_ffalist, QuestItemList *_conditionallist, Player *_viewer,PermissionTypes _permission = ALL_PERMISSION)
- : loot(_loot), qlist(_qlist), ffalist(_ffalist), conditionallist(_conditionallist), viewer(_viewer), permission(_permission) {}
+ LootView(Loot &_loot, Player *_viewer,PermissionTypes _permission = ALL_PERMISSION)
+ : loot(_loot), viewer(_viewer), permission(_permission) {}
};
extern LootStore LootTemplates_Creature;
extern LootStore LootTemplates_Fishing;
extern LootStore LootTemplates_Gameobject;
extern LootStore LootTemplates_Item;
+extern LootStore LootTemplates_Milling;
extern LootStore LootTemplates_Pickpocketing;
extern LootStore LootTemplates_Skinning;
extern LootStore LootTemplates_Disenchant;
extern LootStore LootTemplates_Prospecting;
extern LootStore LootTemplates_QuestMail;
+extern LootStore LootTemplates_Spell;
void LoadLootTemplates_Creature();
void LoadLootTemplates_Fishing();
void LoadLootTemplates_Gameobject();
void LoadLootTemplates_Item();
+void LoadLootTemplates_Milling();
void LoadLootTemplates_Pickpocketing();
void LoadLootTemplates_Skinning();
void LoadLootTemplates_Disenchant();
void LoadLootTemplates_Prospecting();
void LoadLootTemplates_QuestMail();
+
+void LoadLootTemplates_Spell();
void LoadLootTemplates_Reference();
inline void LoadLootTables()
@@ -320,15 +350,16 @@ inline void LoadLootTables()
LoadLootTemplates_Fishing();
LoadLootTemplates_Gameobject();
LoadLootTemplates_Item();
+ LoadLootTemplates_Milling();
LoadLootTemplates_Pickpocketing();
LoadLootTemplates_Skinning();
LoadLootTemplates_Disenchant();
LoadLootTemplates_Prospecting();
LoadLootTemplates_QuestMail();
+ LoadLootTemplates_Spell();
+
LoadLootTemplates_Reference();
}
-ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li);
-ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv);
#endif
diff --git a/src/game/Mail.cpp b/src/game/Mail.cpp
index 5698fdf03f2..8f682a858ee 100644
--- a/src/game/Mail.cpp
+++ b/src/game/Mail.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -29,8 +29,8 @@
#include "UpdateMask.h"
#include "Unit.h"
#include "Language.h"
-#include "Database/DBCStores.h"
#include "AuctionHouseBot.h"
+#include "DBCStores.h"
void MailItem::deleteItem( bool inDB )
{
@@ -55,6 +55,9 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
recv_data >> mailbox;
recv_data >> receiver;
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
+ return;
+
// recheck
CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+1+1+4+4+1+4+4+8+1);
@@ -125,9 +128,9 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
return;
}
- uint32 reqmoney = money + 30;
- if (items_count)
- reqmoney = money + (30 * items_count);
+ uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client
+
+ uint32 reqmoney = cost + money;
if (pl->GetMoney() < reqmoney)
{
@@ -210,6 +213,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
}
pl->ModifyMoney( -int32(reqmoney) );
+ pl->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost);
bool needItemDelay = false;
@@ -276,6 +280,10 @@ void WorldSession::HandleMarkAsRead(WorldPacket & recv_data )
uint64 mailbox;
uint32 mailId;
recv_data >> mailbox;
+
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
+ return;
+
recv_data >> mailId;
Player *pl = _player;
Mail *m = pl->GetMail(mailId);
@@ -299,6 +307,10 @@ void WorldSession::HandleMailDelete(WorldPacket & recv_data )
uint32 mailId;
recv_data >> mailbox;
recv_data >> mailId;
+
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
+ return;
+
Player* pl = _player;
pl->m_mailsUpdated = true;
Mail *m = pl->GetMail(mailId);
@@ -314,6 +326,10 @@ void WorldSession::HandleReturnToSender(WorldPacket & recv_data )
uint64 mailbox;
uint32 mailId;
recv_data >> mailbox;
+
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
+ return;
+
recv_data >> mailId;
Player *pl = _player;
Mail *m = pl->GetMail(mailId);
@@ -418,6 +434,10 @@ void WorldSession::HandleTakeItem(WorldPacket & recv_data )
uint32 mailId;
uint32 itemId;
recv_data >> mailbox;
+
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
+ return;
+
recv_data >> mailId;
recv_data >> itemId; // item guid low?
Player* pl = _player;
@@ -509,6 +529,10 @@ void WorldSession::HandleTakeMoney(WorldPacket & recv_data )
uint32 mailId;
recv_data >> mailbox;
recv_data >> mailId;
+
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
+ return;
+
Player *pl = _player;
Mail* m = pl->GetMail(mailId);
@@ -540,9 +564,8 @@ void WorldSession::HandleGetMail(WorldPacket & recv_data )
uint64 mailbox;
recv_data >> mailbox;
- //GameObject* obj = ObjectAccessor::GetGameObject(_player, mailbox);
- //if(!obj || !obj->IsMailBox())
- // return;
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
+ return;
Player* pl = _player;
@@ -601,7 +624,7 @@ void WorldSession::HandleGetMail(WorldPacket & recv_data )
data << (uint32) (*itr)->mailTemplateId; // mail template (MailTemplate.dbc)
data << (*itr)->subject; // Subject string - once 00, when mail type = 3
- data << (uint8) item_count;
+ data << (uint8) item_count; // client limit is 0x10
for(uint8 i = 0; i < item_count; ++i)
{
@@ -612,7 +635,7 @@ void WorldSession::HandleGetMail(WorldPacket & recv_data )
data << (uint32) (item ? item->GetGUIDLow() : 0);
// entry
data << (uint32) (item ? item->GetEntry() : 0);
- for(uint8 j = 0; j < 6; ++j)
+ for(uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j)
{
// unsure
data << (uint32) (item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0);
@@ -626,13 +649,15 @@ void WorldSession::HandleGetMail(WorldPacket & recv_data )
// unk
data << (uint32) (item ? item->GetItemSuffixFactor() : 0);
// stack count
- data << (uint8) (item ? item->GetCount() : 0);
+ data << (uint32) (item ? item->GetCount() : 0);
// charges
data << (uint32) (item ? item->GetSpellCharges() : 0);
// durability
data << (uint32) (item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0);
// durability
data << (uint32) (item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0);
+ // unknown wotlk
+ data << (uint8) 0;
}
mails_count += 1;
@@ -676,6 +701,9 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket & recv_data )
recv_data >> mailbox >> mailId;
+ if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
+ return;
+
Player *pl = _player;
Mail* m = pl->GetMail(mailId);
diff --git a/src/game/Mail.h b/src/game/Mail.h
index 784028e6d5d..6bac6d60735 100644
--- a/src/game/Mail.h
+++ b/src/game/Mail.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -196,11 +196,11 @@ struct Mail
}
}
- bool RemoveItem(uint32 itemId)
+ bool RemoveItem(uint32 item_guid)
{
for(std::vector<MailItemInfo>::iterator itr = items.begin(); itr != items.end(); ++itr)
{
- if(itr->item_guid == itemId)
+ if(itr->item_guid == item_guid)
{
items.erase(itr);
return true;
diff --git a/src/game/Makefile.am b/src/game/Makefile.am
new file mode 100644
index 00000000000..ed918234265
--- /dev/null
+++ b/src/game/Makefile.am
@@ -0,0 +1,850 @@
+# Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+#
+# Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+## Process this file with automake to produce Makefile.in
+
+## Sub-directories to parse
+
+## CPP flags for includes, defines, etc.
+AM_CPPFLAGS = $(TRINI_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../dep/include -I$(srcdir)/../framework -I$(srcdir)/../shared -I$(srcdir)/../shared/vmap -I$(srcdir)/../realmd -DSYSCONFDIR=\"$(sysconfdir)/\"
+
+## Build MaNGOS game library as convenience library.
+# All libraries will be convenience libraries. Might be changed to shared
+# later.
+noinst_LIBRARIES = libmangosgame.a
+
+# libmangossgame library will later be reused by ...
+libmangosgame_a_SOURCES = \
+<<<<<<< HEAD:src/game/Makefile.am
+<<<<<<< HEAD:src/game/Makefile.am
+ AccountMgr.cpp \
+ AccountMgr.h \
+ AchievementMgr.h \
+ AchievementMgr.cpp \
+ AddonHandler.cpp \
+ AddonHandler.h \
+ AggressorAI.cpp \
+ AggressorAI.h \
+ AnimalRandomMovementGenerator.h \
+ ArenaTeam.cpp \
+ ArenaTeam.h \
+ ArenaTeamHandler.cpp \
+ AuctionHouseBot.cpp \
+ AuctionHouseBot.h \
+ AuctionHouseHandler.cpp \
+ AuctionHouseMgr.cpp \
+ AuctionHouseMgr.h \
+ Bag.cpp \
+ Bag.h \
+ BattleGround.cpp \
+ BattleGroundAA.cpp \
+ BattleGroundAB.cpp \
+ BattleGroundAV.cpp \
+ BattleGroundBE.cpp \
+ BattleGroundDS.cpp \
+ BattleGroundEY.cpp \
+ BattleGroundNA.cpp \
+ BattleGroundRL.cpp \
+ BattleGroundRV.cpp \
+ BattleGroundSA.cpp \
+ BattleGroundWS.cpp \
+ BattleGround.h \
+ BattleGroundAA.h \
+ BattleGroundAB.h \
+ BattleGroundAV.h \
+ BattleGroundBE.h \
+ BattleGroundDS.h \
+ BattleGroundEY.h \
+ BattleGroundNA.h \
+ BattleGroundRL.h \
+ BattleGroundRV.h \
+ BattleGroundSA.h \
+ BattleGroundWS.h \
+ BattleGroundHandler.cpp \
+ BattleGroundMgr.cpp \
+ BattleGroundMgr.h \
+ Calendar.cpp \
+ Calendar.h \
+ CalendarHandler.cpp \
+ Cell.h \
+ CellImpl.h \
+ Channel.cpp \
+ Channel.h \
+ ChannelHandler.cpp \
+ ChannelMgr.h \
+ CharacterHandler.cpp \
+ Chat.cpp \
+ Chat.h \
+ ChatHandler.cpp \
+ CombatHandler.cpp \
+ ConfusedMovementGenerator.cpp \
+ ConfusedMovementGenerator.h \
+ Corpse.cpp \
+ Corpse.h \
+ CreatureAI.cpp \
+ CreatureAI.h \
+ CreatureAIImpl.h \
+ CreatureAIRegistry.cpp \
+ CreatureAIRegistry.h \
+ CreatureAISelector.cpp \
+ CreatureAISelector.h \
+ CreatureGroups.cpp \
+ CreatureGroups.h \
+ Creature.cpp \
+ Creature.h \
+ debugcmds.cpp \
+ DestinationHolder.cpp \
+ DestinationHolder.h \
+ DestinationHolderImp.h \
+ DuelHandler.cpp \
+ DynamicObject.cpp \
+ DynamicObject.h \
+ FleeingMovementGenerator.cpp \
+ FleeingMovementGenerator.h \
+ Formulas.h \
+ GameEventMgr.cpp \
+ GameEventMgr.h \
+ GameObject.cpp \
+ GameObject.h \
+ GlobalEvents.cpp \
+ GlobalEvents.h \
+ GossipDef.cpp \
+ GossipDef.h \
+ GridDefines.h \
+ GridNotifiers.cpp \
+ GridNotifiers.h \
+ GridNotifiersImpl.h \
+ GridStates.cpp \
+ GridStates.h \
+ Group.cpp \
+ Group.h \
+ GroupHandler.cpp \
+ GuardAI.cpp \
+ GuardAI.h \
+ Guild.cpp \
+ Guild.h \
+ GuildHandler.cpp \
+ HomeMovementGenerator.cpp \
+ HomeMovementGenerator.h \
+ HostilRefManager.cpp \
+ HostilRefManager.h \
+ IdleMovementGenerator.cpp \
+ IdleMovementGenerator.h \
+ InstanceData.cpp \
+ InstanceData.h \
+ InstanceSaveMgr.cpp \
+ InstanceSaveMgr.h \
+ Item.cpp \
+ Item.h \
+ ItemEnchantmentMgr.cpp \
+ ItemEnchantmentMgr.h \
+ ItemHandler.cpp \
+ ItemPrototype.h \
+ Language.h \
+ Level0.cpp \
+ Level1.cpp \
+ Level2.cpp \
+ Level3.cpp \
+ LFGHandler.cpp \
+ LootHandler.cpp \
+ LootMgr.cpp \
+ LootMgr.h \
+ Mail.cpp \
+ Mail.h \
+ Map.cpp \
+ Map.h \
+ MapInstanced.cpp \
+ MapInstanced.h \
+ MapManager.cpp \
+ MapManager.h \
+ MapReference.h \
+ MapRefManager.h \
+ MiscHandler.cpp \
+ MotionMaster.cpp \
+ MotionMaster.h \
+ MovementGenerator.cpp \
+ MovementGenerator.h \
+ MovementGeneratorImpl.h \
+ MovementHandler.cpp \
+ NPCHandler.cpp \
+ NPCHandler.h \
+ NullCreatureAI.cpp \
+ NullCreatureAI.h \
+ ObjectAccessor.cpp \
+ ObjectAccessor.h \
+ Object.cpp \
+ ObjectDefines.h \
+ ObjectGridLoader.cpp \
+ ObjectGridLoader.h \
+ Object.h \
+ ObjectMgr.cpp \
+ ObjectMgr.h \
+ ObjectPosSelector.cpp \
+ ObjectPosSelector.h \
+ Opcodes.cpp \
+ Opcodes.h \
+ OutdoorPvP.cpp \
+ OutdoorPvP.h \
+ OutdoorPvPEP.cpp \
+ OutdoorPvPEP.h \
+ OutdoorPvPHP.cpp \
+ OutdoorPvPHP.h \
+ OutdoorPvPMgr.cpp \
+ OutdoorPvPMgr.h \
+ OutdoorPvPNA.cpp \
+ OutdoorPvPNA.h \
+ OutdoorPvPObjectiveAI.cpp \
+ OutdoorPvPObjectiveAI.h \
+ OutdoorPvPSI.cpp \
+ OutdoorPvPSI.h \
+ OutdoorPvPTF.cpp \
+ OutdoorPvPTF.h \
+ OutdoorPvPZM.cpp \
+ OutdoorPvPZM.h \
+ Path.h \
+ PetAI.cpp \
+ PetAI.h \
+ Pet.cpp \
+ Pet.h \
+ PetHandler.cpp \
+ PetitionsHandler.cpp \
+ Player.cpp \
+ Player.h \
+ PlayerDump.cpp \
+ PlayerDump.h \
+ PossessedAI.cpp \
+ PossessedAI.h \
+ PointMovementGenerator.cpp \
+ PointMovementGenerator.h \
+ PoolHandler.cpp \
+ PoolHandler.h \
+ QueryHandler.cpp \
+ QuestDef.cpp \
+ QuestDef.h \
+ QuestHandler.cpp \
+ RandomMovementGenerator.cpp \
+ RandomMovementGenerator.h \
+ ReactorAI.cpp \
+ ReactorAI.h \
+ ScriptCalls.cpp \
+ ScriptCalls.h \
+ SharedDefines.h \
+ SkillHandler.cpp \
+ SpellAuraDefines.h \
+ SpellAuras.cpp \
+ SpellAuras.h \
+ Spell.cpp \
+ SpellEffects.cpp \
+ Spell.h \
+ SkillDiscovery.cpp \
+ SkillDiscovery.h \
+ SkillExtraItems.cpp \
+ SkillExtraItems.h \
+ SpellHandler.cpp \
+ SocialMgr.cpp \
+ SocialMgr.h \
+ SpellMgr.cpp \
+ SpellMgr.h \
+ StatSystem.cpp \
+ TargetedMovementGenerator.cpp \
+ TargetedMovementGenerator.h \
+ TaxiHandler.cpp \
+ TemporarySummon.cpp \
+ TemporarySummon.h \
+ TotemAI.cpp \
+ TotemAI.h \
+ Totem.cpp \
+ Totem.h \
+ TradeHandler.cpp \
+ Transports.cpp \
+ Transports.h \
+ ThreatManager.cpp \
+ ThreatManager.h \
+ TicketHandler.cpp \
+ TicketMgr.cpp \
+ TicketMgr.h \
+ Traveller.h \
+ Unit.cpp \
+ Unit.h \
+ UnitEvents.h \
+ UpdateData.cpp \
+ UpdateData.h \
+ UpdateFields.h \
+ UpdateMask.h \
+ Vehicle.cpp \
+ Vehicle.h \
+ VoiceChatHandler.cpp \
+ WaypointManager.cpp \
+ WaypointManager.h \
+ WaypointMovementGenerator.cpp \
+ WaypointMovementGenerator.h \
+ Weather.cpp \
+ Weather.h \
+ World.cpp \
+ World.h \
+ WorldLog.cpp \
+ WorldLog.h \
+ WorldSession.cpp \
+ WorldSession.h \
+ WorldSocket.cpp \
+ WorldSocket.h \
+ WorldSocketMgr.cpp \
+ WorldSocketMgr.h \
+ FollowerReference.cpp \
+ FollowerReference.h \
+ FollowerRefManager.h \
+ GroupReference.cpp \
+ GroupReference.h \
+ GroupRefManager.h
+=======
+ AccountMgr.cpp \
+ AccountMgr.h \
+ AchievementMgr.h \
+ AchievementMgr.cpp \
+ AggressorAI.cpp \
+ AggressorAI.h \
+ AnimalRandomMovementGenerator.h \
+ ArenaTeam.cpp \
+ ArenaTeam.h \
+ ArenaTeamHandler.cpp \
+ AuctionHouseHandler.cpp \
+ AuctionHouseMgr.cpp \
+ AuctionHouseMgr.h \
+ Bag.cpp \
+ Bag.h \
+ BattleGround.cpp \
+ BattleGroundAA.cpp \
+ BattleGroundAB.cpp \
+ BattleGroundAV.cpp \
+ BattleGroundBE.cpp \
+ BattleGroundDS.cpp \
+ BattleGroundEY.cpp \
+ BattleGroundNA.cpp \
+ BattleGroundRL.cpp \
+ BattleGroundRV.cpp \
+ BattleGroundSA.cpp \
+ BattleGroundWS.cpp \
+ BattleGround.h \
+ BattleGroundAA.h \
+ BattleGroundAB.h \
+ BattleGroundAV.h \
+ BattleGroundBE.h \
+ BattleGroundDS.h \
+ BattleGroundEY.h \
+ BattleGroundNA.h \
+ BattleGroundRL.h \
+ BattleGroundRV.h \
+ BattleGroundSA.h \
+ BattleGroundWS.h \
+ BattleGroundHandler.cpp \
+ BattleGroundMgr.cpp \
+ BattleGroundMgr.h \
+ Calendar.cpp \
+ Calendar.h \
+ CalendarHandler.cpp \
+ Cell.h \
+ CellImpl.h \
+ Channel.cpp \
+ Channel.h \
+ ChannelHandler.cpp \
+ ChannelMgr.h \
+ CharacterHandler.cpp \
+ Chat.cpp \
+ Chat.h \
+ ChatHandler.cpp \
+ CombatHandler.cpp \
+ ConfusedMovementGenerator.cpp \
+ ConfusedMovementGenerator.h \
+ Corpse.cpp \
+ Corpse.h \
+ CreatureAI.cpp \
+ CreatureAI.h \
+ CreatureAIImpl.h \
+ CreatureAIRegistry.cpp \
+ CreatureAIRegistry.h \
+ CreatureAISelector.cpp \
+ CreatureAISelector.h \
+ Creature.cpp \
+ Creature.h \
+ DBCEnums.h \
+ DBCfmt.h \
+ DBCStores.cpp \
+ DBCStores.h \
+ DBCStructure.h \
+ debugcmds.cpp \
+ DestinationHolder.cpp \
+ DestinationHolder.h \
+ DestinationHolderImp.h \
+ DuelHandler.cpp \
+ DynamicObject.cpp \
+ DynamicObject.h \
+ FleeingMovementGenerator.cpp \
+ FleeingMovementGenerator.h \
+ Formulas.h \
+ GameEventMgr.cpp \
+ GameEventMgr.h \
+ GameObject.cpp \
+ GameObject.h \
+ GlobalEvents.cpp \
+ GlobalEvents.h \
+ GMTicketHandler.cpp \
+ GMTicketMgr.cpp \
+ GMTicketMgr.h \
+ GossipDef.cpp \
+ GossipDef.h \
+ GridDefines.h \
+ GridNotifiers.cpp \
+ GridNotifiers.h \
+ GridNotifiersImpl.h \
+ GridStates.cpp \
+ GridStates.h \
+ Group.cpp \
+ Group.h \
+ GroupHandler.cpp \
+ GuardAI.cpp \
+ GuardAI.h \
+ Guild.cpp \
+ Guild.h \
+ GuildHandler.cpp \
+ HomeMovementGenerator.cpp \
+ HomeMovementGenerator.h \
+ HostilRefManager.cpp \
+ HostilRefManager.h \
+ IdleMovementGenerator.cpp \
+ IdleMovementGenerator.h \
+ InstanceData.cpp \
+ InstanceData.h \
+ InstanceSaveMgr.cpp \
+ InstanceSaveMgr.h \
+ Item.cpp \
+ Item.h \
+ ItemEnchantmentMgr.cpp \
+ ItemEnchantmentMgr.h \
+ ItemHandler.cpp \
+ ItemPrototype.h \
+ Language.h \
+ Level0.cpp \
+ Level1.cpp \
+ Level2.cpp \
+ Level3.cpp \
+ LFGHandler.cpp \
+ LootHandler.cpp \
+ LootMgr.cpp \
+ LootMgr.h \
+ Mail.cpp \
+ Mail.h \
+ Map.cpp \
+ Map.h \
+ MapInstanced.cpp \
+ MapInstanced.h \
+ MapManager.cpp \
+ MapManager.h \
+ MapReference.h \
+ MapRefManager.h \
+ MiscHandler.cpp \
+ MotionMaster.cpp \
+ MotionMaster.h \
+ MovementGenerator.cpp \
+ MovementGenerator.h \
+ MovementGeneratorImpl.h \
+ MovementHandler.cpp \
+ NPCHandler.cpp \
+ NPCHandler.h \
+ NullCreatureAI.cpp \
+ NullCreatureAI.h \
+ ObjectAccessor.cpp \
+ ObjectAccessor.h \
+ Object.cpp \
+ ObjectDefines.h \
+ ObjectGridLoader.cpp \
+ ObjectGridLoader.h \
+ Object.h \
+ ObjectMgr.cpp \
+ ObjectMgr.h \
+ ObjectPosSelector.cpp \
+ ObjectPosSelector.h \
+ Opcodes.cpp \
+ Opcodes.h \
+ Path.h \
+ PetAI.cpp \
+ PetAI.h \
+ Pet.cpp \
+ Pet.h \
+ PetHandler.cpp \
+ PetitionsHandler.cpp \
+ Player.cpp \
+ Player.h \
+ PlayerDump.cpp \
+ PlayerDump.h \
+ PointMovementGenerator.cpp \
+ PointMovementGenerator.h \
+ PoolHandler.cpp \
+ PoolHandler.h \
+ QueryHandler.cpp \
+ QuestDef.cpp \
+ QuestDef.h \
+ QuestHandler.cpp \
+ RandomMovementGenerator.cpp \
+ RandomMovementGenerator.h \
+ ReactorAI.cpp \
+ ReactorAI.h \
+ ReputationMgr.cpp \
+ ReputationMgr.h \
+ ScriptCalls.cpp \
+ ScriptCalls.h \
+ SharedDefines.h \
+ SkillHandler.cpp \
+ SpellAuraDefines.h \
+ SpellAuras.cpp \
+ SpellAuras.h \
+ Spell.cpp \
+ SpellEffects.cpp \
+ Spell.h \
+ SkillDiscovery.cpp \
+ SkillDiscovery.h \
+ SkillExtraItems.cpp \
+ SkillExtraItems.h \
+ SpellHandler.cpp \
+ SocialMgr.cpp \
+ SocialMgr.h \
+ SpellMgr.cpp \
+ SpellMgr.h \
+ StatSystem.cpp \
+ TargetedMovementGenerator.cpp \
+ TargetedMovementGenerator.h \
+ TaxiHandler.cpp \
+ TemporarySummon.cpp \
+ TemporarySummon.h \
+ TotemAI.cpp \
+ TotemAI.h \
+ Totem.cpp \
+ Totem.h \
+ TradeHandler.cpp \
+ Transports.cpp \
+ Transports.h \
+ ThreatManager.cpp \
+ ThreatManager.h \
+ Traveller.h \
+ Unit.cpp \
+ Unit.h \
+ UnitEvents.h \
+ UpdateData.cpp \
+ UpdateData.h \
+ UpdateFields.h \
+ UpdateMask.h \
+ Vehicle.cpp \
+ Vehicle.h \
+ VoiceChatHandler.cpp \
+ WaypointManager.cpp \
+ WaypointManager.h \
+ WaypointMovementGenerator.cpp \
+ WaypointMovementGenerator.h \
+ Weather.cpp \
+ Weather.h \
+ World.cpp \
+ World.h \
+ WorldLog.cpp \
+ WorldLog.h \
+ WorldSession.cpp \
+ WorldSession.h \
+ WorldSocket.cpp \
+ WorldSocket.h \
+ WorldSocketMgr.cpp \
+ WorldSocketMgr.h \
+ FollowerReference.cpp \
+ FollowerReference.h \
+ FollowerRefManager.h \
+ GroupReference.cpp \
+ GroupReference.h \
+ GroupRefManager.h
+>>>>>>> 2429aaf2276d689e101ed88285f18449dbe4280d:src/game/Makefile.am
+=======
+ AccountMgr.cpp \
+ AccountMgr.h \
+ AchievementMgr.h \
+ AchievementMgr.cpp \
+ AggressorAI.cpp \
+ AggressorAI.h \
+ AnimalRandomMovementGenerator.h \
+ ArenaTeam.cpp \
+ ArenaTeam.h \
+ ArenaTeamHandler.cpp \
+ AuctionHouseHandler.cpp \
+ AuctionHouseMgr.cpp \
+ AuctionHouseMgr.h \
+ Bag.cpp \
+ Bag.h \
+ BattleGround.cpp \
+ BattleGroundAA.cpp \
+ BattleGroundAB.cpp \
+ BattleGroundAV.cpp \
+ BattleGroundBE.cpp \
+ BattleGroundDS.cpp \
+ BattleGroundEY.cpp \
+ BattleGroundNA.cpp \
+ BattleGroundRL.cpp \
+ BattleGroundRV.cpp \
+ BattleGroundSA.cpp \
+ BattleGroundWS.cpp \
+ BattleGround.h \
+ BattleGroundAA.h \
+ BattleGroundAB.h \
+ BattleGroundAV.h \
+ BattleGroundBE.h \
+ BattleGroundDS.h \
+ BattleGroundEY.h \
+ BattleGroundNA.h \
+ BattleGroundRL.h \
+ BattleGroundRV.h \
+ BattleGroundSA.h \
+ BattleGroundWS.h \
+ BattleGroundHandler.cpp \
+ BattleGroundMgr.cpp \
+ BattleGroundMgr.h \
+ Calendar.cpp \
+ Calendar.h \
+ CalendarHandler.cpp \
+ Cell.h \
+ CellImpl.h \
+ Channel.cpp \
+ Channel.h \
+ ChannelHandler.cpp \
+ ChannelMgr.h \
+ CharacterHandler.cpp \
+ Chat.cpp \
+ Chat.h \
+ ChatHandler.cpp \
+ CombatHandler.cpp \
+ ConfusedMovementGenerator.cpp \
+ ConfusedMovementGenerator.h \
+ Corpse.cpp \
+ Corpse.h \
+ CreatureAI.cpp \
+ CreatureAI.h \
+ CreatureAIImpl.h \
+ CreatureAIRegistry.cpp \
+ CreatureAIRegistry.h \
+ CreatureAISelector.cpp \
+ CreatureAISelector.h \
+ CreatureEventAI.cpp \
+ CreatureEventAI.h \
+ CreatureEventAIMgr.cpp \
+ CreatureEventAIMgr.h \
+ Creature.cpp \
+ Creature.h \
+ DBCEnums.h \
+ DBCfmt.h \
+ DBCStores.cpp \
+ DBCStores.h \
+ DBCStructure.h \
+ debugcmds.cpp \
+ DestinationHolder.cpp \
+ DestinationHolder.h \
+ DestinationHolderImp.h \
+ DuelHandler.cpp \
+ DynamicObject.cpp \
+ DynamicObject.h \
+ FleeingMovementGenerator.cpp \
+ FleeingMovementGenerator.h \
+ Formulas.h \
+ GameEventMgr.cpp \
+ GameEventMgr.h \
+ GameObject.cpp \
+ GameObject.h \
+ GlobalEvents.cpp \
+ GlobalEvents.h \
+ GMTicketHandler.cpp \
+ GMTicketMgr.cpp \
+ GMTicketMgr.h \
+ GossipDef.cpp \
+ GossipDef.h \
+ GridDefines.h \
+ GridNotifiers.cpp \
+ GridNotifiers.h \
+ GridNotifiersImpl.h \
+ GridStates.cpp \
+ GridStates.h \
+ Group.cpp \
+ Group.h \
+ GroupHandler.cpp \
+ GuardAI.cpp \
+ GuardAI.h \
+ Guild.cpp \
+ Guild.h \
+ GuildHandler.cpp \
+ HomeMovementGenerator.cpp \
+ HomeMovementGenerator.h \
+ HostilRefManager.cpp \
+ HostilRefManager.h \
+ IdleMovementGenerator.cpp \
+ IdleMovementGenerator.h \
+ InstanceData.cpp \
+ InstanceData.h \
+ InstanceSaveMgr.cpp \
+ InstanceSaveMgr.h \
+ Item.cpp \
+ Item.h \
+ ItemEnchantmentMgr.cpp \
+ ItemEnchantmentMgr.h \
+ ItemHandler.cpp \
+ ItemPrototype.h \
+ Language.h \
+ Level0.cpp \
+ Level1.cpp \
+ Level2.cpp \
+ Level3.cpp \
+ LFGHandler.cpp \
+ LootHandler.cpp \
+ LootMgr.cpp \
+ LootMgr.h \
+ Mail.cpp \
+ Mail.h \
+ Map.cpp \
+ Map.h \
+ MapInstanced.cpp \
+ MapInstanced.h \
+ MapManager.cpp \
+ MapManager.h \
+ MapReference.h \
+ MapRefManager.h \
+ MiscHandler.cpp \
+ MotionMaster.cpp \
+ MotionMaster.h \
+ MovementGenerator.cpp \
+ MovementGenerator.h \
+ MovementGeneratorImpl.h \
+ MovementHandler.cpp \
+ NPCHandler.cpp \
+ NPCHandler.h \
+ NullCreatureAI.cpp \
+ NullCreatureAI.h \
+ ObjectAccessor.cpp \
+ ObjectAccessor.h \
+ Object.cpp \
+ ObjectDefines.h \
+ ObjectGridLoader.cpp \
+ ObjectGridLoader.h \
+ Object.h \
+ ObjectMgr.cpp \
+ ObjectMgr.h \
+ ObjectPosSelector.cpp \
+ ObjectPosSelector.h \
+ Opcodes.cpp \
+ Opcodes.h \
+ Path.h \
+ PetAI.cpp \
+ PetAI.h \
+ Pet.cpp \
+ Pet.h \
+ PetHandler.cpp \
+ PetitionsHandler.cpp \
+ Player.cpp \
+ Player.h \
+ PlayerDump.cpp \
+ PlayerDump.h \
+ PointMovementGenerator.cpp \
+ PointMovementGenerator.h \
+ PoolHandler.cpp \
+ PoolHandler.h \
+ QueryHandler.cpp \
+ QuestDef.cpp \
+ QuestDef.h \
+ QuestHandler.cpp \
+ RandomMovementGenerator.cpp \
+ RandomMovementGenerator.h \
+ ReactorAI.cpp \
+ ReactorAI.h \
+ ReputationMgr.cpp \
+ ReputationMgr.h \
+ ScriptCalls.cpp \
+ ScriptCalls.h \
+ SharedDefines.h \
+ SkillHandler.cpp \
+ SpellAuraDefines.h \
+ SpellAuras.cpp \
+ SpellAuras.h \
+ Spell.cpp \
+ SpellEffects.cpp \
+ Spell.h \
+ SkillDiscovery.cpp \
+ SkillDiscovery.h \
+ SkillExtraItems.cpp \
+ SkillExtraItems.h \
+ SpellHandler.cpp \
+ SocialMgr.cpp \
+ SocialMgr.h \
+ SpellMgr.cpp \
+ SpellMgr.h \
+ StatSystem.cpp \
+ TargetedMovementGenerator.cpp \
+ TargetedMovementGenerator.h \
+ TaxiHandler.cpp \
+ TemporarySummon.cpp \
+ TemporarySummon.h \
+ TotemAI.cpp \
+ TotemAI.h \
+ Totem.cpp \
+ Totem.h \
+ TradeHandler.cpp \
+ Transports.cpp \
+ Transports.h \
+ ThreatManager.cpp \
+ ThreatManager.h \
+ Traveller.h \
+ Unit.cpp \
+ Unit.h \
+ UnitEvents.h \
+ UpdateData.cpp \
+ UpdateData.h \
+ UpdateFields.h \
+ UpdateMask.h \
+ Vehicle.cpp \
+ Vehicle.h \
+ VoiceChatHandler.cpp \
+ WaypointManager.cpp \
+ WaypointManager.h \
+ WaypointMovementGenerator.cpp \
+ WaypointMovementGenerator.h \
+ Weather.cpp \
+ Weather.h \
+ World.cpp \
+ World.h \
+ WorldLog.cpp \
+ WorldLog.h \
+ WorldSession.cpp \
+ WorldSession.h \
+ WorldSocket.cpp \
+ WorldSocket.h \
+ WorldSocketMgr.cpp \
+ WorldSocketMgr.h \
+ FollowerReference.cpp \
+ FollowerReference.h \
+ FollowerRefManager.h \
+ GroupReference.cpp \
+ GroupReference.h \
+ GroupRefManager.h
+>>>>>>> 5a6594330caefc0dc00a5fe792dcb0e344b457cb:src/game/Makefile.am
+
+## Link against shared library
+libmangosgame_a_LIBADD = ../shared/libmangosshared.a ../shared/Auth/libmangosauth.a ../shared/Config/libmangosconfig.a ../shared/Database/libmangosdatabase.a ../shared/vmap/libmangosvmaps.a
+
+## Additional files to include when running 'make dist'
+# Precompiled Headers for WIN
+EXTRA_DIST = \
+ pchdef.cpp \
+ pchdef.h \ No newline at end of file
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 4ed7593d725..140904bfb19 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -21,7 +21,6 @@
#include "MapManager.h"
#include "Player.h"
#include "GridNotifiers.h"
-#include "WorldSession.h"
#include "Log.h"
#include "GridStates.h"
#include "CellImpl.h"
@@ -36,6 +35,7 @@
#include "ScriptCalls.h"
#include "Group.h"
#include "MapRefManager.h"
+#include "Vehicle.h"
#include "MapInstanced.h"
#include "InstanceSaveMgr.h"
@@ -44,9 +44,6 @@
#define DEFAULT_GRID_EXPIRY 300
#define MAX_GRID_LOAD_TIME 50
-// magic *.map header
-const char MAP_MAGIC[] = "MAP_2.50";
-
GridState* si_GridStates[MAX_GRID_STATE];
Map::~Map()
@@ -54,11 +51,11 @@ Map::~Map()
UnloadAll();
}
-bool Map::ExistMap(uint32 mapid,int x,int y)
+bool Map::ExistMap(uint32 mapid,int gx,int gy)
{
int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1;
char* tmp = new char[len];
- snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,x,y);
+ snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,gx,gy);
FILE *pf=fopen(tmp,"rb");
@@ -69,9 +66,10 @@ bool Map::ExistMap(uint32 mapid,int x,int y)
return false;
}
- char magic[8];
- fread(magic,1,8,pf);
- if(strncmp(MAP_MAGIC,magic,8))
+ map_fileheader header;
+ fread(&header, sizeof(header), 1, pf);
+ if (header.mapMagic != uint32(MAP_MAGIC) ||
+ header.versionMagic != uint32(MAP_VERSION_MAGIC))
{
sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp);
delete [] tmp;
@@ -84,17 +82,17 @@ bool Map::ExistMap(uint32 mapid,int x,int y)
return true;
}
-bool Map::ExistVMap(uint32 mapid,int x,int y)
+bool Map::ExistVMap(uint32 mapid,int gx,int gy)
{
if(VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager())
{
if(vmgr->isMapLoadingEnabled())
{
// x and y are swapped !! => fixed now
- bool exists = vmgr->existsMap((sWorld.GetDataPath()+ "vmaps").c_str(), mapid, x,y);
+ bool exists = vmgr->existsMap((sWorld.GetDataPath()+ "vmaps").c_str(), mapid, gx,gy);
if(!exists)
{
- std::string name = vmgr->getDirFileName(mapid,x,y);
+ std::string name = vmgr->getDirFileName(mapid,gx,gy);
sLog.outError("VMap file '%s' is missing or point to wrong version vmap file, redo vmaps with latest vmap_assembler.exe program", (sWorld.GetDataPath()+"vmaps/"+name).c_str());
return false;
}
@@ -104,91 +102,73 @@ bool Map::ExistVMap(uint32 mapid,int x,int y)
return true;
}
-void Map::LoadVMap(int x,int y)
+void Map::LoadVMap(int gx,int gy)
{
// x and y are swapped !!
- int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath()+ "vmaps").c_str(), GetId(), x,y);
+ int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath()+ "vmaps").c_str(), GetId(), gx,gy);
switch(vmapLoadResult)
{
case VMAP::VMAP_LOAD_RESULT_OK:
- sLog.outDetail("VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), x,y, x,y);
+ sLog.outDetail("VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy);
break;
case VMAP::VMAP_LOAD_RESULT_ERROR:
- sLog.outDetail("Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), x,y, x,y);
+ sLog.outDetail("Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy);
break;
case VMAP::VMAP_LOAD_RESULT_IGNORED:
- DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), x,y, x,y);
+ DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy);
break;
}
}
-void Map::LoadMap(uint32 mapid, uint32 instanceid, int x,int y)
+void Map::LoadMap(int gx,int gy, bool reload)
{
- if( instanceid != 0 )
+ if( i_InstanceId != 0 )
{
- if(GridMaps[x][y])
+ if(GridMaps[gx][gy])
return;
- Map* baseMap = const_cast<Map*>(MapManager::Instance().GetBaseMap(mapid));
-
- // load gridmap for base map
- if (!baseMap->GridMaps[x][y])
- baseMap->EnsureGridCreated(GridPair(63-x,63-y));
+ Map* baseMap = const_cast<Map*>(MapManager::Instance().GetBaseMap(i_id));
-//+++ if (!baseMap->GridMaps[x][y]) don't check for GridMaps[gx][gy], we need the management for vmaps
-// return;
+ // load grid map for base map
+ if (!baseMap->GridMaps[gx][gy])
+ baseMap->EnsureGridCreated(GridPair(63-gx,63-gy));
- ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(x,y));
- GridMaps[x][y] = baseMap->GridMaps[x][y];
+ ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(gx,gy));
+ GridMaps[gx][gy] = baseMap->GridMaps[gx][gy];
return;
}
+ if(GridMaps[gx][gy] && !reload)
+ return;
+
//map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?)
- if(GridMaps[x][y])
+ if(GridMaps[gx][gy])
{
- sLog.outDetail("Unloading already loaded map %u before reloading.",mapid);
- delete (GridMaps[x][y]);
- GridMaps[x][y]=NULL;
+ sLog.outDetail("Unloading already loaded map %u before reloading.",i_id);
+ delete (GridMaps[gx][gy]);
+ GridMaps[gx][gy]=NULL;
}
// map file name
char *tmp=NULL;
- // Pihhan: dataPath length + "maps/" + 3+2+2+ ".map" length may be > 32 !
int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1;
tmp = new char[len];
- snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,x,y);
+ snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),i_id,gx,gy);
sLog.outDetail("Loading map %s",tmp);
// loading data
- FILE *pf=fopen(tmp,"rb");
- if(!pf)
+ GridMaps[gx][gy] = new GridMap();
+ if (!GridMaps[gx][gy]->loadData(tmp))
{
- delete [] tmp;
- return;
- }
-
- char magic[8];
- fread(magic,1,8,pf);
- if(strncmp(MAP_MAGIC,magic,8))
- {
- sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp);
- delete [] tmp;
- fclose(pf); //close file before return
- return;
+ sLog.outError("Error load map file: \n %s\n", tmp);
}
- delete [] tmp;
-
- GridMap * buf= new GridMap;
- fread(buf,1,sizeof(GridMap),pf);
- fclose(pf);
-
- GridMaps[x][y] = buf;
+ delete [] tmp;
}
-void Map::LoadMapAndVMap(uint32 mapid, uint32 instanceid, int x,int y)
+void Map::LoadMapAndVMap(int gx,int gy)
{
- LoadMap(mapid,instanceid,x,y);
- if(instanceid == 0)
- LoadVMap(x, y); // Only load the data for the base map
+ LoadMap(gx,gy);
+ if(i_InstanceId == 0)
+ LoadVMap(gx, gy); // Only load the data for the base map
}
void Map::InitStateMachine()
@@ -208,9 +188,10 @@ void Map::DeleteStateMachine()
}
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
- : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
- i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), i_gridExpiry(expiry),
- m_activeNonPlayersIter(m_activeNonPlayers.end())
+ : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
+ i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0),
+ m_activeNonPlayersIter(m_activeNonPlayers.end()),
+ i_gridExpiry(expiry)
, i_lock(true)
{
for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx)
@@ -256,7 +237,7 @@ template<>
void Map::AddToGrid(Creature* obj, NGridType *grid, Cell const& cell)
{
// add to world object registry in grid
- if(obj->isPet() || obj->IsTempWorldObject)
+ if(obj->isWorldCreature() || obj->IsTempWorldObject)
{
(*grid)(cell.CellX(), cell.CellY()).AddWorldObject<Creature>(obj, obj->GetGUID());
}
@@ -308,7 +289,7 @@ template<>
void Map::RemoveFromGrid(Creature* obj, NGridType *grid, Cell const& cell)
{
// remove from world object registry in grid
- if(obj->isPet() || obj->IsTempWorldObject)
+ if(obj->isWorldCreature() || obj->IsTempWorldObject)
{
(*grid)(cell.CellX(), cell.CellY()).RemoveWorldObject<Creature>(obj, obj->GetGUID());
}
@@ -410,7 +391,7 @@ Map::EnsureGridCreated(const GridPair &p)
Guard guard(*this);
if(!getNGrid(p.x_coord, p.y_coord))
{
- sLog.outDebug("Loading grid[%u,%u] for map %u", p.x_coord, p.y_coord, i_id);
+ sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, i_id, i_InstanceId);
setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)),
p.x_coord, p.y_coord);
@@ -425,20 +406,20 @@ Map::EnsureGridCreated(const GridPair &p)
int gy=63-p.y_coord;
if(!GridMaps[gx][gy])
- Map::LoadMapAndVMap(i_id,i_InstanceId,gx,gy);
+ LoadMapAndVMap(gx,gy);
}
}
}
void
-Map::EnsureGridLoaded(const Cell &cell, Player *player)
+Map::EnsureGridLoadedAtEnter(const Cell &cell, Player *player)
{
- EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
- NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
+ NGridType *grid;
- assert(grid != NULL);
- if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY()))
+ if(EnsureGridLoaded(cell))
{
+ grid = getNGrid(cell.GridX(), cell.GridY());
+
if (player)
{
player->SendDelayResponse(MAX_GRID_LOAD_TIME);
@@ -449,19 +430,37 @@ Map::EnsureGridLoaded(const Cell &cell, Player *player)
DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id);
}
+ ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f);
+ grid->SetGridState(GRID_STATE_ACTIVE);
+ }
+ else
+ grid = getNGrid(cell.GridX(), cell.GridY());
+
+ if (player)
+ AddToGrid(player,grid,cell);
+}
+
+bool Map::EnsureGridLoaded(const Cell &cell)
+{
+ EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
+ NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
+
+ assert(grid != NULL);
+ if( !isGridObjectDataLoaded(cell.GridX(), cell.GridY()) )
+ {
+ sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), i_id, i_InstanceId);
+
ObjectGridLoader loader(*grid, this, cell);
loader.LoadN();
- setGridObjectDataLoaded(true, cell.GridX(), cell.GridY());
// Add resurrectable corpses to world object list in grid
ObjectAccessor::Instance().AddCorpsesToGrid(GridPair(cell.GridX(),cell.GridY()),(*grid)(cell.CellX(), cell.CellY()), this);
- ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f);
- grid->SetGridState(GRID_STATE_ACTIVE);
+ setGridObjectDataLoaded(true,cell.GridX(), cell.GridY());
+ return true;
}
-
- if(player)
- AddToGrid(player,grid,cell);
+
+ return false;
}
void Map::LoadGrid(float x, float y)
@@ -480,7 +479,7 @@ bool Map::Add(Player *player)
// update player state for other player and visa-versa
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
Cell cell(p);
- EnsureGridLoaded(cell, player);
+ EnsureGridLoadedAtEnter(cell, player);
player->AddToWorld();
SendInitSelf(player);
@@ -508,7 +507,7 @@ Map::Add(T *obj)
Cell cell(p);
if(obj->isActiveObject())
- EnsureGridLoaded(cell);
+ EnsureGridLoadedAtEnter(cell);
else
EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
@@ -517,105 +516,42 @@ Map::Add(T *obj)
AddToGrid(obj,grid,cell);
obj->AddToWorld();
-
+
if(obj->isActiveObject())
AddToActive(obj);
DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY());
- UpdateObjectVisibility(obj,cell,p);
+ //something, such as vehicle, needs to be update immediately
+ //also, trigger needs to cast spell, if not update, cannot see visual
+ //if(obj->GetTypeId() != TYPEID_UNIT)
+ UpdateObjectVisibility(obj,cell,p);
- //AddNotifier(obj);
+ AddNotifier(obj);
}
void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self, bool to_possessor)
{
- CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
-
- if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP )
- {
- sLog.outError("Map::MessageBroadcast: Player (GUID: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord);
- return;
- }
-
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
-
- if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
- return;
-
Trinity::MessageDeliverer post_man(*player, msg, to_possessor, to_self);
- TypeContainerVisitor<Trinity::MessageDeliverer, WorldTypeMapContainer > message(post_man);
- CellLock<ReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, message, *this);
+ VisitWorld(player->GetPositionX(), player->GetPositionY(), World::GetMaxVisibleDistance(), post_man);
}
void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg, bool to_possessor)
{
- CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
-
- if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP )
- {
- sLog.outError("Map::MessageBroadcast: Object " I64FMTD " have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord);
- return;
- }
-
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
- cell.SetNoCreate();
-
- if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
- return;
-
Trinity::ObjectMessageDeliverer post_man(*obj, msg, to_possessor);
- TypeContainerVisitor<Trinity::ObjectMessageDeliverer, WorldTypeMapContainer > message(post_man);
- CellLock<ReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, message, *this);
+ VisitWorld(obj->GetPositionX(), obj->GetPositionY(), World::GetMaxVisibleDistance(), post_man);
}
void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, bool to_self, bool to_possessor, bool own_team_only)
{
- CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
-
- if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP )
- {
- sLog.outError("Map::MessageBroadcast: Player (GUID: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord);
- return;
- }
-
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
-
- if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
- return;
-
Trinity::MessageDistDeliverer post_man(*player, msg, to_possessor, dist, to_self, own_team_only);
- TypeContainerVisitor<Trinity::MessageDistDeliverer , WorldTypeMapContainer > message(post_man);
- CellLock<ReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, message, *this);
+ VisitWorld(player->GetPositionX(), player->GetPositionY(), World::GetMaxVisibleDistance(), post_man);
}
void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist, bool to_possessor)
{
- CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
-
- if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP )
- {
- sLog.outError("Map::MessageBroadcast: Object " I64FMTD " have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord);
- return;
- }
-
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
- cell.SetNoCreate();
-
- if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
- return;
-
Trinity::ObjectMessageDistDeliverer post_man(*obj, msg, to_possessor, dist);
- TypeContainerVisitor<Trinity::ObjectMessageDistDeliverer, WorldTypeMapContainer > message(post_man);
- CellLock<ReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, message, *this);
+ VisitWorld(obj->GetPositionX(), obj->GetPositionY(), World::GetMaxVisibleDistance(), post_man);
}
bool Map::loaded(const GridPair &p) const
@@ -740,6 +676,13 @@ void Map::Update(const uint32 &t_diff)
}
}
}
+
+ if(plr->m_seer != plr && !plr->hasUnitState(UNIT_STAT_ONVEHICLE))
+ {
+ Trinity::PlayerVisibilityNotifier notifier(*plr);
+ VisitAll(plr->m_seer->GetPositionX(), plr->m_seer->GetPositionY(), World::GetMaxVisibleDistance(), notifier);
+ notifier.Notify();
+ }
}
// non-player active objects
@@ -757,33 +700,6 @@ void Map::Update(const uint32 &t_diff)
if(!obj->IsInWorld())
continue;
- // Update bindsight players
- /*if(obj->isType(TYPEMASK_UNIT))
- {
- if(!((Unit*)obj)->GetSharedVisionList().empty())
- for(SharedVisionList::const_iterator itr = ((Unit*)obj)->GetSharedVisionList().begin(); itr != ((Unit*)obj)->GetSharedVisionList().end(); ++itr)
- {
- if(!*itr)
- {
- sLog.outError("unit %u has invalid shared vision player, list size %u", obj->GetEntry(), ((Unit*)obj)->GetSharedVisionList().size());
- continue;
- }
- Trinity::PlayerVisibilityNotifier notifier(**itr);
- VisitAll(obj->GetPositionX(), obj->GetPositionY(), World::GetMaxVisibleDistance(), notifier);
- notifier.Notify();
- }
- }
- else */if(obj->GetTypeId() == TYPEID_DYNAMICOBJECT)
- {
- if(Unit *caster = ((DynamicObject*)obj)->GetCaster())
- if(caster->GetTypeId() == TYPEID_PLAYER && caster->GetUInt64Value(PLAYER_FARSIGHT) == obj->GetGUID())
- {
- Trinity::PlayerVisibilityNotifier notifier(*((Player*)caster));
- VisitAll(obj->GetPositionX(), obj->GetPositionY(), World::GetMaxVisibleDistance(), notifier);
- notifier.Notify();
- }
- }
-
CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
// Check for correctness of standing_cell, it also avoids problems with update_cell
@@ -960,7 +876,7 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
if( !old_cell.DiffGrid(new_cell) )
AddToGrid(player, oldGrid,new_cell);
else
- EnsureGridLoaded(new_cell, player);
+ EnsureGridLoadedAtEnter(new_cell, player);
}
AddUnitToNotify(player);
@@ -998,6 +914,27 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
creature->Relocate(x, y, z, ang);
AddUnitToNotify(creature);
}
+
+ if(creature->isVehicle())
+ {
+ for(SeatMap::iterator itr = ((Vehicle*)creature)->m_Seats.begin(); itr != ((Vehicle*)creature)->m_Seats.end(); ++itr)
+ if(Unit *passenger = itr->second.passenger)
+ {
+ if(passenger->GetTypeId() == TYPEID_PLAYER)
+ PlayerRelocation((Player*)passenger,
+ x + passenger->m_movementInfo.t_x,
+ y + passenger->m_movementInfo.t_y,
+ z + passenger->m_movementInfo.t_z,
+ ang + passenger->m_movementInfo.t_o);
+ else
+ CreatureRelocation((Creature*)passenger,
+ x + passenger->m_movementInfo.t_x,
+ y + passenger->m_movementInfo.t_y,
+ z + passenger->m_movementInfo.t_z,
+ ang + passenger->m_movementInfo.t_o);
+ }
+ }
+
assert(CheckGridIntegrity(creature,true));
}
@@ -1079,7 +1016,7 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell)
// in diff. grids but active creature
if(c->isActiveObject())
{
- EnsureGridLoaded(new_cell);
+ EnsureGridLoadedAtEnter(new_cell);
#ifdef TRINITY_DEBUG
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
@@ -1190,7 +1127,11 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll)
{
if (i_InstanceId == 0)
{
- if(GridMaps[gx][gy]) delete (GridMaps[gx][gy]);
+ if(GridMaps[gx][gy])
+ {
+ GridMaps[gx][gy]->unloadData();
+ delete GridMaps[gx][gy];
+ }
// x and y are swapped
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gy, gx);
}
@@ -1215,103 +1156,529 @@ void Map::UnloadAll()
}
}
-float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const
+//*****************************
+// Grid function
+//*****************************
+GridMap::GridMap()
{
- GridPair p = Trinity::ComputeGridPair(x, y);
+ m_flags = 0;
+ // Area data
+ m_gridArea = 0;
+ m_area_map = NULL;
+ // Height level data
+ m_gridHeight = INVALID_HEIGHT;
+ m_gridGetHeight = &GridMap::getHeightFromFlat;
+ m_V9 = NULL;
+ m_V8 = NULL;
+ // Liquid data
+ m_liquidType = 0;
+ m_liquid_offX = 0;
+ m_liquid_offY = 0;
+ m_liquid_width = 0;
+ m_liquid_height = 0;
+ m_liquidLevel = INVALID_HEIGHT;
+ m_liquid_type = NULL;
+ m_liquid_map = NULL;
+}
- // half opt method
- int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x
- int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
+GridMap::~GridMap()
+{
+ unloadData();
+}
- float lx=128*(32 -x/SIZE_OF_GRIDS - gx);
- float ly=128*(32 -y/SIZE_OF_GRIDS - gy);
+bool GridMap::loadData(char *filename)
+{
+ // Unload old data if exist
+ unloadData();
- // ensure GridMap is loaded
- const_cast<Map*>(this)->EnsureGridCreated(GridPair(63-gx,63-gy));
+ map_fileheader header;
+ // Not return error if file not found
+ FILE *in = fopen(filename, "rb");
+ if (!in)
+ return true;
+ fread(&header, sizeof(header),1,in);
+ if (header.mapMagic == uint32(MAP_MAGIC) &&
+ header.versionMagic == uint32(MAP_VERSION_MAGIC))
+ {
+ // loadup area data
+ if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize))
+ {
+ sLog.outError("Error loading map area data\n");
+ fclose(in);
+ return false;
+ }
+ // loadup height data
+ if (header.heightMapOffset && !loadHeihgtData(in, header.heightMapOffset, header.heightMapSize))
+ {
+ sLog.outError("Error loading map height data\n");
+ fclose(in);
+ return false;
+ }
+ // loadup liquid data
+ if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize))
+ {
+ sLog.outError("Error loading map liquids data\n");
+ fclose(in);
+ return false;
+ }
+ fclose(in);
+ return true;
+ }
+ sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.", filename);
+ fclose(in);
+ return false;
+}
- // find raw .map surface under Z coordinates
- float mapHeight;
- if(GridMap* gmap = GridMaps[gx][gy])
+void GridMap::unloadData()
+{
+ if (m_area_map) delete[] m_area_map;
+ if (m_V9) delete[] m_V9;
+ if (m_V8) delete[] m_V8;
+ if (m_liquid_type) delete[] m_liquid_type;
+ if (m_liquid_map) delete[] m_liquid_map;
+ m_area_map = NULL;
+ m_V9 = NULL;
+ m_V8 = NULL;
+ m_liquid_type = NULL;
+ m_liquid_map = NULL;
+ m_gridGetHeight = &GridMap::getHeightFromFlat;
+}
+
+bool GridMap::loadAreaData(FILE *in, uint32 offset, uint32 size)
+{
+ map_areaHeader header;
+ fseek(in, offset, SEEK_SET);
+ fread(&header, sizeof(header), 1, in);
+ if (header.fourcc != uint32(MAP_AREA_MAGIC))
+ return false;
+
+ m_gridArea = header.gridArea;
+ if (!(header.flags & MAP_AREA_NO_AREA))
+ {
+ m_area_map = new uint16 [16*16];
+ fread(m_area_map, sizeof(uint16), 16*16, in);
+ }
+ return true;
+}
+
+bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size)
+{
+ map_heightHeader header;
+ fseek(in, offset, SEEK_SET);
+ fread(&header, sizeof(header), 1, in);
+ if (header.fourcc != uint32(MAP_HEIGTH_MAGIC))
+ return false;
+
+ m_gridHeight = header.gridHeight;
+ if (!(header.flags & MAP_HEIGHT_NO_HIGHT))
{
- int lx_int = (int)lx;
- int ly_int = (int)ly;
+ if ((header.flags & MAP_HEIGHT_AS_INT16))
+ {
+ m_uint16_V9 = new uint16 [129*129];
+ m_uint16_V8 = new uint16 [128*128];
+ fread(m_uint16_V9, sizeof(uint16), 129*129, in);
+ fread(m_uint16_V8, sizeof(uint16), 128*128, in);
+ m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535;
+ m_gridGetHeight = &GridMap::getHeightFromUint16;
+ }
+ else if ((header.flags & MAP_HEIGHT_AS_INT8))
+ {
+ m_uint8_V9 = new uint8 [129*129];
+ m_uint8_V8 = new uint8 [128*128];
+ fread(m_uint8_V9, sizeof(uint8), 129*129, in);
+ fread(m_uint8_V8, sizeof(uint8), 128*128, in);
+ m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255;
+ m_gridGetHeight = &GridMap::getHeightFromUint8;
+ }
+ else
+ {
+ m_V9 = new float [129*129];
+ m_V8 = new float [128*128];
+ fread(m_V9, sizeof(float), 129*129, in);
+ fread(m_V8, sizeof(float), 128*128, in);
+ m_gridGetHeight = &GridMap::getHeightFromFloat;
+ }
+ }
+ else
+ m_gridGetHeight = &GridMap::getHeightFromFlat;
+ return true;
+}
+
+bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 size)
+{
+ map_liquidHeader header;
+ fseek(in, offset, SEEK_SET);
+ fread(&header, sizeof(header), 1, in);
+ if (header.fourcc != uint32(MAP_LIQUID_MAGIC))
+ return false;
+
+ m_liquidType = header.liquidType;
+ m_liquid_offX = header.offsetX;
+ m_liquid_offY = header.offsetY;
+ m_liquid_width = header.width;
+ m_liquid_height= header.height;
+ m_liquidLevel = header.liquidLevel;
+
+ if (!(header.flags&MAP_LIQUID_NO_TYPE))
+ {
+ m_liquid_type = new uint8 [16*16];
+ fread(m_liquid_type, sizeof(uint8), 16*16, in);
+ }
+ if (!(header.flags&MAP_LIQUID_NO_HIGHT))
+ {
+ m_liquid_map = new float [m_liquid_width*m_liquid_height];
+ fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in);
+ }
+ return true;
+}
+
+uint16 GridMap::getArea(float x, float y)
+{
+ if (!m_area_map)
+ return m_gridArea;
+
+ x = 16 * (32 - x/SIZE_OF_GRIDS);
+ y = 16 * (32 - y/SIZE_OF_GRIDS);
+ int lx = (int)x & 15;
+ int ly = (int)y & 15;
+ return m_area_map[lx*16 + ly];
+}
+
+float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const
+{
+ return m_gridHeight;
+}
+
+float GridMap::getHeightFromFloat(float x, float y) const
+{
+ if (!m_V8 || !m_V9)
+ return m_gridHeight;
+
+ x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
- lx -= lx_int;
- ly -= ly_int;
+ int x_int = (int)x;
+ int y_int = (int)y;
+ x -= x_int;
+ y -= y_int;
+ x_int&=(MAP_RESOLUTION - 1);
+ y_int&=(MAP_RESOLUTION - 1);
- float a,b,c;
- if (lx+ly < 1)
+ // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
+ // +--------------> X
+ // | h1-------h2 Coordinates is:
+ // | | \ 1 / | h1 0,0
+ // | | \ / | h2 0,1
+ // | | 2 h5 3 | h3 1,0
+ // | | / \ | h4 1,1
+ // | | / 4 \ | h5 1/2,1/2
+ // | h3-------h4
+ // V Y
+ // For find height need
+ // 1 - detect triangle
+ // 2 - solve linear equation from triangle points
+ // Calculate coefficients for solve h = a*x + b*y + c
+
+ float a,b,c;
+ // Select triangle:
+ if (x+y < 1)
+ {
+ if (x > y)
{
- if (lx > ly)
- {
- // 1
- float h1 = gmap->v9[lx_int][ly_int];
- float h2 = gmap->v9[lx_int+1][ly_int];
- float h5 = 2 * gmap->v8[lx_int][ly_int];
- a = h2-h1;
- b = h5-h1-h2;
- c = h1;
- }
- else
- {
- // 2
- float h1 = gmap->v9[lx_int][ly_int];
- float h3 = gmap->v9[lx_int][ly_int+1];
- float h5 = 2 * gmap->v8[lx_int][ly_int];
- a = h5 - h1 - h3;
- b = h3 - h1;
- c = h1;
- }
+ // 1 triangle (h1, h2, h5 points)
+ float h1 = m_V9[(x_int )*129 + y_int];
+ float h2 = m_V9[(x_int+1)*129 + y_int];
+ float h5 = 2 * m_V8[x_int*128 + y_int];
+ a = h2-h1;
+ b = h5-h1-h2;
+ c = h1;
}
else
{
- if (lx > ly)
- {
- // 3
- float h2 = gmap->v9[lx_int+1][ly_int];
- float h4 = gmap->v9[lx_int+1][ly_int+1];
- float h5 = 2 * gmap->v8[lx_int][ly_int];
- a = h2 + h4 - h5;
- b = h4 - h2;
- c = h5 - h4;
- }
- else
- {
- // 4
- float h3 = gmap->v9[lx_int][ly_int+1];
- float h4 = gmap->v9[lx_int+1][ly_int+1];
- float h5 = 2 * gmap->v8[lx_int][ly_int];
- a = h4 - h3;
- b = h3 + h4 - h5;
- c = h5 - h4;
- }
+ // 2 triangle (h1, h3, h5 points)
+ float h1 = m_V9[x_int*129 + y_int ];
+ float h3 = m_V9[x_int*129 + y_int+1];
+ float h5 = 2 * m_V8[x_int*128 + y_int];
+ a = h5 - h1 - h3;
+ b = h3 - h1;
+ c = h1;
+ }
+ }
+ else
+ {
+ if (x > y)
+ {
+ // 3 triangle (h2, h4, h5 points)
+ float h2 = m_V9[(x_int+1)*129 + y_int ];
+ float h4 = m_V9[(x_int+1)*129 + y_int+1];
+ float h5 = 2 * m_V8[x_int*128 + y_int];
+ a = h2 + h4 - h5;
+ b = h4 - h2;
+ c = h5 - h4;
+ }
+ else
+ {
+ // 4 triangle (h3, h4, h5 points)
+ float h3 = m_V9[(x_int )*129 + y_int+1];
+ float h4 = m_V9[(x_int+1)*129 + y_int+1];
+ float h5 = 2 * m_V8[x_int*128 + y_int];
+ a = h4 - h3;
+ b = h3 + h4 - h5;
+ c = h5 - h4;
}
- float _mapheight = a * lx + b * ly + c;
-
- // In some very rare case this will happen. Need find a better way.
- if(lx_int == MAP_RESOLUTION) --lx_int;
- if(ly_int == MAP_RESOLUTION) --ly_int;
-
- /*
- float zi[4];
- // Probe 4 nearest points (except border cases)
- zi[0] = gmap->Z[lx_int][ly_int];
- zi[1] = lx < MAP_RESOLUTION-1 ? gmap->Z[lx_int+1][ly_int] : zi[0];
- zi[2] = ly < MAP_RESOLUTION-1 ? gmap->Z[lx_int][ly_int+1] : zi[0];
- zi[3] = lx < MAP_RESOLUTION-1 && ly < MAP_RESOLUTION-1 ? gmap->Z[lx_int+1][ly_int+1] : zi[0];
- // Recalculate them like if their x,y positions were in the range 0,1
- float b[4];
- b[0] = zi[0];
- b[1] = zi[1]-zi[0];
- b[2] = zi[2]-zi[0];
- b[3] = zi[0]-zi[1]-zi[2]+zi[3];
- // Normalize the dx and dy to be in range 0..1
- float fact_x = lx - lx_int;
- float fact_y = ly - ly_int;
- // Use the simplified bilinear equation, as described in [url="http://en.wikipedia.org/wiki/Bilinear_interpolation"]http://en.wikipedia.org/wiki/Bilinear_interpolation[/url]
- float _mapheight = b[0] + (b[1]*fact_x) + (b[2]*fact_y) + (b[3]*fact_x*fact_y);
-
- */
+ }
+ // Calculate height
+ return a * x + b * y + c;
+}
+
+float GridMap::getHeightFromUint8(float x, float y) const
+{
+ if (!m_uint8_V8 || !m_uint8_V9)
+ return m_gridHeight;
+
+ x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int x_int = (int)x;
+ int y_int = (int)y;
+ x -= x_int;
+ y -= y_int;
+ x_int&=(MAP_RESOLUTION - 1);
+ y_int&=(MAP_RESOLUTION - 1);
+
+ int32 a, b, c;
+ uint8 *V9_h1_ptr = &m_uint8_V9[x_int*128 + x_int + y_int];
+ if (x+y < 1)
+ {
+ if (x > y)
+ {
+ // 1 triangle (h1, h2, h5 points)
+ int32 h1 = V9_h1_ptr[ 0];
+ int32 h2 = V9_h1_ptr[129];
+ int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
+ a = h2-h1;
+ b = h5-h1-h2;
+ c = h1;
+ }
+ else
+ {
+ // 2 triangle (h1, h3, h5 points)
+ int32 h1 = V9_h1_ptr[0];
+ int32 h3 = V9_h1_ptr[1];
+ int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
+ a = h5 - h1 - h3;
+ b = h3 - h1;
+ c = h1;
+ }
+ }
+ else
+ {
+ if (x > y)
+ {
+ // 3 triangle (h2, h4, h5 points)
+ int32 h2 = V9_h1_ptr[129];
+ int32 h4 = V9_h1_ptr[130];
+ int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
+ a = h2 + h4 - h5;
+ b = h4 - h2;
+ c = h5 - h4;
+ }
+ else
+ {
+ // 4 triangle (h3, h4, h5 points)
+ int32 h3 = V9_h1_ptr[ 1];
+ int32 h4 = V9_h1_ptr[130];
+ int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
+ a = h4 - h3;
+ b = h3 + h4 - h5;
+ c = h5 - h4;
+ }
+ }
+ // Calculate height
+ return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight;
+}
+
+float GridMap::getHeightFromUint16(float x, float y) const
+{
+ if (!m_uint16_V8 || !m_uint16_V9)
+ return m_gridHeight;
+
+ x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int x_int = (int)x;
+ int y_int = (int)y;
+ x -= x_int;
+ y -= y_int;
+ x_int&=(MAP_RESOLUTION - 1);
+ y_int&=(MAP_RESOLUTION - 1);
+
+ int32 a, b, c;
+ uint16 *V9_h1_ptr = &m_uint16_V9[x_int*128 + x_int + y_int];
+ if (x+y < 1)
+ {
+ if (x > y)
+ {
+ // 1 triangle (h1, h2, h5 points)
+ int32 h1 = V9_h1_ptr[ 0];
+ int32 h2 = V9_h1_ptr[129];
+ int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
+ a = h2-h1;
+ b = h5-h1-h2;
+ c = h1;
+ }
+ else
+ {
+ // 2 triangle (h1, h3, h5 points)
+ int32 h1 = V9_h1_ptr[0];
+ int32 h3 = V9_h1_ptr[1];
+ int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
+ a = h5 - h1 - h3;
+ b = h3 - h1;
+ c = h1;
+ }
+ }
+ else
+ {
+ if (x > y)
+ {
+ // 3 triangle (h2, h4, h5 points)
+ int32 h2 = V9_h1_ptr[129];
+ int32 h4 = V9_h1_ptr[130];
+ int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
+ a = h2 + h4 - h5;
+ b = h4 - h2;
+ c = h5 - h4;
+ }
+ else
+ {
+ // 4 triangle (h3, h4, h5 points)
+ int32 h3 = V9_h1_ptr[ 1];
+ int32 h4 = V9_h1_ptr[130];
+ int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
+ a = h4 - h3;
+ b = h3 + h4 - h5;
+ c = h5 - h4;
+ }
+ }
+ // Calculate height
+ return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight;
+}
+
+float GridMap::getLiquidLevel(float x, float y)
+{
+ if (!m_liquid_map)
+ return m_liquidLevel;
+
+ x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int cx_int = ((int)x & (MAP_RESOLUTION-1)) - m_liquid_offY;
+ int cy_int = ((int)y & (MAP_RESOLUTION-1)) - m_liquid_offX;
+
+ if (cx_int < 0 || cx_int >=m_liquid_height)
+ return INVALID_HEIGHT;
+ if (cy_int < 0 || cy_int >=m_liquid_width )
+ return INVALID_HEIGHT;
+
+ return m_liquid_map[cx_int*m_liquid_width + cy_int];
+}
+
+uint8 GridMap::getTerrainType(float x, float y)
+{
+ if (!m_liquid_type)
+ return m_liquidType;
+
+ x = 16 * (32 - x/SIZE_OF_GRIDS);
+ y = 16 * (32 - y/SIZE_OF_GRIDS);
+ int lx = (int)x & 15;
+ int ly = (int)y & 15;
+ return m_liquid_type[lx*16 + ly];
+}
+
+// Get water state on map
+inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data)
+{
+ // Check water type (if no water return)
+ if (!m_liquid_type && !m_liquidType)
+ return LIQUID_MAP_NO_WATER;
+
+ // Get cell
+ float cx = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
+ float cy = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);
+
+ int x_int = (int)cx & (MAP_RESOLUTION-1);
+ int y_int = (int)cy & (MAP_RESOLUTION-1);
+
+ // Check water type in cell
+ uint8 type = m_liquid_type ? m_liquid_type[(x_int>>3)*16 + (y_int>>3)] : m_liquidType;
+ if (type == 0)
+ return LIQUID_MAP_NO_WATER;
+
+ // Check req liquid type mask
+ if (ReqLiquidType && !(ReqLiquidType&type))
+ return LIQUID_MAP_NO_WATER;
+
+ // Check water level:
+ // Check water height map
+ int lx_int = x_int - m_liquid_offY;
+ int ly_int = y_int - m_liquid_offX;
+ if (lx_int < 0 || lx_int >=m_liquid_height)
+ return LIQUID_MAP_NO_WATER;
+ if (ly_int < 0 || ly_int >=m_liquid_width )
+ return LIQUID_MAP_NO_WATER;
+
+ // Get water level
+ float liquid_level = m_liquid_map ? m_liquid_map[lx_int*m_liquid_width + ly_int] : m_liquidLevel;
+ // Get ground level (sub 0.2 for fix some errors)
+ float ground_level = getHeight(x, y);
+
+ // Check water level and ground level
+ if (liquid_level < ground_level || z < ground_level - 2)
+ return LIQUID_MAP_NO_WATER;
+
+ // All ok in water -> store data
+ if (data)
+ {
+ data->type = type;
+ data->level = liquid_level;
+ data->depth_level = ground_level;
+ }
+
+ // For speed check as int values
+ int delta = int((liquid_level - z) * 10);
+
+ // Get position delta
+ if (delta > 20) // Under water
+ return LIQUID_MAP_UNDER_WATER;
+ if (delta > 0 ) // In water
+ return LIQUID_MAP_IN_WATER;
+ if (delta > -1) // Walk on water
+ return LIQUID_MAP_WATER_WALK;
+ // Above water
+ return LIQUID_MAP_ABOVE_WATER;
+}
+
+inline GridMap *Map::GetGrid(float x, float y)
+{
+ // half opt method
+ int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x
+ int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
+
+ // ensure GridMap is loaded
+ EnsureGridCreated(GridPair(63-gx,63-gy));
+
+ return GridMaps[gx][gy];
+}
+
+float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const
+{
+ // find raw .map surface under Z coordinates
+ float mapHeight;
+ if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ {
+ float _mapheight = 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;
@@ -1387,76 +1754,184 @@ float Map::GetVmapHeight(float x, float y, float z, bool useMaps) const
return vmapHeight;
}
-uint16 Map::GetAreaFlag(float x, float y ) const
+uint16 Map::GetAreaFlag(float x, float y, float z) const
{
- //local x,y coords
- float lx,ly;
- int gx,gy;
- GridPair p = Trinity::ComputeGridPair(x, y);
+ uint16 areaflag;
+ if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ areaflag = gmap->getArea(x, y);
+ // this used while not all *.map files generated (instances)
+ else
+ areaflag = GetAreaFlagByMapId(i_id);
+
+ //FIXME: some hacks for areas above or underground for ground area
+ // required for area specific spells/etc, until map/vmap data
+ // not provided correct areaflag with this hacks
+ switch(areaflag)
+ {
+ // Acherus: The Ebon Hold (Plaguelands: The Scarlet Enclave)
+ case 1984: // Plaguelands: The Scarlet Enclave
+ case 2076: // Death's Breach (Plaguelands: The Scarlet Enclave)
+ case 2745: // The Noxious Pass (Plaguelands: The Scarlet Enclave)
+ if(z > 350.0f) areaflag = 2048; break;
+ // Acherus: The Ebon Hold (Eastern Plaguelands)
+ case 856: // The Noxious Glade (Eastern Plaguelands)
+ case 2456: // Death's Breach (Eastern Plaguelands)
+ if(z > 350.0f) areaflag = 1950; break;
+ // Dalaran
+ case 2492: // Forlorn Woods (Crystalsong Forest)
+ if (x > 5568.0f && x < 6116.0f && y > 282.0f && y < 982.0f && z > 563.0f)
+ {
+ // Krasus' Landing (Dalaran), fast check
+ if (x > 5758.77f && x < 5869.03f && y < 510.46f)
+ {
+ // Krasus' Landing (Dalaran), with open east side
+ if (y < 449.33f || (x-5813.9f)*(x-5813.9f)+(y-449.33f)*(y-449.33f) < 1864.0f)
+ {
+ areaflag = 2533; // Note: also 2633, possible one flight allowed and other not allowed case
+ break;
+ }
+ }
- // half opt method
- gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x
- gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
+ // Dalaran
+ areaflag = 2153;
+ }
+ break;
+ // The Violet Citadel (Dalaran) or Dalaran
+ case 2484: // The Twilight Rivulet (Crystalsong Forest)
+ case 1593: // Crystalsong Forest
+ // Dalaran
+ if (x > 5568.0f && x < 6116.0f && y > 282.0f && y < 982.0f && z > 563.0f)
+ {
+ // The Violet Citadel (Dalaran), fast check
+ if (x > 5721.1f && x < 5884.66f && y > 764.4f && y < 948.0f)
+ {
+ // The Violet Citadel (Dalaran)
+ if ((x-5803.0f)*(x-5803.0f)+(y-846.18f)*(y-846.18f) < 6690.0f)
+ {
+ areaflag = 2696;
+ break;
+ }
+ }
+
+ // Dalaran
+ areaflag = 2153;
+ }
+ break;
+ // Vargoth's Retreat (Dalaran) or The Violet Citadel (Dalaran) or Dalaran
+ case 2504: // Violet Stand (Crystalsong Forest)
+ // Dalaran
+ if (x > 5568.0f && x < 6116.0f && y > 282.0f && y < 982.0f && z > 563.0f)
+ {
+ // The Violet Citadel (Dalaran), fast check
+ if (x > 5721.1f && x < 5884.66f && y > 764.4f && y < 948.0f)
+ {
+ // Vargoth's Retreat (Dalaran), nice slow circle with upper limit
+ if (z < 898.0f && (x-5765.0f)*(x-5765.0f)+(y-862.4f)*(y-862.4f) < 262.0f)
+ {
+ areaflag = 2748;
+ break;
+ }
- lx=16*(32 -x/SIZE_OF_GRIDS - gx);
- ly=16*(32 -y/SIZE_OF_GRIDS - gy);
- //DEBUG_LOG("my %d %d si %d %d",gx,gy,p.x_coord,p.y_coord);
+ // The Violet Citadel (Dalaran)
+ if ((x-5803.0f)*(x-5803.0f)+(y-846.18f)*(y-846.18f) < 6690.0f)
+ {
+ areaflag = 2696;
+ break;
+ }
+ }
- // ensure GridMap is loaded
- const_cast<Map*>(this)->EnsureGridCreated(GridPair(63-gx,63-gy));
+ // Dalaran
+ areaflag = 2153;
+ }
+ break;
+ // Maw of Neltharion (cave)
+ case 164: // Dragonblight
+ case 1797: // Obsidian Dragonshrine (Dragonblight)
+ case 1827: // Wintergrasp
+ case 2591: // The Cauldron of Flames (Wintergrasp)
+ if (x > 4364.0f && x < 4632.0f && y > 1545.0f && y < 1886.0f && z < 200.0f) areaflag = 1853; break;
+ // Undercity (sewers enter and path)
+ case 179: // Tirisfal Glades
+ if (x > 1595.0f && x < 1699.0f && y > 535.0f && y < 643.5f && z < 30.5f) areaflag = 685; break;
+ // Undercity (Royal Quarter)
+ case 210: // Silverpine Forest
+ case 316: // The Shining Strand (Silverpine Forest)
+ case 438: // Lordamere Lake (Silverpine Forest)
+ if (x > 1237.0f && x < 1401.0f && y > 284.0f && y < 440.0f && z < -40.0f) areaflag = 685; break;
+ // Undercity (cave and ground zone, part of royal quarter)
+ case 607: // Ruins of Lordaeron (Tirisfal Glades)
+ // ground and near to ground (by city walls)
+ if(z > 0.0f)
+ {
+ if (x > 1510.0f && x < 1839.0f && y > 29.77f && y < 433.0f) areaflag = 685;
+ }
+ // more wide underground, part of royal quarter
+ else
+ {
+ if (x > 1299.0f && x < 1839.0f && y > 10.0f && y < 440.0f) areaflag = 685;
+ }
+ break;
+ // The Makers' Perch (ground) and Makers' Overlook (ground and cave)
+ case 1335: // Sholazar Basin
+ // The Makers' Perch ground (fast box)
+ if (x > 6100.0f && x < 6250.0f && y > 5650.0f && y < 5800.0f)
+ {
+ // nice slow circle
+ if ((x-6183.0f)*(x-6183.0f)+(y-5717.0f)*(y-5717.0f) < 2500.0f)
+ areaflag = 2189;
+ }
+ // Makers' Overlook (ground and cave)
+ else if (x > 5634.48f && x < 5774.53f && y < 3475.0f && z > 300.0f)
+ {
+ if(y > 3380.26f || y > 3265.0f && z < 360.0f) areaflag = 2187;
+ }
+ break;
+ // The Makers' Perch (underground)
+ case 2147: // The Stormwright's Shelf (Sholazar Basin)
+ if (x > 6199.0f && x < 6283.0f && y > 5705.0f && y < 5817.0f && z < 38.0f) areaflag = 2189; break;
+ // Makers' Overlook (deep cave)
+ case 267: // Icecrown
+ if (x > 5684.0f && x < 5798.0f && y > 3035.0f && y < 3367.0f && z < 358.0f) areaflag = 2187; break;
+ // Wyrmrest Temple (Dragonblight)
+ case 1814: // Path of the Titans (Dragonblight)
+ case 1897: // The Dragon Wastes (Dragonblight)
+ // fast box
+ if (x > 3400.0f && x < 3700.0f && y > 130.0f && y < 420.0f)
+ {
+ // nice slow circle
+ if ((x-3546.87f)*(x-3546.87f)+(y-272.71f)*(y-272.71f) < 19600.0f) areaflag = 1791;
+ }
+ break;
+ }
- if(GridMaps[gx][gy])
- return GridMaps[gx][gy]->area_flag[(int)(lx)][(int)(ly)];
- // this used while not all *.map files generated (instances)
- else
- return GetAreaFlagByMapId(i_id);
+ return areaflag;
}
uint8 Map::GetTerrainType(float x, float y ) const
{
- //local x,y coords
- float lx,ly;
- int gx,gy;
-
- // half opt method
- gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x
- gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
-
- lx=16*(32 -x/SIZE_OF_GRIDS - gx);
- ly=16*(32 -y/SIZE_OF_GRIDS - gy);
-
- // ensure GridMap is loaded
- const_cast<Map*>(this)->EnsureGridCreated(GridPair(63-gx,63-gy));
-
- if(GridMaps[gx][gy])
- return GridMaps[gx][gy]->terrain_type[(int)(lx)][(int)(ly)];
+ if(GridMap *gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ return gmap->getTerrainType(x, y);
else
return 0;
}
-float Map::GetWaterLevel(float x, float y ) const
+ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data) const
{
- //local x,y coords
- float lx,ly;
- int gx,gy;
-
- // half opt method
- gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x
- gy=(int)(32-y/SIZE_OF_GRIDS); //grid y
-
- lx=128*(32 -x/SIZE_OF_GRIDS - gx);
- ly=128*(32 -y/SIZE_OF_GRIDS - gy);
-
- // ensure GridMap is loaded
- const_cast<Map*>(this)->EnsureGridCreated(GridPair(63-gx,63-gy));
+ if(GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ return gmap->getLiquidStatus(x, y, z, ReqLiquidType, data);
+ else
+ return LIQUID_MAP_NO_WATER;
+}
- if(GridMaps[gx][gy])
- return GridMaps[gx][gy]->liquid_level[(int)(lx)][(int)(ly)];
+float Map::GetWaterLevel(float x, float y ) const
+{
+ if(GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ return gmap->getLiquidLevel(x, y);
else
return 0;
}
-uint32 Map::GetAreaId(uint16 areaflag,uint32 map_id)
+uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id)
{
AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id);
@@ -1466,7 +1941,7 @@ uint32 Map::GetAreaId(uint16 areaflag,uint32 map_id)
return 0;
}
-uint32 Map::GetZoneId(uint16 areaflag,uint32 map_id)
+uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id)
{
AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id);
@@ -1476,26 +1951,37 @@ uint32 Map::GetZoneId(uint16 areaflag,uint32 map_id)
return 0;
}
-bool Map::IsInWater(float x, float y, float pZ) const
+void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id)
{
- // This method is called too often to use vamps for that (4. parameter = false).
- // The pZ pos is taken anyway for future use
- float z = GetHeight(x,y,pZ,false); // use .map base surface height
+ AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id);
- // underground or instance without vmap
- if(z <= INVALID_HEIGHT)
- return false;
+ areaid = entry ? entry->ID : 0;
+ zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0;
+}
- float water_z = GetWaterLevel(x,y);
- uint8 flag = GetTerrainType(x,y);
- return (z < (water_z-2)) && (flag & 0x01);
+bool Map::IsInWater(float x, float y, float pZ) const
+{
+ // Check surface in x, y point for liquid
+ if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ {
+ LiquidData liquid_status;
+ if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, &liquid_status))
+ {
+ if (liquid_status.level - liquid_status.depth_level > 2)
+ return true;
+ }
+ }
+ return false;
}
bool Map::IsUnderWater(float x, float y, float z) const
{
- float water_z = GetWaterLevel(x,y);
- uint8 flag = GetTerrainType(x,y);
- return (z < (water_z-2)) && (flag & 0x01);
+ if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
+ {
+ if (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN)&LIQUID_MAP_UNDER_WATER)
+ return true;
+ }
+ return false;
}
bool Map::CheckGridIntegrity(Creature* c, bool moved) const
@@ -1583,9 +2069,10 @@ void Map::SendInitTransports( Player * player )
bool hasTransport = false;
- for (MapManager::TransportSet::iterator i = tset.begin(); i != tset.end(); ++i)
+ for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
{
- if((*i) != player->GetTransport()) // send data for current transport in other place
+ // send data for current transport in other place
+ if((*i) != player->GetTransport() && (*i)->GetMapId()==i_id)
{
hasTransport = true;
(*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
@@ -1611,8 +2098,8 @@ void Map::SendRemoveTransports( Player * player )
MapManager::TransportSet& tset = tmap[player->GetMapId()];
// except used transport
- for (MapManager::TransportSet::iterator i = tset.begin(); i != tset.end(); ++i)
- if(player->GetTransport() != (*i))
+ for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
+ if((*i) != player->GetTransport() && (*i)->GetMapId()!=i_id)
(*i)->BuildOutOfRangeUpdateBlock(&transData);
WorldPacket packet;
@@ -1669,7 +2156,7 @@ void Map::RemoveAllObjectsInRemoveList()
switch(obj->GetTypeId())
{
case TYPEID_UNIT:
- if(!((Creature*)obj)->isPet())
+ if(!((Creature*)obj)->isWorldCreature())
SwitchGridContainers((Creature*)obj, on);
break;
}
@@ -1816,8 +2303,9 @@ template void Map::Remove(DynamicObject *, bool);
/* ******* Dungeon Instance Maps ******* */
InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
- : Map(id, expiry, InstanceId, SpawnMode), i_data(NULL),
- m_resetAfterUnload(false), m_unloadWhenEmpty(false)
+ : Map(id, expiry, InstanceId, SpawnMode),
+ m_resetAfterUnload(false), m_unloadWhenEmpty(false),
+ i_data(NULL), i_script_id(0)
{
// the timer is started by default, and stopped when the first player joins
// this make sure it gets unloaded if for some reason no player joins
@@ -1846,10 +2334,10 @@ bool InstanceMap::CanEnter(Player *player)
}
// cannot enter if the instance is full (player cap), GMs don't count
- InstanceTemplate const* iTemplate = objmgr.GetInstanceTemplate(GetId());
- if (!player->isGameMaster() && GetPlayersCountExceptGMs() >= iTemplate->maxPlayers)
+ uint32 maxPlayers = GetMaxPlayers();
+ if (!player->isGameMaster() && GetPlayersCountExceptGMs() >= maxPlayers)
{
- sLog.outDetail("MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), iTemplate->maxPlayers, player->GetName());
+ sLog.outDetail("MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName());
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
return false;
}
@@ -1879,79 +2367,81 @@ bool InstanceMap::Add(Player *player)
if(!CanEnter(player))
return false;
- // get or create an instance save for the map
- InstanceSave *mapSave = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
- if(!mapSave)
- {
- sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
- mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), GetSpawnMode(), 0, true);
- }
-
- // check for existing instance binds
- InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetSpawnMode());
- if(playerBind && playerBind->perm)
+ // Dungeon only code
+ if(IsDungeon())
{
- // cannot enter other instances if bound permanently
- if(playerBind->save != mapSave)
+ // get or create an instance save for the map
+ InstanceSave *mapSave = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
+ if(!mapSave)
{
- sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put in instance %d,%d,%d,%d,%d,%d", player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
- assert(false);
+ sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
+ mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), GetSpawnMode(), 0, true);
}
- }
- else
- {
- Group *pGroup = player->GetGroup();
- if(pGroup)
+
+ // check for existing instance binds
+ InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetSpawnMode());
+ if(playerBind && playerBind->perm)
{
- // solo saves should be reset when entering a group
- InstanceGroupBind *groupBind = pGroup->GetBoundInstance(GetId(), GetSpawnMode());
- if(playerBind)
+ // cannot enter other instances if bound permanently
+ if(playerBind->save != mapSave)
{
- sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
- if(groupBind) sLog.outError("InstanceMap::Add: the group is bound to instance %d,%d,%d,%d,%d,%d", groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
- sLog.outError("InstanceMap::Add: do not let player %s enter instance otherwise crash will happen", player->GetName());
- return false;
- //player->UnbindInstance(GetId(), GetSpawnMode());
- //assert(false);
+ sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put in instance %d,%d,%d,%d,%d,%d", player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
+ assert(false);
}
- // bind to the group or keep using the group save
- if(!groupBind)
- pGroup->BindToInstance(mapSave, false);
- else
+ }
+ else
+ {
+ Group *pGroup = player->GetGroup();
+ if(pGroup)
{
- // cannot jump to a different instance without resetting it
- if(groupBind->save != mapSave)
+ // solo saves should be reset when entering a group
+ InstanceGroupBind *groupBind = pGroup->GetBoundInstance(GetId(), GetSpawnMode());
+ if(playerBind)
{
- sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty());
- if(mapSave)
- sLog.outError("MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
- else
- sLog.outError("MapSave NULL");
- if(groupBind->save)
- sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
- else
- sLog.outError("GroupBind save NULL");
- assert(false);
+ sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
+ if(groupBind) sLog.outError("InstanceMap::Add: the group is bound to instance %d,%d,%d,%d,%d,%d", groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
+ //assert(false);
+ return false;
}
- // if the group/leader is permanently bound to the instance
- // players also become permanently bound when they enter
- if(groupBind->perm)
+ // bind to the group or keep using the group save
+ if(!groupBind)
+ pGroup->BindToInstance(mapSave, false);
+ else
{
- WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
- data << uint32(0);
- player->GetSession()->SendPacket(&data);
- player->BindToInstance(mapSave, true);
+ // cannot jump to a different instance without resetting it
+ if(groupBind->save != mapSave)
+ {
+ sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty());
+ if(mapSave)
+ sLog.outError("MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
+ else
+ sLog.outError("MapSave NULL");
+ if(groupBind->save)
+ sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
+ else
+ sLog.outError("GroupBind save NULL");
+ assert(false);
+ }
+ // if the group/leader is permanently bound to the instance
+ // players also become permanently bound when they enter
+ if(groupBind->perm)
+ {
+ WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4);
+ data << uint32(0);
+ player->GetSession()->SendPacket(&data);
+ player->BindToInstance(mapSave, true);
+ }
}
}
- }
- else
- {
- // set up a solo bind or continue using it
- if(!playerBind)
- player->BindToInstance(mapSave, false);
else
- // cannot jump to a different instance without resetting it
- assert(playerBind->save == mapSave);
+ {
+ // set up a solo bind or continue using it
+ if(!playerBind)
+ player->BindToInstance(mapSave, false);
+ else
+ // cannot jump to a different instance without resetting it
+ assert(playerBind->save == mapSave);
+ }
}
}
@@ -1960,7 +2450,6 @@ bool InstanceMap::Add(Player *player)
// first player enters (no players yet)
SetResetSchedule(false);
- player->SendInitWorldStates();
sLog.outDetail("MAP: Player '%s' entered the instance '%u' of map '%s'", player->GetName(), GetInstanceId(), GetMapName());
// initialize unload state
m_unloadTimer = 0;
@@ -1992,20 +2481,6 @@ void InstanceMap::Remove(Player *player, bool remove)
SetResetSchedule(true);
}
-Creature * Map::GetCreatureInMap(uint64 guid)
-{
- Creature * obj = HashMapHolder<Creature>::Find(guid);
- if(obj && obj->GetInstanceId() != GetInstanceId()) obj = NULL;
- return obj;
-}
-
-GameObject * Map::GetGameObjectInMap(uint64 guid)
-{
- GameObject * obj = HashMapHolder<GameObject>::Find(guid);
- if(obj && obj->GetInstanceId() != GetInstanceId()) obj = NULL;
- return obj;
-}
-
void InstanceMap::CreateInstanceData(bool load)
{
if(i_data != NULL)
@@ -2031,7 +2506,7 @@ void InstanceMap::CreateInstanceData(bool load)
{
Field* fields = result->Fetch();
const char* data = fields[0].GetString();
- if(data)
+ if(data && data != "")
{
sLog.outDebug("Loading instance data for `%s` with id %u", objmgr.GetScriptName(i_script_id), i_InstanceId);
i_data->Load(data);
@@ -2084,10 +2559,13 @@ bool InstanceMap::Reset(uint8 method)
void InstanceMap::PermBindAllPlayers(Player *player)
{
+ if(!IsDungeon())
+ return;
+
InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
if(!save)
{
- sLog.outError("Cannot bind players, no instance save available for map!\n");
+ sLog.outError("Cannot bind players, no instance save available for map!");
return;
}
@@ -2113,12 +2591,6 @@ void InstanceMap::PermBindAllPlayers(Player *player)
}
}
-time_t InstanceMap::GetResetTime()
-{
- InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
- return save ? save->GetDifficulty() : DIFFICULTY_NORMAL;
-}
-
void InstanceMap::UnloadAll()
{
if(HavePlayers())
@@ -2148,7 +2620,7 @@ void InstanceMap::SetResetSchedule(bool on)
// only for normal instances
// the reset time is only scheduled when there are no payers inside
// it is assumed that the reset time will rarely (if ever) change while the reset is scheduled
- if(!HavePlayers() && !IsRaid() && !IsHeroic())
+ if(IsDungeon() && !HavePlayers() && !IsRaid() && !IsHeroic())
{
InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId());
if(!save) sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId());
@@ -2156,6 +2628,14 @@ void InstanceMap::SetResetSchedule(bool on)
}
}
+uint32 InstanceMap::GetMaxPlayers() const
+{
+ InstanceTemplate const* iTemplate = objmgr.GetInstanceTemplate(GetId());
+ if(!iTemplate)
+ return 0;
+ return IsHeroic() ? iTemplate->maxPlayersHeroic : iTemplate->maxPlayers;
+}
+
/* ******* Battleground Instance Maps ******* */
BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId)
@@ -2213,7 +2693,7 @@ void BattleGroundMap::UnloadAll()
{
if(Player * plr = m_mapRefManager.getFirst()->getSource())
{
- plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
+ plr->TeleportTo(plr->GetBattleGroundEntryPoint());
// TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator.
// just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop
// note that this remove is not needed if the code works well in other places
@@ -2224,5 +2704,44 @@ void BattleGroundMap::UnloadAll()
Map::UnloadAll();
}
-/*--------------------------TRINITY-------------------------*/
+Creature*
+Map::GetCreature(uint64 guid)
+{
+ Creature * ret = ObjectAccessor::GetObjectInWorld(guid, (Creature*)NULL);
+ if(!ret)
+ return NULL;
+ if(ret->GetMapId() != GetId())
+ return NULL;
+
+ if(ret->GetInstanceId() != GetInstanceId())
+ return NULL;
+
+ return ret;
+}
+
+GameObject*
+Map::GetGameObject(uint64 guid)
+{
+ GameObject * ret = ObjectAccessor::GetObjectInWorld(guid, (GameObject*)NULL);
+ if(!ret)
+ return NULL;
+ if(ret->GetMapId() != GetId())
+ return NULL;
+ if(ret->GetInstanceId() != GetInstanceId())
+ return NULL;
+ return ret;
+}
+
+DynamicObject*
+Map::GetDynamicObject(uint64 guid)
+{
+ DynamicObject * ret = ObjectAccessor::GetObjectInWorld(guid, (DynamicObject*)NULL);
+ if(!ret)
+ return NULL;
+ if(ret->GetMapId() != GetId())
+ return NULL;
+ if(ret->GetInstanceId() != GetInstanceId())
+ return NULL;
+ return ret;
+}
diff --git a/src/game/Map.h b/src/game/Map.h
index f117a1c1cec..c69fe5f7345 100644
--- a/src/game/Map.h
+++ b/src/game/Map.h
@@ -23,10 +23,10 @@
#include "Platform/Define.h"
#include "Policies/ThreadingModel.h"
-#include "zthread/Lockable.h"
-#include "zthread/Mutex.h"
-#include "zthread/FairReadWriteLock.h"
-#include "Database/DBCStructure.h"
+#include "ace/RW_Thread_Mutex.h"
+#include "ace/Thread_Mutex.h"
+
+#include "DBCStructure.h"
#include "GridDefines.h"
#include "Cell.h"
#include "Timer.h"
@@ -43,15 +43,11 @@ class InstanceData;
class Group;
class InstanceSave;
class WorldObject;
+class TempSummon;
class CreatureGroup;
-namespace ZThread
-{
- class Lockable;
- class ReadWriteLock;
-}
-typedef ZThread::FairReadWriteLock GridRWLock;
+typedef ACE_RW_Thread_Mutex GridRWLock;
template<class MUTEX, class LOCK_TYPE>
struct RGuard
@@ -67,19 +63,139 @@ struct WGuard
Trinity::GeneralLock<LOCK_TYPE> i_lock;
};
-typedef RGuard<GridRWLock, ZThread::Lockable> GridReadGuard;
-typedef WGuard<GridRWLock, ZThread::Lockable> GridWriteGuard;
-typedef Trinity::SingleThreaded<GridRWLock>::Lock NullGuard;
+typedef RGuard<GridRWLock, ACE_Thread_Mutex> GridReadGuard;
+typedef WGuard<GridRWLock, ACE_Thread_Mutex> GridWriteGuard;
+typedef MaNGOS::SingleThreaded<GridRWLock>::Lock NullGuard;
+
+//******************************************
+// Map file format defines
+//******************************************
+#define MAP_MAGIC 'SPAM'
+#define MAP_VERSION_MAGIC '0.1w'
+#define MAP_AREA_MAGIC 'AERA'
+#define MAP_HEIGTH_MAGIC 'TGHM'
+#define MAP_LIQUID_MAGIC 'QILM'
+
+struct map_fileheader{
+ uint32 mapMagic;
+ uint32 versionMagic;
+ uint32 areaMapOffset;
+ uint32 areaMapSize;
+ uint32 heightMapOffset;
+ uint32 heightMapSize;
+ uint32 liquidMapOffset;
+ uint32 liquidMapSize;
+};
+
+#define MAP_AREA_NO_AREA 0x0001
+struct map_areaHeader{
+ uint32 fourcc;
+ uint16 flags;
+ uint16 gridArea;
+};
+
+#define MAP_HEIGHT_NO_HIGHT 0x0001
+#define MAP_HEIGHT_AS_INT16 0x0002
+#define MAP_HEIGHT_AS_INT8 0x0004
+
+struct map_heightHeader{
+ uint32 fourcc;
+ uint32 flags;
+ float gridHeight;
+ float gridMaxHeight;
+};
+
+#define MAP_LIQUID_NO_TYPE 0x0001
+#define MAP_LIQUID_NO_HIGHT 0x0002
+struct map_liquidHeader{
+ uint32 fourcc;
+ uint16 flags;
+ uint16 liquidType;
+ uint8 offsetX;
+ uint8 offsetY;
+ uint8 width;
+ uint8 height;
+ float liquidLevel;
+};
+
+enum ZLiquidStatus{
+ LIQUID_MAP_NO_WATER = 0x00000000,
+ LIQUID_MAP_ABOVE_WATER = 0x00000001,
+ LIQUID_MAP_WATER_WALK = 0x00000002,
+ LIQUID_MAP_IN_WATER = 0x00000004,
+ LIQUID_MAP_UNDER_WATER = 0x00000008
+};
+
+#define MAP_LIQUID_TYPE_NO_WATER 0x00
+#define MAP_LIQUID_TYPE_WATER 0x01
+#define MAP_LIQUID_TYPE_OCEAN 0x02
+#define MAP_LIQUID_TYPE_MAGMA 0x04
+#define MAP_LIQUID_TYPE_SLIME 0x08
-typedef struct
+#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)
+
+#define MAP_LIQUID_TYPE_DARK_WATER 0x10
+#define MAP_LIQUID_TYPE_WMO_WATER 0x20
+
+struct LiquidData{
+ uint32 type;
+ float level;
+ float depth_level;
+};
+
+class GridMap
{
- uint16 area_flag[16][16];
- uint8 terrain_type[16][16];
- float liquid_level[128][128];
- float v9[16 * 8 + 1][16 * 8 + 1];
- float v8[16 * 8][16 * 8];
- //float Z[MAP_RESOLUTION][MAP_RESOLUTION];
-}GridMap;
+ uint32 m_flags;
+ // Area data
+ uint16 m_gridArea;
+ uint16 *m_area_map;
+ // Height level data
+ float m_gridHeight;
+ float m_gridIntHeightMultiplier;
+ union{
+ float *m_V9;
+ uint16 *m_uint16_V9;
+ uint8 *m_uint8_V9;
+ };
+ union{
+ float *m_V8;
+ uint16 *m_uint16_V8;
+ uint8 *m_uint8_V8;
+ };
+ // Liquid data
+ uint16 m_liquidType;
+ uint8 m_liquid_offX;
+ uint8 m_liquid_offY;
+ uint8 m_liquid_width;
+ uint8 m_liquid_height;
+ float m_liquidLevel;
+ uint8 *m_liquid_type;
+ float *m_liquid_map;
+
+ bool loadAreaData(FILE *in, uint32 offset, uint32 size);
+ bool loadHeihgtData(FILE *in, uint32 offset, uint32 size);
+ bool loadLiquidData(FILE *in, uint32 offset, uint32 size);
+
+ // Get height functions and pointers
+ typedef float (GridMap::*pGetHeightPtr) (float x, float y) const;
+ pGetHeightPtr m_gridGetHeight;
+ float getHeightFromFloat(float x, float y) const;
+ float getHeightFromUint16(float x, float y) const;
+ float getHeightFromUint8(float x, float y) const;
+ float getHeightFromFlat(float x, float y) const;
+
+public:
+ GridMap();
+ ~GridMap();
+ bool loadData(char *filaname);
+ void unloadData();
+
+ uint16 getArea(float x, float y);
+ inline float getHeight(float x, float y) {return (this->*m_gridGetHeight)(x, y);}
+ float getLiquidLevel(float x, float y);
+ uint8 getTerrainType(float x, float y);
+ ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0);
+};
struct CreatureMover
{
@@ -99,9 +215,10 @@ struct CreatureMover
struct InstanceTemplate
{
uint32 map;
- uint32 parent;
+ uint32 parent;
uint32 maxPlayers;
- uint32 reset_delay;
+ uint32 maxPlayersHeroic;
+ uint32 reset_delay; // FIX ME: now exist normal/heroic raids with possible different time of reset.
uint32 access_id;
float startLocX;
float startLocY;
@@ -129,7 +246,7 @@ typedef UNORDERED_MAP<Creature*, CreatureMover> CreatureMoveList;
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
-class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::ObjectLevelLockable<Map, ZThread::Mutex>
+class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::ObjectLevelLockable<Map, ACE_Thread_Mutex>
{
friend class MapReference;
public:
@@ -182,9 +299,8 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
time_t GetGridExpiry(void) const { return i_gridExpiry; }
uint32 GetId(void) const { return i_id; }
- static bool ExistMap(uint32 mapid, int x, int y);
- static bool ExistVMap(uint32 mapid, int x, int y);
- void LoadMapAndVMap(uint32 mapid, uint32 instanceid, int x, int y);
+ static bool ExistMap(uint32 mapid, int gx, int gy);
+ static bool ExistVMap(uint32 mapid, int gx, int gy);
static void InitStateMachine();
static void DeleteStateMachine();
@@ -195,22 +311,30 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
float GetVmapHeight(float x, float y, float z, bool useMaps) const;
bool IsInWater(float x, float y, float z) const; // does not use z pos. This is for future use
- uint16 GetAreaFlag(float x, float y ) const;
+ ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0) const;
+
+ uint16 GetAreaFlag(float x, float y, float z) const;
uint8 GetTerrainType(float x, float y ) const;
float GetWaterLevel(float x, float y ) const;
bool IsUnderWater(float x, float y, float z) const;
- static uint32 GetAreaId(uint16 areaflag,uint32 map_id);
- static uint32 GetZoneId(uint16 areaflag,uint32 map_id);
+ static uint32 GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id);
+ static uint32 GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id);
+ static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id);
+
+ uint32 GetAreaId(float x, float y, float z) const
+ {
+ return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),i_id);
+ }
- uint32 GetAreaId(float x, float y) const
+ uint32 GetZoneId(float x, float y, float z) const
{
- return GetAreaId(GetAreaFlag(x,y),i_id);
+ return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),i_id);
}
- uint32 GetZoneId(float x, float y) const
+ void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
{
- return GetZoneId(GetAreaFlag(x,y),i_id);
+ GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),i_id);
}
virtual void MoveAllCreaturesInMoveList();
@@ -221,8 +345,8 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
// assert print helper
bool CheckGridIntegrity(Creature* c, bool moved) const;
- uint32 GetInstanceId() { return i_InstanceId; }
- uint8 GetSpawnMode() { return (i_spawnMode); }
+ uint32 GetInstanceId() const { return i_InstanceId; }
+ uint8 GetSpawnMode() const { return (i_spawnMode); }
virtual bool CanEnter(Player* /*player*/) { return true; }
const char* GetMapName() const;
@@ -234,6 +358,17 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); }
bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); }
bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); }
+ bool GetEntrancePos(int32 &mapid, float &x, float &y)
+ {
+ if(!i_mapEntry)
+ return false;
+ if(i_mapEntry->entrance_map < 0)
+ return false;
+ mapid = i_mapEntry->entrance_map;
+ x = i_mapEntry->entrance_x;
+ y = i_mapEntry->entrance_y;
+ return true;
+ }
void AddObjectToRemoveList(WorldObject *obj);
void AddObjectToSwitchList(WorldObject *obj, bool on);
@@ -246,8 +381,6 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
void resetMarkedCells() { marked_cells.reset(); }
bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); }
void markCell(uint32 pCellId) { marked_cells.set(pCellId); }
- Creature* GetCreatureInMap(uint64 guid);
- GameObject* GetGameObjectInMap(uint64 guid);
bool HavePlayers() const { return !m_mapRefManager.isEmpty(); }
uint32 GetPlayersCountExceptGMs() const;
@@ -277,10 +410,19 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
template<class NOTIFIER> void VisitAll(const float &x, const float &y, float radius, NOTIFIER &notifier);
template<class NOTIFIER> void VisitWorld(const float &x, const float &y, float radius, NOTIFIER &notifier);
template<class NOTIFIER> void VisitGrid(const float &x, const float &y, float radius, NOTIFIER &notifier);
- CreatureGroupHolderType CreatureGroupHolder;
+
+ TempSummon *SummonCreature(uint32 entry, float x, float y, float z, float angle, SummonPropertiesEntry const *properties = NULL, uint32 duration = 0, Unit *summoner = NULL);
+
+ CreatureGroupHolderType CreatureGroupHolder;
+
+ Creature* GetCreature(uint64 guid);
+ GameObject* GetGameObject(uint64 guid);
+ DynamicObject* GetDynamicObject(uint64 guid);
private:
- void LoadVMap(int pX, int pY);
- void LoadMap(uint32 mapid, uint32 instanceid, int x,int y);
+ void LoadMapAndVMap(int gx, int gy);
+ void LoadVMap(int gx, int gy);
+ void LoadMap(int gx,int gy, bool reload = false);
+ GridMap *GetGrid(float x, float y);
void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; }
//uint64 CalculateGridMask(const uint32 &y) const;
@@ -296,8 +438,9 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
CreatureMoveList i_creaturesToMove;
bool loaded(const GridPair &) const;
- void EnsureGridLoaded(const Cell&, Player* player = NULL);
- void EnsureGridCreated(const GridPair &);
+ void EnsureGridCreated(const GridPair &);
+ bool EnsureGridLoaded(Cell const&);
+ void EnsureGridLoadedAtEnter(Cell const&, Player* player = NULL);
void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); }
@@ -318,7 +461,7 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
protected:
void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); }
- typedef Trinity::ObjectLevelLockable<Map, ZThread::Mutex>::Lock Guard;
+ typedef MaNGOS::ObjectLevelLockable<Map, ACE_Thread_Mutex>::Lock Guard;
MapEntry const* i_mapEntry;
uint8 i_spawnMode;
@@ -410,11 +553,11 @@ class TRINITY_DLL_SPEC InstanceMap : public Map
uint32 GetScriptId() { return i_script_id; }
InstanceData* GetInstanceData() { return i_data; }
void PermBindAllPlayers(Player *player);
- time_t GetResetTime();
void UnloadAll();
bool CanEnter(Player* player);
void SendResetWarnings(uint32 timeLeft) const;
void SetResetSchedule(bool on);
+ uint32 GetMaxPlayers() const;
private:
bool m_resetAfterUnload;
bool m_unloadWhenEmpty;
diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp
index fcdc2f76c11..df0fca8016c 100644
--- a/src/game/MapInstanced.cpp
+++ b/src/game/MapInstanced.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -112,93 +112,66 @@ void MapInstanced::UnloadAll()
*/
Map* MapInstanced::GetInstance(const WorldObject* obj)
{
- uint32 CurInstanceId = obj->GetInstanceId();
- Map* map = NULL;
-
- if (obj->GetMapId() == GetId() && CurInstanceId != 0)
+ if(obj->GetTypeId() == TYPEID_UNIT)
{
- // the object wants to be put in a certain instance of this map
- map = _FindMap(CurInstanceId);
- if(!map)
- {
- // For players if the instanceId is set, it's assumed they are already in a map,
- // hence the map must be loaded. For Creatures, GameObjects etc the map must exist
- // prior to calling GetMap, they are not allowed to create maps for themselves.
- sLog.outError("GetInstance: object %s(%d), typeId %d, in world %d, should be in map %d,%d but that's not loaded yet.", obj->GetName(), obj->GetGUIDLow(), obj->GetTypeId(), obj->IsInWorld(), obj->GetMapId(), obj->GetInstanceId());
- assert(false);
- }
- return(map);
+ assert(obj->GetMapId() == GetId() && obj->GetInstanceId());
+ return _FindMap(obj->GetInstanceId());
}
- else
+
+ Player* player = (Player*)obj;
+ uint32 instanceId = player->GetInstanceId();
+
+ if(instanceId)
+ if(Map *map = _FindMap(instanceId))
+ return map;
+
+ if(IsBattleGroundOrArena())
{
- // instance not specified, find an existing or create a new one
- if(obj->GetTypeId() != TYPEID_PLAYER)
+ instanceId = player->GetBattleGroundId();
+
+ if(instanceId)
{
- sLog.outError("MAPINSTANCED: WorldObject '%u' (Entry: %u TypeID: %u) is in map %d,%d and requested base map instance of map %d, this must not happen", obj->GetGUIDLow(), obj->GetEntry(), obj->GetTypeId(), obj->GetMapId(), obj->GetInstanceId(), GetId());
- assert(false);
- return NULL;
+ if(Map *map = _FindMap(instanceId))
+ return map;
+ else
+ return CreateBattleGround(instanceId);
}
else
+ return NULL;
+ }
+
+ InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty());
+ InstanceSave *pSave = pBind ? pBind->save : NULL;
+ if(!pBind || !pBind->perm)
+ {
+ if(Group *group = player->GetGroup())
+ if(InstanceGroupBind *groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty()))
+ pSave = groupBind->save;
+ }
+
+ if(pSave)
+ {
+ if(!instanceId)
{
- uint32 NewInstanceId = 0; // instanceId of the resulting map
- Player* player = (Player*)obj;
-
- if(IsBattleGroundOrArena())
- {
- // instantiate or find existing bg map for player
- // the instance id is set in battlegroundid
- NewInstanceId = player->GetBattleGroundId();
- if(!NewInstanceId)
- {
- if(player->GetSession()->PlayerLoading())
- return NULL;
- else
- assert(NewInstanceId);
- }
- map = _FindMap(NewInstanceId);
- if(!map)
- map = CreateBattleGround(NewInstanceId);
- return map;
- }
-
- InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty());
- InstanceSave *pSave = pBind ? pBind->save : NULL;
-
- // the player's permanet player bind is taken into consideration first
- // then the player's group bind and finally the solo bind.
- if(!pBind || !pBind->perm)
- {
- InstanceGroupBind *groupBind = NULL;
- Group *group = player->GetGroup();
- // use the player's difficulty setting (it may not be the same as the group's)
- if(group && (groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty())))
- pSave = groupBind->save;
- }
-
- if(pSave)
- {
- // solo/perm/group
- NewInstanceId = pSave->GetInstanceId();
- map = _FindMap(NewInstanceId);
- // it is possible that the save exists but the map doesn't
- if(!map)
- map = CreateInstance(NewInstanceId, pSave, pSave->GetDifficulty());
+ instanceId = pSave->GetInstanceId(); // go from outside to instance
+ if(Map *map = _FindMap(instanceId))
return map;
- }
- else if(!player->GetSession()->PlayerLoading())
- {
- // if no instanceId via group members or instance saves is found
- // the instance will be created for the first time
- NewInstanceId = MapManager::Instance().GenerateInstanceId();
- return CreateInstance(NewInstanceId, NULL, player->GetDifficulty());
- }
- else
- {
- sLog.outError("MAPINSTANCED: Player %s is trying to create instance (MapId %u) when login.", player->GetName(), player->GetMapId());
- return NULL;
- }
}
+ else if(instanceId != pSave->GetInstanceId()) // cannot go from one instance to another
+ return NULL;
+ // else log in at a saved instance
+
+ return CreateInstance(instanceId, pSave, pSave->GetDifficulty());
+ }
+ else if(!player->GetSession()->PlayerLoading())
+ {
+ if(!instanceId)
+ instanceId = MapManager::Instance().GenerateInstanceId();
+
+ return CreateInstance(instanceId, NULL, player->GetDifficulty());
}
+
+ return NULL;
}
InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty)
@@ -221,7 +194,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save,
}
// some instances only have one difficulty
- if(!entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL;
+ if (entry && !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL;
sLog.outDebug("MapInstanced::CreateInstance: %smap instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal");
diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h
index d34a5cf2dfb..70e59065577 100644
--- a/src/game/MapInstanced.h
+++ b/src/game/MapInstanced.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -52,7 +52,7 @@ class TRINITY_DLL_DECL MapInstanced : public Map
SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), true);
}
- void RemoveGridMapReference(const GridPair &p)
+ void RemoveGridMapReference(GridPair const& p)
{
--GridMapReference[p.x_coord][p.y_coord];
if (!GridMapReference[p.x_coord][p.y_coord])
diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp
index 6a8cd130691..d75ba22b19a 100644
--- a/src/game/MapManager.cpp
+++ b/src/game/MapManager.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,10 +32,11 @@
#include "CellImpl.h"
#include "Corpse.h"
#include "ObjectMgr.h"
+#include "Language.h"
-#define CLASS_LOCK Trinity::ClassLevelLockable<MapManager, ZThread::Mutex>
+#define CLASS_LOCK MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex>
INSTANTIATE_SINGLETON_2(MapManager, CLASS_LOCK);
-INSTANTIATE_CLASS_MUTEX(MapManager, ZThread::Mutex);
+INSTANTIATE_CLASS_MUTEX(MapManager, ACE_Thread_Mutex);
extern GridState* si_GridStates[]; // debugging code, should be deleted some day
@@ -165,7 +166,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player)
{
// probably there must be special opcode, because client has this string constant in GlobalStrings.lua
// TODO: this is not a good place to send the message
- player->GetSession()->SendAreaTriggerMessage(player->GetSession()->GetTrinityString(810), mapName);
+ player->GetSession()->SendAreaTriggerMessage(player->GetSession()->GetTrinityString(LANG_INSTANCE_RAID_GROUP_ONLY), mapName);
sLog.outDebug("MAP: Player '%s' must be in a raid group to enter instance of '%s'", player->GetName(), mapName);
return false;
}
@@ -175,7 +176,8 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player)
//The player has a heroic mode and tries to enter into instance which has no a heroic mode
if (!entry->SupportsHeroicMode() && player->GetDifficulty() == DIFFICULTY_HEROIC)
{
- player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY2); //Send aborted message
+ //Send aborted message
+ player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, DIFFICULTY_HEROIC);
return false;
}
@@ -213,7 +215,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player)
InstanceTemplate const* instance = objmgr.GetInstanceTemplate(mapid);
if(!instance)
return false;
-
+
return player->Satisfy(objmgr.GetAccessRequirement(instance->access_id), mapid, true);
}
else
@@ -238,7 +240,7 @@ void MapManager::RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y)
}
void
-MapManager::Update(time_t diff)
+MapManager::Update(uint32 diff)
{
i_timer.Update(diff);
if( !i_timer.Passed() )
@@ -284,7 +286,8 @@ bool MapManager::ExistMapAndVMap(uint32 mapid, float x,float y)
bool MapManager::IsValidMAP(uint32 mapid)
{
MapEntry const* mEntry = sMapStore.LookupEntry(mapid);
- return mEntry && (!mEntry->Instanceable() || objmgr.GetInstanceTemplate(mapid));
+ return mEntry && (!mEntry->IsDungeon() || objmgr.GetInstanceTemplate(mapid));
+ // TODO: add check for battleground template
}
/*void MapManager::LoadGrid(int mapid, float x, float y, const WorldObject* obj, bool no_unload)
diff --git a/src/game/MapManager.h b/src/game/MapManager.h
index ce2e9ab012b..b54c1cfbfa1 100644
--- a/src/game/MapManager.h
+++ b/src/game/MapManager.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,14 +23,14 @@
#include "Platform/Define.h"
#include "Policies/Singleton.h"
-#include "zthread/Mutex.h"
+#include "ace/Thread_Mutex.h"
#include "Common.h"
#include "Map.h"
#include "GridStates.h"
class Transport;
-class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinity::ClassLevelLockable<MapManager, ZThread::Mutex> >
+class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex> >
{
friend class Trinity::OperatorNew<MapManager>;
@@ -47,18 +47,28 @@ class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinit
Map const* GetBaseMap(uint32 id) const { return const_cast<MapManager*>(this)->_GetBaseMap(id); }
void DeleteInstance(uint32 mapid, uint32 instanceId);
- inline uint16 GetAreaFlag(uint32 mapid, float x, float y) const
+ uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const
{
Map const* m = GetBaseMap(mapid);
- return m->GetAreaFlag(x, y);
+ return m->GetAreaFlag(x, y, z);
+ }
+ uint32 GetAreaId(uint32 mapid, float x, float y, float z) const
+ {
+ return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid);
+ }
+ uint32 GetZoneId(uint32 mapid, float x, float y, float z) const
+ {
+ return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid);
+ }
+ void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)
+ {
+ Map::GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(mapid, x, y, z),mapid);
}
- inline uint32 GetAreaId(uint32 mapid, float x, float y) { return Map::GetAreaId(GetAreaFlag(mapid, x, y),mapid); }
- inline uint32 GetZoneId(uint32 mapid, float x, float y) { return Map::GetZoneId(GetAreaFlag(mapid, x, y),mapid); }
void Initialize(void);
- void Update(time_t);
+ void Update(uint32);
- inline void SetGridCleanUpDelay(uint32 t)
+ void SetGridCleanUpDelay(uint32 t)
{
if( t < MIN_GRID_DELAY )
i_gridCleanUpDelay = MIN_GRID_DELAY;
@@ -66,7 +76,7 @@ class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinit
i_gridCleanUpDelay = t;
}
- inline void SetMapUpdateInterval(uint32 t)
+ void SetMapUpdateInterval(uint32 t)
{
if( t > MIN_MAP_UPDATE_DELAY )
t = MIN_MAP_UPDATE_DELAY;
@@ -96,6 +106,11 @@ class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinit
return IsValidMAP(mapid) && Trinity::IsValidMapCoord(x,y,z,o);
}
+ static bool IsValidMapCoord(WorldLocation const& loc)
+ {
+ return IsValidMapCoord(loc.mapid,loc.x,loc.y,loc.z,loc.o);
+ }
+
void DoDelayedMovesAndRemoves();
void LoadTransports();
@@ -108,7 +123,7 @@ class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinit
bool CanPlayerEnter(uint32 mapid, Player* player);
void RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y);
- inline uint32 GenerateInstanceId() { return ++i_MaxInstanceId; }
+ uint32 GenerateInstanceId() { return ++i_MaxInstanceId; }
void InitMaxInstanceId();
/* statistics */
@@ -134,7 +149,7 @@ class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinit
return (iter == i_maps.end() ? NULL : iter->second);
}
- typedef Trinity::ClassLevelLockable<MapManager, ZThread::Mutex>::Lock Guard;
+ typedef MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex>::Lock Guard;
uint32 i_gridCleanUpDelay;
MapMapType i_maps;
IntervalTimer i_timer;
diff --git a/src/game/MapRefManager.h b/src/game/MapRefManager.h
index cf8170a7bb3..4337aa75fd9 100644
--- a/src/game/MapRefManager.h
+++ b/src/game/MapRefManager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/MapReference.h b/src/game/MapReference.h
index 50a7dcea5a4..ae485af7487 100644
--- a/src/game/MapReference.h
+++ b/src/game/MapReference.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index 1bed4c6a483..f7c53e536c4 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,15 +37,16 @@
#include "Chat.h"
#include "ScriptCalls.h"
#include <zlib/zlib.h>
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Object.h"
#include "BattleGround.h"
#include "OutdoorPvP.h"
-#include "SpellAuras.h"
#include "Pet.h"
#include "SocialMgr.h"
#include "CellImpl.h"
+#include "AccountMgr.h"
+#include "Vehicle.h"
+#include "CreatureAI.h"
void WorldSession::HandleRepopRequestOpcode( WorldPacket & /*recv_data*/ )
{
@@ -97,7 +98,7 @@ void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
GameObject *go = NULL;
if(IS_CREATURE_GUID(guid))
{
- unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE);
+ unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!unit)
{
sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -106,7 +107,7 @@ void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
}
else if(IS_GAMEOBJECT_GUID(guid))
{
- go = ObjectAccessor::GetGameObject(*_player, guid);
+ go = _player->GetMap()->GetGameObject(guid);
if (!go)
{
sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - GameObject (GUID: %u) not found.", uint32(GUID_LOPART(guid)) );
@@ -121,7 +122,7 @@ void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if(!code.empty())
{
@@ -180,7 +181,7 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
// recheck
CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4);
- for(uint32 i = 0; i < zones_count; i++)
+ for(uint32 i = 0; i < zones_count; ++i)
{
uint32 temp;
recv_data >> temp; // zone id, 0 if zone is unknown...
@@ -199,7 +200,7 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
sLog.outDebug("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count);
std::wstring str[4]; // 4 is client limit
- for(uint32 i = 0; i < str_count; i++)
+ for(uint32 i = 0; i < str_count; ++i)
{
// recheck (have one more byte)
CHECK_PACKET_SIZE(recv_data,recv_data.rpos());
@@ -238,7 +239,7 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
//TODO: Guard Player map
HashMapHolder<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();
- for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
+ for(HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)
{
if (security == SEC_PLAYER)
{
@@ -273,7 +274,7 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
uint32 pzoneid = itr->second->GetZoneId();
bool z_show = true;
- for(uint32 i = 0; i < zones_count; i++)
+ for(uint32 i = 0; i < zones_count; ++i)
{
if(zoneids[i] == pzoneid)
{
@@ -309,7 +310,7 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
aname = areaEntry->area_name[GetSessionDbcLocale()];
bool s_show = true;
- for(uint32 i = 0; i < str_count; i++)
+ for(uint32 i = 0; i < str_count; ++i)
{
if (!str[i].empty())
{
@@ -357,7 +358,7 @@ void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
//Can not logout if...
if( GetPlayer()->isInCombat() || //...is in combat
GetPlayer()->duel || //...is in Duel
- GetPlayer()->HasAura(9454,0) || //...is frozen by GM via freeze command
+ GetPlayer()->HasAura(9454) || //...is frozen by GM via freeze command
//...is jumping ...is falling
GetPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING))
{
@@ -381,13 +382,13 @@ void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
// not set flags if player can't free move to prevent lost state at logout cancel
if(GetPlayer()->CanFreeMove())
{
- GetPlayer()->SetStandState(PLAYER_STATE_SIT);
+ GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT);
WorldPacket data( SMSG_FORCE_MOVE_ROOT, (8+4) ); // guess size
data.append(GetPlayer()->GetPackGUID());
data << (uint32)2;
SendPacket( &data );
- GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
}
WorldPacket data( SMSG_LOGOUT_RESPONSE, 5 );
@@ -421,10 +422,10 @@ void WorldSession::HandleLogoutCancelOpcode( WorldPacket & /*recv_data*/ )
SendPacket( &data );
//! Stand Up
- GetPlayer()->SetStandState(PLAYER_STATE_NONE);
+ GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND);
//! DISABLE_ROTATE
- GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
}
sLog.outDebug( "WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message" );
@@ -438,10 +439,12 @@ void WorldSession::HandleTogglePvP( WorldPacket & recv_data )
bool newPvPStatus;
recv_data >> newPvPStatus;
GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus);
+ GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER, !newPvPStatus);
}
else
{
GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP);
+ GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER);
}
if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
@@ -470,9 +473,11 @@ void WorldSession::HandleZoneUpdateOpcode( WorldPacket & recv_data )
sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone);
- GetPlayer()->UpdateZone(newZone);
-
- GetPlayer()->SendInitWorldStates(true,newZone);
+ // use server size data
+ uint32 newzone, newarea;
+ GetPlayer()->GetZoneAndAreaId(newzone,newarea);
+ GetPlayer()->UpdateZone(newzone,newarea);
+ //GetPlayer()->SendInitWorldStates(true,newZone);
}
void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data )
@@ -490,7 +495,8 @@ void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data )
if(!unit)
return;
- _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
+ if(FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction()))
+ _player->GetReputationMgr().SetVisible(factionTemplateEntry);
}
void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
@@ -507,7 +513,8 @@ void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
if(!unit)
return;
- _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
+ if(FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction()))
+ _player->GetReputationMgr().SetVisible(factionTemplateEntry);
}
void WorldSession::HandleStandStateChangeOpcode( WorldPacket & recv_data )
@@ -555,20 +562,21 @@ void WorldSession::HandleAddFriendOpcode( WorldPacket & recv_data )
sLog.outDebug( "WORLD: %s asked to add friend : '%s'",
GetPlayer()->GetName(), friendName.c_str() );
- CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race FROM characters WHERE name = '%s'", friendName.c_str());
+ CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race, account FROM characters WHERE name = '%s'", friendName.c_str());
}
void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult *result, uint32 accountId, std::string friendNote)
{
uint64 friendGuid;
+ uint64 friendAcctid;
uint32 team;
FriendsResult friendResult;
-
+
WorldSession * session = sWorld.FindSession(accountId);
if(!session || !session->GetPlayer())
return;
-
+
friendResult = FRIEND_NOT_FOUND;
friendGuid = 0;
@@ -576,30 +584,33 @@ void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult *result, uint32 acc
{
friendGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
team = Player::TeamForRace((*result)[1].GetUInt8());
+ friendAcctid = (*result)[2].GetUInt32();
delete result;
- if(friendGuid)
+ if ( session->GetSecurity() >= SEC_MODERATOR || sWorld.getConfig(CONFIG_ALLOW_GM_FRIEND) || accmgr.GetSecurity(friendAcctid) < SEC_MODERATOR)
{
- if(friendGuid==session->GetPlayer()->GetGUID())
- friendResult = FRIEND_SELF;
- else if(session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR)
- friendResult = FRIEND_ENEMY;
- else if(session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
- friendResult = FRIEND_ALREADY;
- else
+ if(friendGuid)
{
- Player* pFriend = ObjectAccessor::FindPlayer(friendGuid);
- if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer()))
- friendResult = FRIEND_ADDED_ONLINE;
+ if(friendGuid==session->GetPlayer()->GetGUID())
+ friendResult = FRIEND_SELF;
+ else if(session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR)
+ friendResult = FRIEND_ENEMY;
+ else if(session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
+ friendResult = FRIEND_ALREADY;
else
- friendResult = FRIEND_ADDED_OFFLINE;
- if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
{
- friendResult = FRIEND_LIST_FULL;
- sLog.outDebug( "WORLD: %s's friend list is full.", session->GetPlayer()->GetName());
+ Player* pFriend = ObjectAccessor::FindPlayer(friendGuid);
+ if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer()))
+ friendResult = FRIEND_ADDED_ONLINE;
+ else
+ friendResult = FRIEND_ADDED_OFFLINE;
+ if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
+ {
+ friendResult = FRIEND_LIST_FULL;
+ sLog.outDebug( "WORLD: %s's friend list is full.", session->GetPlayer()->GetName());
+ }
}
-
session->GetPlayer()->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote);
}
}
@@ -652,12 +663,12 @@ void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult *result, uint32 acc
{
uint64 IgnoreGuid;
FriendsResult ignoreResult;
-
+
WorldSession * session = sWorld.FindSession(accountId);
if(!session || !session->GetPlayer())
return;
-
+
ignoreResult = FRIEND_IGNORE_NOT_FOUND;
IgnoreGuid = 0;
@@ -676,7 +687,7 @@ void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult *result, uint32 acc
else
{
ignoreResult = FRIEND_IGNORE_ADDED;
-
+
// ignore list full
if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true))
ignoreResult = FRIEND_IGNORE_FULL;
@@ -769,9 +780,7 @@ void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data)
if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL))
return;
- float dist = corpse->GetDistance2d(GetPlayer());
- sLog.outDebug("Corpse 2D Distance: \t%f",dist);
- if (dist > CORPSE_RECLAIM_RADIUS)
+ if (!corpse->IsWithinDist(GetPlayer(),CORPSE_RECLAIM_RADIUS,false))
return;
uint64 guid;
@@ -903,7 +912,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
GetPlayer()->SetRestType(REST_TYPE_IN_TAVERN);
if(sWorld.IsFFAPvPRealm())
- GetPlayer()->RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
+ GetPlayer()->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
return;
}
@@ -935,16 +944,96 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,TELE_TO_NOT_LEAVE_TRANSPORT);
}
-void WorldSession::HandleUpdateAccountData(WorldPacket &/*recv_data*/)
+void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data)
{
sLog.outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA");
- //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4+4+4);
+
+ uint32 type, timestamp, decompressedSize;
+ recv_data >> type >> timestamp >> decompressedSize;
+
+ sLog.outDebug("UAD: type %u, time %u, decompressedSize %u", type, timestamp, decompressedSize);
+
+ if(type > NUM_ACCOUNT_DATA_TYPES)
+ return;
+
+ if(decompressedSize == 0) // erase
+ {
+ SetAccountData(type, 0, "");
+
+ WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4);
+ data << uint32(type);
+ data << uint32(0);
+ SendPacket(&data);
+
+ return;
+ }
+
+ if(decompressedSize > 0xFFFF)
+ {
+ sLog.outError("UAD: Account data packet too big, size %u", decompressedSize);
+ return;
+ }
+
+ ByteBuffer dest;
+ dest.resize(decompressedSize);
+
+ uLongf realSize = decompressedSize;
+ if(uncompress(const_cast<uint8*>(dest.contents()), &realSize, const_cast<uint8*>(recv_data.contents() + recv_data.rpos()), recv_data.size() - recv_data.rpos()) != Z_OK)
+ {
+ sLog.outError("UAD: Failed to decompress account data");
+ return;
+ }
+
+ std::string adata;
+ dest >> adata;
+
+ SetAccountData(type, timestamp, adata);
+
+ WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4);
+ data << uint32(type);
+ data << uint32(0);
+ SendPacket(&data);
}
-void WorldSession::HandleRequestAccountData(WorldPacket& /*recv_data*/)
+void WorldSession::HandleRequestAccountData(WorldPacket& recv_data)
{
sLog.outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA");
- //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ uint32 type;
+ recv_data >> type;
+
+ sLog.outDebug("RAD: type %u", type);
+
+ if(type > NUM_ACCOUNT_DATA_TYPES)
+ return;
+
+ AccountData *adata = GetAccountData(type);
+
+ uint32 size = adata->Data.size();
+
+ ByteBuffer dest;
+ dest.resize(size);
+
+ uLongf destSize = size;
+ if(size && compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK)
+ {
+ sLog.outDebug("RAD: Failed to compress account data");
+ return;
+ }
+
+ dest.resize(destSize);
+
+ WorldPacket data (SMSG_UPDATE_ACCOUNT_DATA, 8+4+4+4+destSize);
+ data << uint64(_player->GetGUID()); // player guid
+ data << uint32(type); // type (0-7)
+ data << uint32(adata->Time); // unix time
+ data << uint32(size); // decompressed length
+ data.append(dest); // compressed data
+ SendPacket(&data);
}
void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
@@ -971,7 +1060,7 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
}
else if(type==ACTION_BUTTON_SPELL)
{
- sLog.outDetail( "MISC: Added Action %u into button %u", action, button );
+ sLog.outDetail( "MISC: Added Spell %u into button %u", action, button );
GetPlayer()->addActionButton(button,action,type,misc);
}
else if(type==ACTION_BUTTON_ITEM)
@@ -1088,22 +1177,6 @@ void WorldSession::HandleMoveRootAck(WorldPacket&/* recv_data*/)
*/
}
-void WorldSession::HandleMoveTeleportAck(WorldPacket&/* recv_data*/)
-{
- /*
- CHECK_PACKET_SIZE(recv_data,8+4);
-
- sLog.outDebug("MSG_MOVE_TELEPORT_ACK");
- uint64 guid;
- uint32 flags, time;
-
- recv_data >> guid;
- recv_data >> flags >> time;
- DEBUG_LOG("Guid " I64FMTD,guid);
- DEBUG_LOG("Flags %u, time %u",flags, time/1000);
- */
-}
-
void WorldSession::HandleSetActionBar(WorldPacket& recv_data)
{
CHECK_PACKET_SIZE(recv_data,1);
@@ -1191,7 +1264,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
// find talent rank
uint32 curtalent_maxrank = 0;
- for(uint32 k = 5; k > 0; --k)
+ for(uint32 k = MAX_TALENT_RANK; k > 0; --k)
{
if(talentInfo->RankID[k-1] && plr->HasSpell(talentInfo->RankID[k-1]))
{
@@ -1363,7 +1436,10 @@ void WorldSession::HandleReportSpamOpcode( WorldPacket & recv_data )
uint8 spam_type; // 0 - mail, 1 - chat
uint64 spammer_guid;
- uint32 unk1, unk2, unk3, unk4 = 0;
+ uint32 unk1 = 0;
+ uint32 unk2 = 0;
+ uint32 unk3 = 0;
+ uint32 unk4 = 0;
std::string description = "";
recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat)
recv_data >> spammer_guid; // player guid
@@ -1428,22 +1504,18 @@ void WorldSession::HandleFarSightOpcode( WorldPacket & recv_data )
uint8 apply;
recv_data >> apply;
- CellPair pair;
-
switch(apply)
{
case 0:
- _player->SetFarsightVision(false);
- pair = Trinity::ComputeCellPair(_player->GetPositionX(), _player->GetPositionY());
- sLog.outDebug("Player %u set vision to himself", _player->GetGUIDLow());
+ sLog.outDebug("Player %u set vision to self", _player->GetGUIDLow());
+ _player->SetSeer(_player);
break;
case 1:
- _player->SetFarsightVision(true);
- if (WorldObject* obj = _player->GetFarsightTarget())
- pair = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
+ sLog.outDebug("Added FarSight " I64FMT " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow());
+ if(WorldObject *target = _player->GetViewpoint())
+ _player->SetSeer(target);
else
- return;
- sLog.outDebug("Added FarSight " I64FMT " to player %u", _player->GetFarSight(), _player->GetGUIDLow());
+ sLog.outError("Player %s requests non-existing seer", _player->GetName());
break;
default:
sLog.outDebug("Unhandled mode in CMSG_FAR_SIGHT: %u", apply);
@@ -1476,11 +1548,11 @@ void WorldSession::HandleChooseTitleOpcode( WorldPacket & recv_data )
GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title);
}
-void WorldSession::HandleAllowMoveAckOpcode( WorldPacket & recv_data )
+void WorldSession::HandleTimeSyncResp( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data, 4+4);
- sLog.outDebug("CMSG_ALLOW_MOVE_ACK");
+ sLog.outDebug("CMSG_TIME_SYNC_RESP");
uint32 counter, time_;
recv_data >> counter >> time_;
@@ -1550,26 +1622,6 @@ void WorldSession::HandleDungeonDifficultyOpcode( WorldPacket & recv_data )
}
}
-void WorldSession::HandleNewUnknownOpcode( WorldPacket & recv_data )
-{
- sLog.outDebug("New Unknown Opcode %u", recv_data.GetOpcode());
- recv_data.hexlike();
- /*
- New Unknown Opcode 837
- STORAGE_SIZE: 60
- 02 00 00 00 00 00 00 00 | 00 00 00 00 01 20 00 00
- 89 EB 33 01 71 5C 24 C4 | 15 03 35 45 74 47 8B 42
- BA B8 1B 40 00 00 00 00 | 00 00 00 00 77 66 42 BF
- 23 91 26 3F 00 00 60 41 | 00 00 00 00
-
- New Unknown Opcode 837
- STORAGE_SIZE: 44
- 02 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
- 7B 80 34 01 84 EA 2B C4 | 5F A1 36 45 C9 39 1C 42
- BA B8 1B 40 CE 06 00 00 | 00 00 80 3F
- */
-}
-
void WorldSession::HandleDismountOpcode( WorldPacket & /*recv_data*/ )
{
sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA");
@@ -1589,7 +1641,7 @@ void WorldSession::HandleDismountOpcode( WorldPacket & /*recv_data*/ )
}
_player->Unmount();
- _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+ _player->RemoveAurasByType(SPELL_AURA_MOUNTED);
}
void WorldSession::HandleMoveFlyModeChangeAckOpcode( WorldPacket & recv_data )
@@ -1637,3 +1689,16 @@ void WorldSession::HandleSetTaxiBenchmarkOpcode( WorldPacket & recv_data )
sLog.outDebug("Client used \"/timetest %d\" command", mode);
}
+void WorldSession::HandleInspectAchievements( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 1);
+ uint64 guid;
+ if(!recv_data.readPackGUID(guid))
+ return;
+
+ Player *player = objmgr.GetPlayer(guid);
+ if(!player)
+ return;
+
+ player->GetAchievementMgr().SendRespondInspectAchievements(_player);
+}
diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp
index 9beecf9c5cf..3a7832fe914 100644
--- a/src/game/MotionMaster.cpp
+++ b/src/game/MotionMaster.cpp
@@ -50,17 +50,20 @@ MotionMaster::Initialize()
if(curr) DirectDelete(curr);
}
- // set new default movement generator
+ InitDefault();
+}
+
+// set new default movement generator
+void MotionMaster::InitDefault()
+{
if(i_owner->GetTypeId() == TYPEID_UNIT)
{
MovementGenerator* movement = FactorySelector::selectMovementGenerator((Creature*)i_owner);
- push( movement == NULL ? &si_idleMovement : movement );
- InitTop();
+ Mutate(movement == NULL ? &si_idleMovement : movement, MOTION_SLOT_IDLE);
}
else
{
- push(&si_idleMovement);
- needInit[MOTION_SLOT_IDLE] = false;
+ Mutate(&si_idleMovement, MOTION_SLOT_IDLE);
}
}
@@ -200,25 +203,11 @@ MotionMaster::MoveTargetedHome()
Clear(false);
- if(i_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)i_owner)->GetCharmerOrOwnerGUID())
+ if(i_owner->GetTypeId() == TYPEID_UNIT)
{
DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow());
Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE);
}
- else if(i_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)i_owner)->GetCharmerOrOwnerGUID())
- {
- DEBUG_LOG("Pet or controlled creature (Entry: %u GUID: %u) targeting home",
- i_owner->GetEntry(), i_owner->GetGUIDLow() );
- Unit *target = ((Creature*)i_owner)->GetCharmerOrOwner();
- if(target)
- {
- i_owner->addUnitState(UNIT_STAT_FOLLOW);
- DEBUG_LOG("Following %s (GUID: %u)",
- target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
- target->GetTypeId()==TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() );
- Mutate(new TargetedMovementGenerator<Creature>(*target,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE);
- }
- }
else
{
sLog.outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow() );
@@ -268,7 +257,7 @@ MotionMaster::MoveChase(Unit* target, float dist, float angle)
}
void
-MotionMaster::MoveFollow(Unit* target, float dist, float angle)
+MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlot slot)
{
// ignore movement request if target not exist
if(!target || target == i_owner)
@@ -280,7 +269,7 @@ MotionMaster::MoveFollow(Unit* target, float dist, float angle)
DEBUG_LOG("Player (GUID: %u) follow to %s (GUID: %u)", i_owner->GetGUIDLow(),
target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId()==TYPEID_PLAYER ? i_owner->GetGUIDLow() : ((Creature*)i_owner)->GetDBTableGUIDLow() );
- Mutate(new TargetedMovementGenerator<Player>(*target,dist,angle), MOTION_SLOT_ACTIVE);
+ Mutate(new TargetedMovementGenerator<Player>(*target,dist,angle), slot);
}
else
{
@@ -288,7 +277,7 @@ MotionMaster::MoveFollow(Unit* target, float dist, float angle)
i_owner->GetEntry(), i_owner->GetGUIDLow(),
target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId()==TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() );
- Mutate(new TargetedMovementGenerator<Creature>(*target,dist,angle), MOTION_SLOT_ACTIVE);
+ Mutate(new TargetedMovementGenerator<Creature>(*target,dist,angle), slot);
}
}
@@ -308,13 +297,60 @@ MotionMaster::MovePoint(uint32 id, float x, float y, float z)
}
}
+void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
+{
+ //this function may make players fall below map
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ return;
+
+ float x, y, z;
+ float dist = speedXY * speedZ * 0.1f;
+ i_owner->GetNearPoint(i_owner, x, y, z, i_owner->GetObjectSize(), dist, i_owner->GetAngle(srcX, srcY) + M_PI);
+ MoveJump(x, y, z, speedXY, speedZ);
+}
+
+void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ)
+{
+ //this function may make players fall below map
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ return;
+
+ float x, y, z;
+ float dist = speedXY * speedZ * 0.1f;
+ i_owner->GetClosePoint(x, y, z, i_owner->GetObjectSize(), dist, angle);
+ MoveJump(x, y, z, speedXY, speedZ);
+}
+
+void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ)
+{
+ uint32 moveFlag = MOVEFLAG_JUMP | MOVEFLAG_WALK;
+ uint32 time = speedZ * 100;
+
+ i_owner->addUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
+ i_owner->m_TempSpeed = speedXY;
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ DEBUG_LOG("Player (GUID: %u) jump to point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z );
+ Mutate(new PointMovementGenerator<Player>(0,x,y,z), MOTION_SLOT_CONTROLLED);
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) jump to point (X: %f Y: %f Z: %f)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z );
+ Mutate(new PointMovementGenerator<Creature>(0,x,y,z), MOTION_SLOT_CONTROLLED);
+ }
+
+ i_owner->SendMonsterMove(x, y, z, moveFlag, time, speedZ);
+}
+
void
-MotionMaster::MoveCharge(float x, float y, float z)
+MotionMaster::MoveCharge(float x, float y, float z, float speed)
{
if(Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
return;
i_owner->addUnitState(UNIT_STAT_CHARGING);
+ i_owner->m_TempSpeed = speed;
if(i_owner->GetTypeId()==TYPEID_PLAYER)
{
DEBUG_LOG("Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z );
@@ -329,7 +365,39 @@ MotionMaster::MoveCharge(float x, float y, float z)
}
void
-MotionMaster::MoveFleeing(Unit* enemy)
+MotionMaster::MoveSeekAssistance(float x, float y, float z)
+{
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ sLog.outError("Player (GUID: %u) attempt to seek assistance",i_owner->GetGUIDLow());
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) seek assistance (X: %f Y: %f Z: %f)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z );
+ i_owner->AttackStop();
+ ((Creature*)i_owner)->SetReactState(REACT_PASSIVE);
+ Mutate(new AssistanceMovementGenerator(x,y,z), MOTION_SLOT_ACTIVE);
+ }
+}
+
+void
+MotionMaster::MoveSeekAssistanceDistract(uint32 time)
+{
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ sLog.outError("Player (GUID: %u) attempt to call distract after assistance",i_owner->GetGUIDLow());
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) is distracted after assistance call (Time: %u)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(), time );
+ Mutate(new AssistanceDistractMovementGenerator(time), MOTION_SLOT_ACTIVE);
+ }
+}
+
+void
+MotionMaster::MoveFleeing(Unit* enemy, uint32 time)
{
if(!enemy)
return;
@@ -346,11 +414,15 @@ MotionMaster::MoveFleeing(Unit* enemy)
}
else
{
- DEBUG_LOG("Creature (Entry: %u GUID: %u) flee from %s (GUID: %u)",
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) flee from %s (GUID: %u)%s",
i_owner->GetEntry(), i_owner->GetGUIDLow(),
enemy->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
- enemy->GetTypeId()==TYPEID_PLAYER ? enemy->GetGUIDLow() : ((Creature*)enemy)->GetDBTableGUIDLow() );
- Mutate(new FleeingMovementGenerator<Creature>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED);
+ enemy->GetTypeId()==TYPEID_PLAYER ? enemy->GetGUIDLow() : ((Creature*)enemy)->GetDBTableGUIDLow(),
+ time ? " for a limited time" : "");
+ if (time)
+ Mutate(new TimedFleeingMovementGenerator(enemy->GetGUID(), time), MOTION_SLOT_CONTROLLED);
+ else
+ Mutate(new FleeingMovementGenerator<Creature>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED);
}
}
@@ -394,6 +466,7 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot)
{
if(MovementGenerator *curr = Impl[slot])
{
+ Impl[slot] = NULL; // in case a new one is generated in this slot during directdelete
if(i_top == slot && (m_cleanFlag & MMCF_UPDATE))
DelayedDelete(curr);
else
@@ -484,7 +557,7 @@ void MotionMaster::DirectDelete(_Ty curr)
void MotionMaster::DelayedDelete(_Ty curr)
{
- sLog.outError("CRASH ALARM! Unit (Entry %u) is trying to delete its updating MG (Type %u)!", i_owner->GetEntry(), curr->GetMovementGeneratorType());
+ sLog.outCrash("Unit (Entry %u) is trying to delete its updating MG (Type %u)!", i_owner->GetEntry(), curr->GetMovementGeneratorType());
if(isStatic(curr))
return;
if(!m_expList)
@@ -494,9 +567,9 @@ void MotionMaster::DelayedDelete(_Ty curr)
bool MotionMaster::GetDestination(float &x, float &y, float &z)
{
- if(empty())
+ if(empty())
return false;
-
- return top()->GetDestination(x,y,z);
+
+ return top()->GetDestination(x,y,z);
}
diff --git a/src/game/MotionMaster.h b/src/game/MotionMaster.h
index d68a94b7a1f..be2960624cd 100644
--- a/src/game/MotionMaster.h
+++ b/src/game/MotionMaster.h
@@ -45,7 +45,10 @@ enum MovementGeneratorType
POINT_MOTION_TYPE = 8, // PointMovementGenerator.h
FLEEING_MOTION_TYPE = 9, // FleeingMovementGenerator.h
DISTRACT_MOTION_TYPE = 10, // IdleMovementGenerator.h
- NULL_MOTION_TYPE = 11,
+ ASSISTANCE_MOTION_TYPE= 11, // PointMovementGenerator.h (first part of flee for assistance)
+ ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h (second part of flee for assistance)
+ TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h (alt.second part of flee for assistance)
+ NULL_MOTION_TYPE = 14,
};
enum MovementSlot
@@ -63,6 +66,9 @@ enum MMCleanFlag
MMCF_RESET = 2 // Flag if need top()->Reset()
};
+// assume it is 25 yard per 0.6 second
+#define SPEED_CHARGE 42.0f
+
class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *>
{
private:
@@ -73,7 +79,7 @@ class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *>
typedef std::vector<_Ty> ExpireList;
int i_top;
- bool empty() const { return i_top < 0; }
+ bool empty() const { return (i_top < 0); }
void pop() { Impl[i_top] = NULL; --i_top; }
void push(_Ty _Val) { ++i_top; Impl[i_top] = _Val; }
@@ -92,6 +98,7 @@ class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *>
~MotionMaster();
void Initialize();
+ void InitDefault();
int size() const { return i_top + 1; }
_Ty top() const { return Impl[i_top]; }
@@ -131,12 +138,17 @@ class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *>
void MoveIdle(MovementSlot slot = MOTION_SLOT_ACTIVE);
void MoveTargetedHome();
void MoveRandom(float spawndist = 0.0f);
- void MoveFollow(Unit* target, float dist, float angle);
+ void MoveFollow(Unit* target, float dist, float angle, MovementSlot slot = MOTION_SLOT_ACTIVE);
void MoveChase(Unit* target, float dist = 0.0f, float angle = 0.0f);
void MoveConfused();
- void MoveFleeing(Unit* enemy);
+ void MoveFleeing(Unit* enemy, uint32 time = 0);
void MovePoint(uint32 id, float x,float y,float z);
- void MoveCharge(float x, float y, float z);
+ void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE);
+ void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
+ void MoveJumpTo(float angle, float speedXY, float speedZ);
+ void MoveJump(float x, float y, float z, float speedXY, float speedZ);
+ void MoveSeekAssistance(float x,float y,float z);
+ void MoveSeekAssistanceDistract(uint32 timer);
void MoveTaxiFlight(uint32 path, uint32 pathnode);
void MoveDistract(uint32 time);
void MovePath(uint32 path_id, bool repeatable);
diff --git a/src/game/MovementGenerator.cpp b/src/game/MovementGenerator.cpp
index ee314ffae3f..7784df315c9 100644
--- a/src/game/MovementGenerator.cpp
+++ b/src/game/MovementGenerator.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/MovementGenerator.h b/src/game/MovementGenerator.h
index 49d0ce8798a..cb352b7f1c6 100644
--- a/src/game/MovementGenerator.h
+++ b/src/game/MovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/MovementGeneratorImpl.h b/src/game/MovementGeneratorImpl.h
index 7197adb5dfe..fc676704d3a 100644
--- a/src/game/MovementGeneratorImpl.h
+++ b/src/game/MovementGeneratorImpl.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp
index 2eb3bab12e7..53aa5923782 100644
--- a/src/game/MovementHandler.cpp
+++ b/src/game/MovementHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,14 +23,16 @@
#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
-#include "World.h"
#include "Corpse.h"
#include "Player.h"
+#include "Vehicle.h"
+#include "SpellAuras.h"
#include "MapManager.h"
#include "Transports.h"
#include "BattleGround.h"
#include "WaypointMovementGenerator.h"
#include "InstanceSaveMgr.h"
+#include "ObjectMgr.h"
void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & /*recv_data*/ )
{
@@ -40,6 +42,10 @@ void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & /*recv_data*/ )
void WorldSession::HandleMoveWorldportAckOpcode()
{
+ // ignore unexpected far teleports
+ if(!GetPlayer()->IsBeingTeleportedFar())
+ return;
+
// get the teleport destination
WorldLocation &loc = GetPlayer()->GetTeleportDest();
@@ -58,7 +64,7 @@ void WorldSession::HandleMoveWorldportAckOpcode()
if(GetPlayer()->m_InstanceValid == false && !mInstance)
GetPlayer()->m_InstanceValid = true;
- GetPlayer()->SetSemaphoreTeleport(false);
+ GetPlayer()->SetSemaphoreTeleportFar(false);
// relocate the player to the teleport destination
GetPlayer()->SetMapId(loc.mapid);
@@ -78,7 +84,6 @@ void WorldSession::HandleMoveWorldportAckOpcode()
{
sLog.outDebug("WORLD: teleport of player %s (%d) to location %d,%f,%f,%f,%f failed", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.x, loc.y, loc.z, loc.o);
// teleport the player home
- GetPlayer()->SetDontMove(false);
if(!GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()))
{
// the player must always be able to teleport home
@@ -87,6 +92,26 @@ void WorldSession::HandleMoveWorldportAckOpcode()
}
return;
}
+
+ // battleground state prepare (in case join to BG), at relogin/tele player not invited
+ // only add to bg group and object, if the player was invited (else he entered through command)
+ if(_player->InBattleGround())
+ {
+ // cleanup seting if outdated
+ if(!mEntry->IsBattleGroundOrArena())
+ {
+ _player->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
+ // reset destination bg team
+ _player->SetBGTeam(0);
+ }
+ // join to bg case
+ else if(BattleGround *bg = _player->GetBattleGround())
+ {
+ if(_player->IsInvitedForBattleGroundInstance(_player->GetBattleGroundId()))
+ bg->AddPlayer(_player);
+ }
+ }
+
GetPlayer()->SendInitialPacketsAfterAddToMap();
// flight fast teleport case
@@ -95,7 +120,6 @@ void WorldSession::HandleMoveWorldportAckOpcode()
if(!_player->InBattleGround())
{
// short preparations to continue flight
- GetPlayer()->SetDontMove(false);
FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top());
flight->Initialize(*GetPlayer());
return;
@@ -129,113 +153,77 @@ void WorldSession::HandleMoveWorldportAckOpcode()
// mount allow check
if(!mEntry->IsMountAllowed())
- _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
-
- // battleground state prepare
- // only add to bg group and object, if the player was invited (else he entered through command)
- if(_player->InBattleGround() && _player->IsInvitedForBattleGroundInstance(_player->GetBattleGroundId()))
- {
- BattleGround *bg = _player->GetBattleGround();
- if(bg)
- {
- bg->AddPlayer(_player);
- if(bg->GetMapId() == _player->GetMapId()) // we teleported to bg
- {
- // get the team this way, because arenas might 'override' the teams.
- uint32 team = bg->GetPlayerTeam(_player->GetGUID());
- if(!team)
- team = _player->GetTeam();
- if(!bg->GetBgRaid(team)) // first player joined
- {
- Group *group = new Group;
- bg->SetBgRaid(team, group);
- group->Create(_player->GetGUIDLow(), _player->GetName());
- }
- else // raid already exist
- {
- bg->GetBgRaid(team)->AddMember(_player->GetGUID(), _player->GetName());
- }
- }
- }
- }
+ _player->RemoveAurasByType(SPELL_AURA_MOUNTED);
// honorless target
if(GetPlayer()->pvpInfo.inHostileArea)
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
// resummon pet
- if(GetPlayer()->m_temporaryUnsummonedPetNumber)
- {
- Pet* NewPet = new Pet;
- if(!NewPet->LoadPetFromDB(GetPlayer(), 0, GetPlayer()->m_temporaryUnsummonedPetNumber, true))
- delete NewPet;
-
- GetPlayer()->m_temporaryUnsummonedPetNumber = 0;
- }
-
- GetPlayer()->SetDontMove(false);
+ GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
}
-void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
+void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data)
{
- CHECK_PACKET_SIZE(recv_data, 4+1+4+4+4+4+4);
+ CHECK_PACKET_SIZE(recv_data,8+4);
- /* extract packet */
- MovementInfo movementInfo;
- uint32 MovementFlags;
+ sLog.outDebug("MSG_MOVE_TELEPORT_ACK");
+ uint64 guid;
+ uint32 flags, time;
- recv_data >> MovementFlags;
- recv_data >> movementInfo.unk1;
- recv_data >> movementInfo.time;
- recv_data >> movementInfo.x;
- recv_data >> movementInfo.y;
- recv_data >> movementInfo.z;
- recv_data >> movementInfo.o;
+ recv_data >> guid;
+ recv_data >> flags >> time;
+ DEBUG_LOG("Guid " I64FMTD,guid);
+ DEBUG_LOG("Flags %u, time %u",flags, time/IN_MILISECONDS);
- if(MovementFlags & MOVEMENTFLAG_ONTRANSPORT)
- {
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+8+4+4+4+4+4);
-
- recv_data >> movementInfo.t_guid;
- recv_data >> movementInfo.t_x;
- recv_data >> movementInfo.t_y;
- recv_data >> movementInfo.t_z;
- recv_data >> movementInfo.t_o;
- recv_data >> movementInfo.t_time;
- }
+ Unit *mover = _player->m_mover;
+ Player *plMover = mover->GetTypeId()==TYPEID_PLAYER ? (Player*)mover : NULL;
- if(MovementFlags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2))
- {
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4);
+ if(!plMover || !plMover->IsBeingTeleportedNear())
+ return;
- recv_data >> movementInfo.s_pitch; // pitch, -1.55=looking down, 0=looking straight forward, +1.55=looking up
- }
+ if(guid != plMover->GetGUID())
+ return;
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4);
+ plMover->SetSemaphoreTeleportNear(false);
- recv_data >> movementInfo.fallTime; // duration of last jump (when in jump duration from jump begin to now)
+ uint32 old_zone = plMover->GetZoneId();
- if(MovementFlags & MOVEMENTFLAG_JUMPING)
- {
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4+4);
+ WorldLocation const& dest = plMover->GetTeleportDest();
- recv_data >> movementInfo.j_unk; // constant, but different when jumping in water and on land?
- recv_data >> movementInfo.j_sinAngle; // sin of angle between orientation0 and players orientation
- recv_data >> movementInfo.j_cosAngle; // cos of angle between orientation0 and players orientation
- recv_data >> movementInfo.j_xyspeed; // speed of xy movement
- }
+ plMover->SetPosition(dest.x, dest.y, dest.z, dest.o, true);
- if(MovementFlags & MOVEMENTFLAG_SPLINE)
- {
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4);
+ uint32 newzone, newarea;
+ plMover->GetZoneAndAreaId(newzone,newarea);
+ plMover->UpdateZone(newzone,newarea);
- recv_data >> movementInfo.u_unk1; // unknown
+ // new zone
+ if(old_zone != newzone)
+ {
+ // honorless target
+ if(plMover->pvpInfo.inHostileArea)
+ plMover->CastSpell(plMover, 2479, true);
}
+
+ // resummon pet
+ GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
+}
+
+void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
+{
+ uint32 opcode = recv_data.GetOpcode();
+ //sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode);
+
+ Unit *mover = _player->m_mover;
+ Player *plMover = mover->GetTypeId()==TYPEID_PLAYER ? (Player*)mover : NULL;
+
+ // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck
+ if(plMover && plMover->IsBeingTeleported())
+ return;
+
+ /* extract packet */
+ MovementInfo movementInfo;
+ ReadMovementInfo(recv_data, &movementInfo);
/*----------------*/
if(recv_data.size() != recv_data.rpos())
@@ -248,22 +236,8 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
if (!Trinity::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o))
return;
- // Handle possessed unit movement separately
- Unit* pos_unit = GetPlayer()->GetCharm();
- if (pos_unit && pos_unit->isPossessed()) // can be charmed but not possessed
- {
- HandlePossessedMovement(recv_data, movementInfo, MovementFlags);
- return;
- }
-
- if (GetPlayer()->GetDontMove())
- return;
-
- //Save movement flags
- GetPlayer()->SetUnitMovementFlags(MovementFlags);
-
/* handle special cases */
- if (MovementFlags & MOVEMENTFLAG_ONTRANSPORT)
+ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT)
{
// transports size limited
// (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped)
@@ -275,141 +249,115 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
return;
// if we boarded a transport, add us to it
- if (!GetPlayer()->m_transport)
+ if (plMover && !plMover->m_transport)
{
// elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list
- for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
+ for (MapManager::TransportSet::const_iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
{
if ((*iter)->GetGUID() == movementInfo.t_guid)
{
- // unmount before boarding
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
-
- GetPlayer()->m_transport = (*iter);
- (*iter)->AddPassenger(GetPlayer());
+ plMover->m_transport = (*iter);
+ (*iter)->AddPassenger(plMover);
break;
}
}
}
+
+ if(!mover->GetTransport() && !mover->m_Vehicle)
+ movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
}
- else if (GetPlayer()->m_transport) // if we were on a transport, leave
+ else if (plMover && plMover->m_transport) // if we were on a transport, leave
{
- GetPlayer()->m_transport->RemovePassenger(GetPlayer());
- GetPlayer()->m_transport = NULL;
+ plMover->m_transport->RemovePassenger(plMover);
+ plMover->m_transport = NULL;
movementInfo.t_x = 0.0f;
movementInfo.t_y = 0.0f;
movementInfo.t_z = 0.0f;
movementInfo.t_o = 0.0f;
movementInfo.t_time = 0;
+ movementInfo.t_seat = -1;
}
// fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
- if (recv_data.GetOpcode() == MSG_MOVE_FALL_LAND && !GetPlayer()->isInFlight())
- GetPlayer()->HandleFallDamage(movementInfo);
+ if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight())
+ plMover->HandleFall(movementInfo);
- if(((MovementFlags & MOVEMENTFLAG_SWIMMING) != 0) != GetPlayer()->IsInWater())
+ if (plMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater())
{
// now client not include swimming flag in case jumping under water
- GetPlayer()->SetInWater( !GetPlayer()->IsInWater() || GetPlayer()->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) );
+ plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) );
}
/*----------------------*/
/* process position-change */
- recv_data.put<uint32>(5, getMSTime()); // offset flags(4) + unk(1)
- WorldPacket data(recv_data.GetOpcode(), (GetPlayer()->GetPackGUID().size()+recv_data.size()));
- data.append(GetPlayer()->GetPackGUID());
+ recv_data.put<uint32>(6, getMSTime()); // fix time, offset flags(4) + unk(2)
+ WorldPacket data(recv_data.GetOpcode(), (mover->GetPackGUID().size()+recv_data.size()));
+ data.append(mover->GetPackGUID()); // use mover guid
data.append(recv_data.contents(), recv_data.size());
GetPlayer()->SendMessageToSet(&data, false);
- GetPlayer()->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
- GetPlayer()->m_movementInfo = movementInfo;
- if (GetPlayer()->m_lastFallTime >= movementInfo.fallTime || GetPlayer()->m_lastFallZ <=movementInfo.z || recv_data.GetOpcode() == MSG_MOVE_FALL_LAND)
- GetPlayer()->SetFallInformation(movementInfo.fallTime, movementInfo.z);
-
- if(GetPlayer()->isMovingOrTurning())
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
-
- if(movementInfo.z < -500.0f)
- GetPlayer()->HandleFallUnderMap();
-}
+ mover->m_movementInfo = movementInfo;
+ mover->SetUnitMovementFlags(movementInfo.flags);
-void WorldSession::HandlePossessedMovement(WorldPacket& recv_data, MovementInfo& movementInfo, uint32& MovementFlags)
-{
- // Whatever the client is controlling, it will send the GUID of the original player.
- // If current player is controlling, it must be handled like the controlled player sent these opcodes
-
- Unit* pos_unit = GetPlayer()->GetCharm();
-
- if (pos_unit->GetTypeId() == TYPEID_PLAYER && ((Player*)pos_unit)->GetDontMove())
- return;
-
- //Save movement flags
- pos_unit->SetUnitMovementFlags(MovementFlags);
-
- // Remove possession if possessed unit enters a transport
- if (MovementFlags & MOVEMENTFLAG_ONTRANSPORT)
+ if(plMover) // nothing is charmed, or player charmed
{
- GetPlayer()->Uncharm();
- return;
- }
+ plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
+ plMover->UpdateFallInformationIfNeed(movementInfo,recv_data.GetOpcode());
- recv_data.put<uint32>(5, getMSTime());
- WorldPacket data(recv_data.GetOpcode(), pos_unit->GetPackGUID().size()+recv_data.size());
- data.append(pos_unit->GetPackGUID());
- data.append(recv_data.contents(), recv_data.size());
- // Send the packet to self but not to the possessed player; for creatures the first bool is irrelevant
- pos_unit->SendMessageToSet(&data, true, false);
-
- // Possessed is a player
- if (pos_unit->GetTypeId() == TYPEID_PLAYER)
- {
- Player* plr = (Player*)pos_unit;
-
- if (recv_data.GetOpcode() == MSG_MOVE_FALL_LAND)
- plr->HandleFallDamage(movementInfo);
-
- if(((MovementFlags & MOVEMENTFLAG_SWIMMING) != 0) != plr->IsInWater())
- {
- // Now client not include swimming flag in case jumping under water
- plr->SetInWater( !plr->IsInWater() || plr->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) );
- }
-
- plr->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o, false);
- plr->m_movementInfo = movementInfo;
-
- if(plr->isMovingOrTurning())
- plr->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ if(plMover->isMovingOrTurning())
+ plMover->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if(movementInfo.z < -500.0f)
{
- GetPlayer()->Uncharm();
- plr->HandleFallUnderMap();
+ if(plMover->InBattleGround()
+ && plMover->GetBattleGround()
+ && plMover->GetBattleGround()->HandlePlayerUnderMap(_player))
+ {
+ // do nothing, the handle already did if returned true
+ }
+ else
+ {
+ // NOTE: this is actually called many times while falling
+ // even after the player has been teleported away
+ // TODO: discard movement packets after the player is rooted
+ if(plMover->isAlive())
+ {
+ plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
+ // pl can be alive if GM/etc
+ if(!plMover->isAlive())
+ {
+ // change the death state to CORPSE to prevent the death timer from
+ // starting in the next player update
+ plMover->KillPlayer();
+ plMover->BuildPlayerRepop();
+ }
+ }
+
+ // cancel the death timer here if started
+ plMover->RepopAtGraveyard();
+ }
}
}
- else // Possessed unit is a creature
+ else // creature charmed
{
- Map* map = MapManager::Instance().GetMap(pos_unit->GetMapId(), pos_unit);
- map->CreatureRelocation((Creature*)pos_unit, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
+ if(Map *map = mover->GetMap())
+ {
+ map->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
+ }
+ mover->SetUnitMovementFlags(movementInfo.flags);
}
}
void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data)
{
- CHECK_PACKET_SIZE(recv_data, 8+4+4+1+4+4+4+4+4);
+ //sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(recv_data.GetOpcode()), recv_data.GetOpcode(), recv_data.GetOpcode());
+
+ CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+8+4);
/* extract packet */
uint64 guid;
- uint8 unkB;
- uint32 unk1, flags, time, fallTime;
- float x, y, z, orientation;
-
- uint64 t_GUID;
- float t_x, t_y, t_z, t_o;
- uint32 t_time;
- float s_pitch;
- float j_unk1, j_sinAngle, j_cosAngle, j_xyspeed;
- float u_unk1;
+ uint32 unk1;
float newspeed;
recv_data >> guid;
@@ -420,47 +368,10 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data)
// continue parse packet
- recv_data >> unk1;
- recv_data >> flags >> unkB >> time;
- recv_data >> x >> y >> z >> orientation;
- if (flags & MOVEMENTFLAG_ONTRANSPORT)
- {
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+8+4+4+4+4+4);
-
- recv_data >> t_GUID;
- recv_data >> t_x >> t_y >> t_z >> t_o >> t_time;
- }
- if (flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2))
- {
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4);
-
- recv_data >> s_pitch; // pitch, -1.55=looking down, 0=looking straight forward, +1.55=looking up
- }
-
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4);
+ recv_data >> unk1; // counter or moveEvent
- recv_data >> fallTime; // duration of last jump (when in jump duration from jump begin to now)
-
- if ((flags & MOVEMENTFLAG_JUMPING) || (flags & MOVEMENTFLAG_FALLING))
- {
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4+4);
-
- recv_data >> j_unk1; // ?constant, but different when jumping in water and on land?
- recv_data >> j_sinAngle >> j_cosAngle; // sin + cos of angle between orientation0 and players orientation
- recv_data >> j_xyspeed; // speed of xy movement
- }
-
- if(flags & MOVEMENTFLAG_SPLINE)
- {
- // recheck
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4);
-
- recv_data >> u_unk1; // unknown
- }
+ MovementInfo movementInfo;
+ ReadMovementInfo(recv_data, &movementInfo);
// recheck
CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4);
@@ -473,7 +384,7 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data)
UnitMoveType move_type;
UnitMoveType force_move_type;
- static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack" };
+ static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" };
uint16 opcode = recv_data.GetOpcode();
switch(opcode)
@@ -486,6 +397,7 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data)
case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break;
case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break;
case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break;
+ case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break;
default:
sLog.outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode);
return;
@@ -521,19 +433,103 @@ void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data)
{
sLog.outDebug("WORLD: Recvd CMSG_SET_ACTIVE_MOVER");
- CHECK_PACKET_SIZE(recv_data,8);
+ CHECK_PACKET_SIZE(recv_data, 8);
uint64 guid;
recv_data >> guid;
- WorldPacket data(SMSG_TIME_SYNC_REQ, 4); // new 2.0.x, enable movement
- data << uint32(0x00000000); // on blizz it increments periodically
- SendPacket(&data);
+ if(guid == GetPlayer()->m_mover->GetGUID())
+ return;
+
+ if(Unit *mover = ObjectAccessor::GetUnit(*GetPlayer(), guid))
+ GetPlayer()->SetMover(mover);
+ else
+ {
+ sLog.outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is " I64FMT " and should be " I64FMT, guid, _player->m_mover->GetGUID());
+ GetPlayer()->SetMover(GetPlayer());
+ }
}
-void WorldSession::HandleNotActiveMoverOpcode(WorldPacket& /*recv_data*/)
+void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data)
{
sLog.outDebug("WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER");
+
+ CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+8);
+
+ uint64 old_mover_guid;
+ recv_data >> old_mover_guid;
+
+ /*if(_player->m_mover->GetGUID() == old_mover_guid)
+ {
+ sLog.outError("HandleMoveNotActiveMover: incorrect mover guid: mover is " I64FMT " and should be " I64FMT " instead of " I64FMT, _player->m_mover->GetGUID(), _player->GetGUID(), old_mover_guid);
+ return;
+ }*/
+
+ MovementInfo mi;
+ ReadMovementInfo(recv_data, &mi);
+ _player->m_movementInfo = mi;
+}
+
+void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: Recvd CMSG_DISMISS_CONTROLLED_VEHICLE");
+ recv_data.hexlike();
+
+ uint64 vehicleGUID = _player->GetCharmGUID();
+
+ if(!vehicleGUID) // something wrong here...
+ return;
+
+ MovementInfo mi;
+ ReadMovementInfo(recv_data, &mi);
+ _player->m_movementInfo = mi;
+ _player->ExitVehicle();
+}
+
+void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE");
+ recv_data.hexlike();
+
+ if(!GetPlayer()->m_Vehicle)
+ return;
+
+ if(recv_data.GetOpcode() == CMSG_REQUEST_VEHICLE_PREV_SEAT)
+ {
+ GetPlayer()->ChangeSeat(-1, false);
+ return;
+ }
+ else if(recv_data.GetOpcode() == CMSG_REQUEST_VEHICLE_NEXT_SEAT)
+ {
+ GetPlayer()->ChangeSeat(-1, true);
+ return;
+ }
+ else if(recv_data.GetOpcode() == CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE)
+ ReadMovementInfo(recv_data, &GetPlayer()->m_Vehicle->m_movementInfo);
+
+ CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+1);
+ uint64 guid;
+ if(!recv_data.readPackGUID(guid))
+ return;
+
+ CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+1);
+ int8 seatId;
+ recv_data >> seatId;
+
+ if(!guid)
+ GetPlayer()->ChangeSeat(-1, seatId > 0); // prev/next
+ else if(Vehicle *vehicle = ObjectAccessor::GetVehicle(guid))
+ {
+ if(vehicle->HasEmptySeat(seatId))
+ GetPlayer()->EnterVehicle(vehicle, seatId);
+ }
+}
+
+void WorldSession::HandleRequestVehicleExit(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: Recvd CMSG_REQUEST_VEHICLE_EXIT");
+ recv_data.hexlike();
+ GetPlayer()->ExitVehicle();
}
void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvdata*/)
diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp
index df027a48acd..c97196c0d91 100644
--- a/src/game/NPCHandler.cpp
+++ b/src/game/NPCHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,17 +25,14 @@
#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
-#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "GossipDef.h"
-#include "SpellAuras.h"
#include "UpdateMask.h"
#include "ScriptCalls.h"
#include "ObjectAccessor.h"
#include "Creature.h"
-#include "MapManager.h"
#include "Pet.h"
#include "BattleGroundMgr.h"
#include "BattleGround.h"
@@ -48,7 +45,7 @@ void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data )
uint64 guid;
recv_data >> guid;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TABARDDESIGNER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TABARDDESIGNER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -57,7 +54,7 @@ void WorldSession::HandleTabardVendorActivateOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
SendTabardVendorActivate(guid);
}
@@ -79,7 +76,7 @@ void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data )
recv_data >> guid;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_BANKER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_BANKER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -88,7 +85,7 @@ void WorldSession::HandleBankerActivateOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
SendShowBank(guid);
}
@@ -120,7 +117,7 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
{
sLog.outDebug( "WORLD: SendTrainerList" );
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TRAINER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER);
if (!unit)
{
sLog.outDebug( "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -129,7 +126,7 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
// trainer list loaded at check;
if(!unit->isCanTrainingOf(_player,true))
@@ -160,34 +157,37 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
// reputation discount
float fDiscountMod = _player->GetReputationPriceDiscount(unit);
+ bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProffesionPoints() > 0;
uint32 count = 0;
- for(TrainerSpellList::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
+ for(TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
{
- TrainerSpell const* tSpell = *itr;
+ TrainerSpell const* tSpell = &itr->second;
- if(!_player->IsSpellFitByClassAndRace(tSpell->spell))
+ if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell))
continue;
- ++count;
-
- bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->spell);
-
- SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->spell);
+ bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell);
+ SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell);
uint32 req_spell = spellmgr.GetSpellRequired(tSpell->spell);
+ TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
- data << uint32(tSpell->spell);
- data << uint8(_player->GetTrainerSpellState(tSpell));
- data << uint32(floor(tSpell->spellcost * fDiscountMod));
+ data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
+ data << uint8(state==TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
+ data << uint32(floor(tSpell->spellCost * fDiscountMod));
- data << uint32(primary_prof_first_rank ? 1 : 0); // primary prof. learn confirmation dialog
+ data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0);
+ // primary prof. learn confirmation dialog
data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
- data << uint8(tSpell->reqlevel);
- data << uint32(tSpell->reqskill);
- data << uint32(tSpell->reqskillvalue);
- data << uint32(chain_node && chain_node->prev ? chain_node->prev : req_spell);
- data << uint32(chain_node && chain_node->prev ? req_spell : 0);
+ data << uint8(tSpell->reqLevel);
+ data << uint32(tSpell->reqSkill);
+ data << uint32(tSpell->reqSkillValue);
+ //prev + req or req + 0
+ data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? chain_node->prev : req_spell);
+ data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? req_spell : 0);
data << uint32(0);
+
+ ++count;
}
data << strTitle;
@@ -206,7 +206,7 @@ void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
recv_data >> guid >> spellId;
sLog.outDebug( "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId );
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_TRAINER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -215,7 +215,7 @@ void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if(!unit->isCanTrainingOf(_player,true))
return;
@@ -235,12 +235,14 @@ void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
return;
// apply reputation discount
- uint32 nSpellCost = uint32(floor(trainer_spell->spellcost * _player->GetReputationPriceDiscount(unit)));
+ uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit)));
// check money requirement
if(_player->GetMoney() < nSpellCost )
return;
+ _player->ModifyMoney( -int32(nSpellCost) );
+
WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer
data << uint64(guid) << uint32(0xB3);
SendPacket(&data);
@@ -249,13 +251,15 @@ void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
data << uint64(_player->GetGUID()) << uint32(0x016A);
SendPacket(&data);
- _player->ModifyMoney( -int32(nSpellCost) );
-
- // learn explicitly to prevent lost money at lags, learning spell will be only show spell animation
- _player->learnSpell(trainer_spell->spell);
+ // learn explicitly or cast explicitly
+ if(trainer_spell->IsCastable ())
+ //FIXME: prof. spell entry in trainer list not marked gray until list re-open.
+ _player->CastSpell(_player,trainer_spell->spell,true);
+ else
+ _player->learnSpell(spellId,false);
data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12);
- data << uint64(guid) << uint32(spellId);
+ data << uint64(guid) << uint32(trainer_spell->spell);
SendPacket(&data);
}
@@ -268,7 +272,7 @@ void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data )
uint64 guid;
recv_data >> guid;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!unit)
{
sLog.outDebug( "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -278,7 +282,7 @@ void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data )
GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
// remove fake death
//if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- // GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if( unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider())
{
@@ -327,7 +331,7 @@ void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data )
sLog.outDebug("string read: %s", code.c_str());
}
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_NONE);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!unit)
{
sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -336,7 +340,7 @@ void WorldSession::HandleGossipHelloOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if(!code.empty())
{
@@ -360,7 +364,7 @@ void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data )
recv_data >> guid;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_SPIRITHEALER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -369,7 +373,7 @@ void WorldSession::HandleSpiritHealerActivateOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
SendSpiritResurrect();
}
@@ -421,7 +425,7 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
if(!GetPlayer()->isAlive())
return;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID,UNIT_NPC_FLAG_INNKEEPER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
@@ -430,25 +434,30 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
SendBindPoint(unit);
}
void WorldSession::SendBindPoint(Creature *npc)
{
+ // prevent set homebind to instances in any case
+ if(sMapStore.LookupEntry(GetPlayer()->GetMapId())->Instanceable())
+ return;
+
uint32 bindspell = 3286;
+ uint32 zone_id = _player->GetZoneId();
// update sql homebind
- CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), _player->GetZoneId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow());
+ CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), zone_id, _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow());
_player->m_homebindMapId = _player->GetMapId();
- _player->m_homebindZoneId = _player->GetZoneId();
+ _player->m_homebindZoneId = zone_id;
_player->m_homebindX = _player->GetPositionX();
_player->m_homebindY = _player->GetPositionY();
_player->m_homebindZ = _player->GetPositionZ();
// send spell for bind 3286 bind magic
- npc->CastSpell(_player, bindspell, true);
+ _player->CastSpell(_player, bindspell, true);
WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, (8+4));
data << npc->GetGUID();
@@ -461,25 +470,24 @@ void WorldSession::SendBindPoint(Creature *npc)
data << float(_player->GetPositionY());
data << float(_player->GetPositionZ());
data << uint32(_player->GetMapId());
- data << uint32(_player->GetZoneId());
+ data << uint32(zone_id);
SendPacket( &data );
DEBUG_LOG("New Home Position X is %f",_player->GetPositionX());
DEBUG_LOG("New Home Position Y is %f",_player->GetPositionY());
DEBUG_LOG("New Home Position Z is %f",_player->GetPositionZ());
DEBUG_LOG("New Home MapId is %u",_player->GetMapId());
- DEBUG_LOG("New Home ZoneId is %u",_player->GetZoneId());
+ DEBUG_LOG("New Home ZoneId is %u",zone_id);
// zone update
data.Initialize( SMSG_PLAYERBOUND, 8+4 );
data << uint64(_player->GetGUID());
- data << uint32(_player->GetZoneId());
+ data << uint32(zone_id);
SendPacket( &data );
_player->PlayerTalkClass->CloseGossip();
}
-//Need fix
void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data,8);
@@ -489,7 +497,7 @@ void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
recv_data >> npcGUID;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
@@ -498,11 +506,11 @@ void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
// remove mounts this fix bug where getting pet from stable while mounted deletes pet.
if(GetPlayer()->IsMounted())
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED);
SendStablePet(npcGUID);
}
@@ -516,7 +524,9 @@ void WorldSession::SendStablePet(uint64 guid )
Pet *pet = _player->GetPet();
+ size_t wpos = data.wpos();
data << uint8(0); // place holder for slot show number
+
data << uint8(GetPlayer()->m_stableSlots);
uint8 num = 0; // counter for place holder
@@ -528,13 +538,13 @@ void WorldSession::SendStablePet(uint64 guid )
data << uint32(pet->GetEntry());
data << uint32(pet->getLevel());
data << pet->GetName(); // petname
- data << uint32(pet->GetLoyaltyLevel()); // loyalty
- data << uint8(0x01); // client slot 1 == current pet (0)
+ data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
++num;
}
- // 0 1 2 3 4 5 6
- QueryResult* result = CharacterDatabase.PQuery("SELECT owner, slot, id, entry, level, loyalty, name FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow());
+ // 0 1 2 3 4
+ QueryResult* result = CharacterDatabase.PQuery("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);
if(result)
{
@@ -542,12 +552,11 @@ void WorldSession::SendStablePet(uint64 guid )
{
Field *fields = result->Fetch();
- data << uint32(fields[2].GetUInt32()); // petnumber
- data << uint32(fields[3].GetUInt32()); // creature entry
- data << uint32(fields[4].GetUInt32()); // level
- data << fields[6].GetString(); // name
- data << uint32(fields[5].GetUInt32()); // loyalty
- data << uint8(fields[1].GetUInt32()+1); // slot
+ data << uint32(fields[1].GetUInt32()); // petnumber
+ data << uint32(fields[2].GetUInt32()); // creature entry
+ data << uint32(fields[3].GetUInt32()); // level
+ data << fields[4].GetString(); // name
+ data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show)
++num;
}while( result->NextRow() );
@@ -555,7 +564,7 @@ void WorldSession::SendStablePet(uint64 guid )
delete result;
}
- data.put<uint8>(8, num); // set real data to placeholder
+ data.put<uint8>(wpos, num); // set real data to placeholder
SendPacket(&data);
}
@@ -571,7 +580,7 @@ void WorldSession::HandleStablePet( WorldPacket & recv_data )
if(!GetPlayer()->isAlive())
return;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleStablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
@@ -580,7 +589,7 @@ void WorldSession::HandleStablePet( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
Pet *pet = _player->GetPet();
@@ -596,7 +605,8 @@ void WorldSession::HandleStablePet( WorldPacket & recv_data )
uint32 free_slot = 1;
- QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3 ORDER BY slot ",_player->GetGUIDLow());
+ QueryResult *result = CharacterDatabase.PQuery("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);
if(result)
{
do
@@ -605,11 +615,16 @@ void WorldSession::HandleStablePet( WorldPacket & recv_data )
uint32 slot = fields[1].GetUInt32();
- if(slot==free_slot) // this slot not free
- ++free_slot;
+ // slots ordered in query, and if not equal then free
+ if(slot!=free_slot)
+ break;
+
+ // this slot not free, skip
+ ++free_slot;
}while( result->NextRow() );
+
+ delete result;
}
- delete result;
if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots)
{
@@ -632,7 +647,7 @@ void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
recv_data >> npcGUID >> petnumber;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
@@ -641,15 +656,14 @@ void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
Pet* pet = _player->GetPet();
if(pet && pet->isAlive())
{
- uint8 i = 0x06;
- data << uint8(i);
+ data << uint8(0x06);
SendPacket(&data);
return;
}
@@ -660,13 +674,14 @@ void WorldSession::HandleUnstablePet( WorldPacket & recv_data )
Pet *newpet = NULL;
- QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot > 0 AND slot < 3",_player->GetGUIDLow(),petnumber);
+ QueryResult *result = CharacterDatabase.PQuery("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);
if(result)
{
Field *fields = result->Fetch();
uint32 petentry = fields[0].GetUInt32();
- newpet = new Pet(HUNTER_PET);
+ newpet = new Pet(_player, HUNTER_PET);
if(!newpet->LoadPetFromDB(_player,petentry,petnumber))
{
delete newpet;
@@ -691,7 +706,7 @@ void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
recv_data >> npcGUID;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
@@ -700,11 +715,11 @@ void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
WorldPacket data(SMSG_STABLE_RESULT, 200);
- if(GetPlayer()->m_stableSlots < 2) // max slots amount = 2
+ if(GetPlayer()->m_stableSlots < MAX_PET_STABLES)
{
StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1);
if(_player->GetMoney() >= SlotPrice->Price)
@@ -737,7 +752,7 @@ void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
recv_data >> npcGUID >> pet_number;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
@@ -746,7 +761,7 @@ void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size
@@ -756,7 +771,8 @@ void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
return;
// find swapped pet slot in stable
- QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",_player->GetGUIDLow(),pet_number);
+ QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",
+ _player->GetGUIDLow(),pet_number);
if(!result)
return;
@@ -766,11 +782,11 @@ void WorldSession::HandleStableSwapPet( WorldPacket & recv_data )
uint32 petentry = fields[1].GetUInt32();
delete result;
- // move alive pet to slot or delele dead pet
+ // move alive pet to slot or delete dead pet
_player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
// summon unstabled pet
- Pet *newpet = new Pet;
+ Pet *newpet = new Pet(_player);
if(!newpet->LoadPetFromDB(_player,petentry,pet_number))
{
delete newpet;
@@ -793,7 +809,7 @@ void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
recv_data >> npcGUID >> itemGUID >> guildBank;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, npcGUID, UNIT_NPC_FLAG_REPAIR);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR);
if (!unit)
{
sLog.outDebug( "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(npcGUID)) );
@@ -802,7 +818,7 @@ void WorldSession::HandleRepairItemOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
// reputation discount
float discountMod = _player->GetReputationPriceDiscount(unit);
diff --git a/src/game/NPCHandler.h b/src/game/NPCHandler.h
index e359878173f..4d0395a0c87 100644
--- a/src/game/NPCHandler.h
+++ b/src/game/NPCHandler.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,7 +60,6 @@ struct GossipTextOption
struct GossipText
{
- uint32 Text_ID;
GossipTextOption Options[8];
};
diff --git a/src/game/NullCreatureAI.cpp b/src/game/NullCreatureAI.cpp
index 8bea03d0216..be59ed6e40d 100644
--- a/src/game/NullCreatureAI.cpp
+++ b/src/game/NullCreatureAI.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/NullCreatureAI.h b/src/game/NullCreatureAI.h
index d20d727690a..347f52228b4 100644
--- a/src/game/NullCreatureAI.h
+++ b/src/game/NullCreatureAI.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,46 +22,53 @@
#define TRINITY_NULLCREATUREAI_H
#include "CreatureAI.h"
+#include "CreatureAIImpl.h"
class TRINITY_DLL_DECL PassiveAI : public CreatureAI
{
public:
- PassiveAI(Creature *c) : CreatureAI(c) {}
- ~PassiveAI() {}
+ explicit PassiveAI(Creature *c) : CreatureAI(c) {}
void MoveInLineOfSight(Unit *) {}
void AttackStart(Unit *) {}
-
void UpdateAI(const uint32);
+
static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; }
};
-class TRINITY_DLL_DECL PossessedAI : public PassiveAI
+class TRINITY_DLL_DECL PossessedAI : public CreatureAI
{
public:
- PossessedAI(Creature *c) : PassiveAI(c) {}
+ explicit PossessedAI(Creature *c) : CreatureAI(c) {}
+ void MoveInLineOfSight(Unit *) {}
void AttackStart(Unit *target);
void UpdateAI(const uint32);
void EnterEvadeMode() {}
void JustDied(Unit*);
void KilledUnit(Unit* victim);
+
+ static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; }
};
-class TRINITY_DLL_DECL NullCreatureAI : public PassiveAI
+class TRINITY_DLL_DECL NullCreatureAI : public CreatureAI
{
public:
- NullCreatureAI(Creature *c) : PassiveAI(c) {}
+ explicit NullCreatureAI(Creature *c) : CreatureAI(c) {}
+ void MoveInLineOfSight(Unit *) {}
+ void AttackStart(Unit *) {}
void UpdateAI(const uint32) {}
void EnterEvadeMode() {}
+
+ static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; }
};
class TRINITY_DLL_DECL CritterAI : public PassiveAI
{
public:
- CritterAI(Creature *c) : PassiveAI(c) {}
+ explicit CritterAI(Creature *c) : PassiveAI(c) {}
void DamageTaken(Unit *done_by, uint32 & /*damage*/);
void EnterEvadeMode();
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index fe3239e9d6b..bc697d14f11 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -27,8 +27,8 @@
#include "Object.h"
#include "Creature.h"
#include "Player.h"
+#include "Vehicle.h"
#include "ObjectMgr.h"
-#include "WorldSession.h"
#include "UpdateData.h"
#include "UpdateMask.h"
#include "Util.h"
@@ -44,6 +44,7 @@
#include "GridNotifiersImpl.h"
#include "TemporarySummon.h"
+#include "Totem.h"
uint32 GuidHigh2TypeId(uint32 guid_hi)
{
@@ -58,8 +59,9 @@ uint32 GuidHigh2TypeId(uint32 guid_hi)
case HIGHGUID_DYNAMICOBJECT:return TYPEID_DYNAMICOBJECT;
case HIGHGUID_CORPSE: return TYPEID_CORPSE;
case HIGHGUID_MO_TRANSPORT: return TYPEID_GAMEOBJECT;
+ case HIGHGUID_VEHICLE: return TYPEID_UNIT;
}
- return 10; // unknown
+ return MAX_TYPEID; // unknown
}
Object::Object( )
@@ -83,17 +85,16 @@ Object::~Object( )
//if(m_objectUpdated)
// ObjectAccessor::Instance().RemoveUpdateObject(this);
- if(m_uint32Values)
+ if(IsInWorld())
{
- if(IsInWorld())
- {
- ///- Do NOT call RemoveFromWorld here, if the object is a player it will crash
- sLog.outError("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId());
- assert(false);
- }
+ sLog.outCrash("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId());
+ assert(false);
+ }
- assert(!m_objectUpdated);
+ assert(!m_objectUpdated);
+ if(m_uint32Values)
+ {
//DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
delete [] m_uint32Values;
delete [] m_uint32Values_mirror;
@@ -132,7 +133,7 @@ void Object::BuildMovementUpdateBlock(UpdateData * data, uint32 flags ) const
buf << uint8( UPDATETYPE_MOVEMENT );
buf << GetGUID();
- _BuildMovementUpdate(&buf, flags, 0x00000000);
+ _BuildMovementUpdate(&buf, flags);
data->AddUpdateBlock(buf);
}
@@ -146,13 +147,12 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) c
uint8 updatetype = UPDATETYPE_CREATE_OBJECT;
uint8 flags = m_updateFlag;
- uint32 flags2 = 0;
/** lower flag1 **/
if(target == this) // building packet for oneself
flags |= UPDATEFLAG_SELF;
- if(flags & UPDATEFLAG_HASPOSITION)
+ if(flags & UPDATEFLAG_HAS_POSITION)
{
// UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
if(isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER))
@@ -176,8 +176,16 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) c
case GAMEOBJECT_TYPE_TRANSPORT:
flags |= UPDATEFLAG_TRANSPORT;
break;
+ default:
+ break;
}
}
+
+ if(isType(TYPEMASK_UNIT))
+ {
+ if(((Unit*)this)->getVictim())
+ flags |= UPDATEFLAG_HAS_TARGET;
+ }
}
//sLog.outDebug("BuildCreateUpdate: update-type: %u, object-type: %u got flags: %X, flags2: %X", updatetype, m_objectTypeId, flags, flags2);
@@ -188,7 +196,7 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) c
buf << (uint8)0xFF << GetGUID();
buf << (uint8)m_objectTypeId;
- _BuildMovementUpdate(&buf, flags, flags2);
+ _BuildMovementUpdate(&buf, flags);
UpdateMask updateMask;
updateMask.SetCount( m_valuesCount );
@@ -248,34 +256,29 @@ void Object::DestroyForPlayer(Player *target) const
WorldPacket data(SMSG_DESTROY_OBJECT, 8);
data << GetGUID();
+ data << uint8(0); // WotLK (bool)
target->GetSession()->SendPacket( &data );
}
-void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2 ) const
+void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags) const
{
*data << (uint8)flags; // update flags
// 0x20
if (flags & UPDATEFLAG_LIVING)
{
+ uint32 flags2 = ((Unit*)this)->GetUnitMovementFlags();
switch(GetTypeId())
{
case TYPEID_UNIT:
{
- flags2 = ((Unit*)this)->GetUnitMovementFlags();
- flags2 &= ~MOVEMENTFLAG_ONTRANSPORT;
flags2 &= ~MOVEMENTFLAG_SPLINE2;
+ if(((Creature*)this)->isVehicle())
+ ((Unit*)this)->m_movementInfo.unk1 |= 0x20; // always allow pitch
}
break;
case TYPEID_PLAYER:
{
- flags2 = ((Player*)this)->GetUnitMovementFlags();
-
- if(((Player*)this)->GetTransport())
- flags2 |= MOVEMENTFLAG_ONTRANSPORT;
- else
- flags2 &= ~MOVEMENTFLAG_ONTRANSPORT;
-
// remove unknown, unused etc flags for now
flags2 &= ~MOVEMENTFLAG_SPLINE2; // will be set manually
@@ -289,12 +292,12 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
}
*data << uint32(flags2); // movement flags
- *data << uint8(0); // unk 2.3.0
+ *data << uint16(((Unit*)this)->m_movementInfo.unk1);// unknown 2.3.0
*data << uint32(getMSTime()); // time (in milliseconds)
}
// 0x40
- if (flags & UPDATEFLAG_HASPOSITION)
+ if (flags & UPDATEFLAG_HAS_POSITION)
{
// 0x02
if(flags & UPDATEFLAG_TRANSPORT && ((GameObject*)this)->GetGoType() == GAMEOBJECT_TYPE_MO_TRANSPORT)
@@ -316,62 +319,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
// 0x20
if(flags & UPDATEFLAG_LIVING)
{
- // 0x00000200
- if(flags2 & MOVEMENTFLAG_ONTRANSPORT)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- *data << (uint64)((Player*)this)->GetTransport()->GetGUID();
- *data << (float)((Player*)this)->GetTransOffsetX();
- *data << (float)((Player*)this)->GetTransOffsetY();
- *data << (float)((Player*)this)->GetTransOffsetZ();
- *data << (float)((Player*)this)->GetTransOffsetO();
- *data << (uint32)((Player*)this)->GetTransTime();
- }
- //TrinIty currently not have support for other than player on transport
- }
-
- // 0x02200000
- if(flags2 & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2))
- {
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (float)((Player*)this)->m_movementInfo.s_pitch;
- else
- *data << (float)0; // is't part of movement packet, we must store and send it...
- }
-
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (uint32)((Player*)this)->m_movementInfo.fallTime;
- else
- *data << (uint32)0; // last fall time
-
- // 0x00001000
- if(flags2 & MOVEMENTFLAG_JUMPING)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- *data << (float)((Player*)this)->m_movementInfo.j_unk;
- *data << (float)((Player*)this)->m_movementInfo.j_sinAngle;
- *data << (float)((Player*)this)->m_movementInfo.j_cosAngle;
- *data << (float)((Player*)this)->m_movementInfo.j_xyspeed;
- }
- else
- {
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- }
- }
-
- // 0x04000000
- if(flags2 & MOVEMENTFLAG_SPLINE)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (float)((Player*)this)->m_movementInfo.u_unk1;
- else
- *data << (float)0;
- }
+ ((Unit*)this)->BuildMovementPacket(data);
*data << ((Unit*)this)->GetSpeed( MOVE_WALK );
*data << ((Unit*)this)->GetSpeed( MOVE_RUN );
@@ -381,22 +329,11 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
*data << ((Unit*)this)->GetSpeed( MOVE_FLIGHT );
*data << ((Unit*)this)->GetSpeed( MOVE_FLIGHT_BACK );
*data << ((Unit*)this)->GetSpeed( MOVE_TURN_RATE );
+ *data << ((Unit*)this)->GetSpeed( MOVE_PITCH_RATE );
// 0x08000000
- if(flags2 & MOVEMENTFLAG_SPLINE2)
+ if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isInFlight())
{
- if(GetTypeId() != TYPEID_PLAYER)
- {
- sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 for non-player");
- return;
- }
-
- if(!((Player*)this)->isInFlight())
- {
- sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 but not in flight");
- return;
- }
-
WPAssert(((Player*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
FlightPathMovementGenerator *fmg = (FlightPathMovementGenerator*)(((Player*)this)->GetMotionMaster()->top());
@@ -445,6 +382,8 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
*data << path.GetNodes()[i].z;
}
+ *data << uint8(0); // added in 3.0.8
+
/*for(uint32 i = 0; i < poscount; i++)
{
// path points
@@ -482,7 +421,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
break;
case TYPEID_PLAYER:
if(flags & UPDATEFLAG_SELF)
- *data << uint32(0x00000015); // unk, can be 0x15 or 0x22
+ *data << uint32(0x0000002F); // unk, can be 0x15 or 0x22
else
*data << uint32(0x00000008); // unk, can be 0x7 or 0x8
break;
@@ -505,6 +444,15 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
case TYPEID_CORPSE:
*data << uint32(GetGUIDHigh()); // GetGUIDHigh()
break;
+ case TYPEID_UNIT:
+ *data << uint32(0x0000000B); // unk, can be 0xB or 0xC
+ break;
+ case TYPEID_PLAYER:
+ if(flags & UPDATEFLAG_SELF)
+ *data << uint32(0x0000002F); // unk, can be 0x15 or 0x22
+ else
+ *data << uint32(0x00000008); // unk, can be 0x7 or 0x8
+ break;
default:
*data << uint32(0x00000000); // unk
break;
@@ -512,9 +460,12 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
}
// 0x4
- if(flags & UPDATEFLAG_FULLGUID)
+ if(flags & UPDATEFLAG_HAS_TARGET) // packed guid (current target guid)
{
- *data << uint8(0); // packed guid (probably target guid)
+ if(Unit *victim = ((Unit*)this)->getVictim())
+ data->append(victim->GetPackGUID());
+ else
+ *data << uint8(0);
}
// 0x2
@@ -522,6 +473,13 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
{
*data << uint32(getMSTime()); // ms time
}
+
+ // 0x80
+ if(flags & UPDATEFLAG_VEHICLE) // unused for now
+ {
+ *data << uint32(((Vehicle*)this)->GetVehicleInfo()->m_ID); // vehicle id
+ *data << float(0); // facing adjustment
+ }
}
void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask *updateMask, Player *target) const
@@ -537,10 +495,10 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
if ( ((GameObject*)this)->ActivateToQuest(target) || target->isGameMaster())
{
IsActivateToQuest = true;
- updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
+ updateMask->SetBit(GAMEOBJECT_DYNAMIC);
}
- if (GetUInt32Value(GAMEOBJECT_ARTKIT))
- updateMask->SetBit(GAMEOBJECT_ARTKIT);
+ if (((GameObject*)this)->GetGoArtKit())
+ updateMask->SetBit(GAMEOBJECT_BYTES_1);
}
}
else //case UPDATETYPE_VALUES
@@ -551,8 +509,8 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
{
IsActivateToQuest = true;
}
- updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
- updateMask->SetBit(GAMEOBJECT_ANIMPROGRESS);
+ updateMask->SetBit(GAMEOBJECT_DYNAMIC);
+ updateMask->SetBit(GAMEOBJECT_BYTES_1);
}
}
@@ -568,9 +526,16 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
{
if( updateMask->GetBit( index ) )
{
- // remove custom flag before send
if( index == UNIT_NPC_FLAGS )
- *data << uint32(m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP));
+ {
+ // remove custom flag before sending
+ uint32 appendValue = m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP);
+
+ if (GetTypeId() == TYPEID_UNIT && !target->canSeeSpellClickOn((Creature*)this))
+ appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
+
+ *data << uint32(appendValue);
+ }
// FIXME: Some values at server stored in float format but must be sent to client in uint32 format
else if(index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
{
@@ -578,83 +543,93 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
*data << uint32(m_floatValues[ index ] < 0 ? 0 : m_floatValues[ index ]);
}
// there are some float values which may be negative or can't get negative due to other checks
- else if(index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4 ||
- index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6) ||
- index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6) ||
- index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4)
+ else if ((index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4) ||
+ (index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6)) ||
+ (index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6)) ||
+ (index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4))
{
*data << uint32(m_floatValues[ index ]);
}
// Gamemasters should be always able to select units - remove not selectable flag
- else if(index == UNIT_FIELD_FLAGS && target->isGameMaster())
+ else if(index == UNIT_FIELD_FLAGS)
{
- *data << (m_uint32Values[ index ] & ~UNIT_FLAG_NOT_SELECTABLE);
+ if(target->isGameMaster())
+ *data << (m_uint32Values[ index ] & ~UNIT_FLAG_NOT_SELECTABLE);
+ else
+ *data << m_uint32Values[ index ];
}
// use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures
- else if(index == UNIT_FIELD_DISPLAYID && GetTypeId() == TYPEID_UNIT)
+ else if(index == UNIT_FIELD_DISPLAYID)
{
- const CreatureInfo* cinfo = ((Creature*)this)->GetCreatureInfo();
- if(cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
+ if(GetTypeId() == TYPEID_UNIT)
{
- if(target->isGameMaster())
+ const CreatureInfo* cinfo = ((Creature*)this)->GetCreatureInfo();
+ if(cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
{
- if(cinfo->Modelid_A2)
- *data << cinfo->Modelid_A1;
+ if(target->isGameMaster())
+ {
+ if(cinfo->Modelid_A1)
+ *data << cinfo->Modelid_A1;
+ else
+ *data << 17519; // world invisible trigger's model
+ }
else
- *data << 17519; // world invisible trigger's model
+ {
+ if(cinfo->Modelid_A2)
+ *data << cinfo->Modelid_A2;
+ else
+ *data << 11686; // world invisible trigger's model
+ }
}
else
- {
- if(cinfo->Modelid_A2)
- *data << cinfo->Modelid_A2;
- else
- *data << 11686; // world invisible trigger's model
- }
+ *data << m_uint32Values[ index ];
}
else
*data << m_uint32Values[ index ];
}
// hide lootable animation for unallowed players
- else if(index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_UNIT)
+ else if(index == UNIT_DYNAMIC_FLAGS)
{
- if(!target->isAllowedToLoot((Creature*)this))
- *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_LOOTABLE);
+ if(GetTypeId() == TYPEID_UNIT)
+ {
+ if(!target->isAllowedToLoot((Creature*)this))
+ *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_LOOTABLE);
+ else
+ *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_OTHER_TAGGER);
+ }
else
- *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_OTHER_TAGGER);
+ *data << m_uint32Values[ index ];
}
// FG: pretend that OTHER players in own group are friendly ("blue")
else if(index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE)
{
- bool ch = false;
- if(target->GetTypeId() == TYPEID_PLAYER && GetTypeId() == TYPEID_PLAYER && target != this)
+ if(((Unit*)this)->IsControlledByPlayer() && target != this && sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && ((Unit*)this)->IsInRaidWith(target))
{
- if(target->IsInSameGroupWith((Player*)this) || target->IsInSameRaidWith((Player*)this))
- {
- if(index == UNIT_FIELD_BYTES_2)
- {
- DEBUG_LOG("-- VALUES_UPDATE: Sending '%s' the blue-group-fix from '%s' (flag)", target->GetName(), ((Player*)this)->GetName());
- *data << ( m_uint32Values[ index ] & ((UNIT_BYTE2_FLAG_SANCTUARY | UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5) << 8) ); // this flag is at uint8 offset 1 !!
-
- ch = true;
- }
- else if(index == UNIT_FIELD_FACTIONTEMPLATE)
+ FactionTemplateEntry const *ft1, *ft2;
+ ft1 = ((Unit*)this)->getFactionTemplateEntry();
+ ft2 = target->getFactionTemplateEntry();
+ if(ft1 && ft2 && !ft1->IsFriendlyTo(*ft2))
{
- FactionTemplateEntry const *ft1, *ft2;
- ft1 = ((Player*)this)->getFactionTemplateEntry();
- ft2 = ((Player*)target)->getFactionTemplateEntry();
- if(ft1 && ft2 && !ft1->IsFriendlyTo(*ft2))
+ if(index == UNIT_FIELD_BYTES_2)
+ {
+ // Allow targetting opposite faction in party when enabled in config
+ DEBUG_LOG("-- VALUES_UPDATE: Sending '%s' the blue-group-fix from '%s' (flag)", target->GetName(), ((Player*)this)->GetName());
+ *data << ( m_uint32Values[ index ] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8) ); // this flag is at uint8 offset 1 !!
+ }
+ else
{
- uint32 faction = ((Player*)target)->getFaction(); // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
+ // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
+ uint32 faction = target->getFaction();
DEBUG_LOG("-- VALUES_UPDATE: Sending '%s' the blue-group-fix from '%s' (faction %u)", target->GetName(), ((Player*)this)->GetName(), faction);
*data << uint32(faction);
- ch = true;
}
}
+ else
+ *data << m_uint32Values[ index ];
}
- }
- if(!ch)
+ else
*data << m_uint32Values[ index ];
- }
+ }
else
{
// send in current format (float as float, uint32 as uint32)
@@ -670,7 +645,7 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
if( updateMask->GetBit( index ) )
{
// send in current format (float as float, uint32 as uint32)
- if ( index == GAMEOBJECT_DYN_FLAGS )
+ if (index == GAMEOBJECT_DYNAMIC )
{
if(IsActivateToQuest )
{
@@ -710,11 +685,10 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
void Object::ClearUpdateMask(bool remove)
{
- for( uint16 index = 0; index < m_valuesCount; index ++ )
- {
- if(m_uint32Values_mirror[index]!= m_uint32Values[index])
- m_uint32Values_mirror[index] = m_uint32Values[index];
- }
+ uint32 *temp = m_uint32Values;
+
+ memcpy(m_uint32Values_mirror, m_uint32Values, m_valuesCount*sizeof(uint32));
+
if(m_objectUpdated)
{
if(remove)
@@ -758,18 +732,23 @@ bool Object::LoadValues(const char* data)
void Object::_SetUpdateBits(UpdateMask *updateMask, Player* /*target*/) const
{
- for( uint16 index = 0; index < m_valuesCount; index ++ )
+ uint32 *value = m_uint32Values;
+ uint32 *mirror = m_uint32Values_mirror;
+
+ for(uint16 index = 0; index < m_valuesCount; ++index, ++value, ++mirror)
{
- if(m_uint32Values_mirror[index]!= m_uint32Values[index])
+ if(*mirror != *value)
updateMask->SetBit(index);
}
}
void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const
{
- for( uint16 index = 0; index < m_valuesCount; index++ )
+ uint32 *value = m_uint32Values;
+
+ for(uint16 index = 0; index < m_valuesCount; ++index, ++value)
{
- if(GetUInt32Value(index) != 0)
+ if(*value)
updateMask->SetBit(index);
}
}
@@ -831,6 +810,48 @@ void Object::SetUInt64Value( uint16 index, const uint64 &value )
}
}
+bool Object::AddUInt64Value(uint16 index, const uint64 &value)
+{
+ ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
+ if(value && !*((uint64*)&(m_uint32Values[index])))
+ {
+ m_uint32Values[ index ] = *((uint32*)&value);
+ m_uint32Values[ index + 1 ] = *(((uint32*)&value) + 1);
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Object::RemoveUInt64Value(uint16 index, const uint64 &value)
+{
+ ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
+ if(value && *((uint64*)&(m_uint32Values[index])) == value)
+ {
+ m_uint32Values[ index ] = 0;
+ m_uint32Values[ index + 1 ] = 0;
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
void Object::SetFloatValue( uint16 index, float value )
{
ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
@@ -1051,6 +1072,8 @@ bool Object::PrintIndexError(uint32 index, bool set) const
}
WorldObject::WorldObject()
+ : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL),
+ m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f)
{
m_positionX = 0.0f;
m_positionY = 0.0f;
@@ -1063,8 +1086,6 @@ WorldObject::WorldObject()
m_name = "";
- mSemaphoreTeleport = false;
-
m_isActive = false;
IsTempWorldObject = false;
}
@@ -1073,8 +1094,8 @@ void WorldObject::SetWorldObject(bool on)
{
if(!IsInWorld())
return;
-
- GetMap()->AddObjectToSwitchList(this, on);
+
+ GetMap()->AddObjectToSwitchList(this, on);
}
void WorldObject::setActive( bool on )
@@ -1110,21 +1131,27 @@ void WorldObject::setActive( bool on )
}
}
-void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid )
+void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask )
{
Object::_Create(guidlow, 0, guidhigh);
m_mapId = mapid;
+ m_phaseMask = phaseMask;
}
uint32 WorldObject::GetZoneId() const
{
- return MapManager::Instance().GetBaseMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
+ return MapManager::Instance().GetBaseMap(m_mapId)->GetZoneId(m_positionX,m_positionY,m_positionZ);
}
uint32 WorldObject::GetAreaId() const
{
- return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX,m_positionY);
+ return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX,m_positionY,m_positionZ);
+}
+
+void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const
+{
+ MapManager::Instance().GetBaseMap(m_mapId)->GetZoneAndAreaId(zoneid,areaid,m_positionX,m_positionY,m_positionZ);
}
InstanceData* WorldObject::GetInstanceData()
@@ -1132,7 +1159,6 @@ InstanceData* WorldObject::GetInstanceData()
Map *map = GetMap();
return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
}
-
//slow
float WorldObject::GetDistance(const WorldObject* obj) const
{
@@ -1160,7 +1186,7 @@ float WorldObject::GetExactDistance2d(const float x, const float y) const
return sqrt((dx*dx) + (dy*dy));
}
-float WorldObject::GetDistance(const float x, const float y, const float z) const
+float WorldObject::GetDistance(float x, float y, float z) const
{
float dx = GetPositionX() - x;
float dy = GetPositionY() - y;
@@ -1178,6 +1204,14 @@ float WorldObject::GetDistanceSq(const float &x, const float &y, const float &z)
return dx*dx + dy*dy + dz*dz;
}
+float WorldObject::GetDistanceSq(const WorldObject *obj) const
+{
+ float dx = GetPositionX() - obj->GetPositionX();
+ float dy = GetPositionY() - obj->GetPositionY();
+ float dz = GetPositionZ() - obj->GetPositionZ();
+ return dx*dx + dy*dy + dz*dz;
+}
+
float WorldObject::GetDistance2d(const WorldObject* obj) const
{
float dx = GetPositionX() - obj->GetPositionX();
@@ -1195,10 +1229,33 @@ float WorldObject::GetDistanceZ(const WorldObject* obj) const
return ( dist > 0 ? dist : 0);
}
-bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D) const
+bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist2compare) const
{
- if (!obj || !IsInMap(obj)) return false;
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float dz = GetPositionZ() - z;
+ float distsq = dx*dx + dy*dy + dz*dz;
+
+ float sizefactor = GetObjectSize();
+ float maxdist = dist2compare + sizefactor;
+ return distsq < maxdist * maxdist;
+}
+
+bool WorldObject::IsWithinDist2d(float x, float y, float dist2compare) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float distsq = dx*dx + dy*dy;
+
+ float sizefactor = GetObjectSize();
+ float maxdist = dist2compare + sizefactor;
+
+ return distsq < maxdist * maxdist;
+}
+
+bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const
+{
float dx = GetPositionX() - obj->GetPositionX();
float dy = GetPositionY() - obj->GetPositionY();
float distsq = dx*dx + dy*dy;
@@ -1221,7 +1278,7 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
return(IsWithinLOS(ox, oy, oz ));
}
-bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const
+bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
{
float x,y,z;
GetPosition(x,y,z);
@@ -1229,6 +1286,95 @@ bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) c
return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);
}
+bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const
+{
+ float dx1 = GetPositionX() - obj1->GetPositionX();
+ float dy1 = GetPositionY() - obj1->GetPositionY();
+ float distsq1 = dx1*dx1 + dy1*dy1;
+ if(is3D)
+ {
+ float dz1 = GetPositionZ() - obj1->GetPositionZ();
+ distsq1 += dz1*dz1;
+ }
+
+ float dx2 = GetPositionX() - obj2->GetPositionX();
+ float dy2 = GetPositionY() - obj2->GetPositionY();
+ float distsq2 = dx2*dx2 + dy2*dy2;
+ if(is3D)
+ {
+ float dz2 = GetPositionZ() - obj2->GetPositionZ();
+ distsq2 += dz2*dz2;
+ }
+
+ return distsq1 < distsq2;
+}
+
+bool WorldObject::IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D /* = true */) const
+{
+ float dx = GetPositionX() - obj->GetPositionX();
+ float dy = GetPositionY() - obj->GetPositionY();
+ float distsq = dx*dx + dy*dy;
+ if(is3D)
+ {
+ float dz = GetPositionZ() - obj->GetPositionZ();
+ distsq += dz*dz;
+ }
+
+ float sizefactor = GetObjectSize() + obj->GetObjectSize();
+
+ // check only for real range
+ if(minRange > 0.0f)
+ {
+ float mindist = minRange + sizefactor;
+ if(distsq < mindist * mindist)
+ return false;
+ }
+
+ float maxdist = maxRange + sizefactor;
+ return distsq < maxdist * maxdist;
+}
+
+bool WorldObject::IsInRange2d(float x, float y, float minRange, float maxRange) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float distsq = dx*dx + dy*dy;
+
+ float sizefactor = GetObjectSize();
+
+ // check only for real range
+ if(minRange > 0.0f)
+ {
+ float mindist = minRange + sizefactor;
+ if(distsq < mindist * mindist)
+ return false;
+ }
+
+ float maxdist = maxRange + sizefactor;
+ return distsq < maxdist * maxdist;
+}
+
+bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float maxRange) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float dz = GetPositionZ() - z;
+ float distsq = dx*dx + dy*dy + dz*dz;
+
+ float sizefactor = GetObjectSize();
+
+ // check only for real range
+ if(minRange > 0.0f)
+ {
+ float mindist = minRange + sizefactor;
+ if(distsq < mindist * mindist)
+ return false;
+ }
+
+ float maxdist = maxRange + sizefactor;
+ return distsq < maxdist * maxdist;
+}
+
float WorldObject::GetAngle(const WorldObject* obj) const
{
if(!obj) return 0;
@@ -1246,6 +1392,25 @@ float WorldObject::GetAngle( const float x, const float y ) const
return ang;
}
+void WorldObject::GetSinCos(const float x, const float y, float &vsin, float &vcos)
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+
+ if(dx < 0.001f && dy < 0.001f)
+ {
+ float angle = rand_norm()*2*M_PI;
+ vcos = cos(angle);
+ vsin = sin(angle);
+ }
+ else
+ {
+ float dist = sqrt((dx*dx) + (dy*dy));
+ vcos = dx / dist;
+ vsin = dy / dist;
+ }
+}
+
bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
{
// always have self in arc
@@ -1274,6 +1439,21 @@ bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
return (( angle >= lborder ) && ( angle <= rborder ));
}
+bool WorldObject::IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size) const
+{
+ if(GetPositionX() > std::max(obj1->GetPositionX(), obj2->GetPositionX())
+ || GetPositionX() < std::min(obj1->GetPositionX(), obj2->GetPositionX())
+ || GetPositionY() > std::max(obj1->GetPositionY(), obj2->GetPositionY())
+ || GetPositionY() < std::min(obj1->GetPositionY(), obj2->GetPositionY()))
+ return false;
+
+ if(!size)
+ size = GetObjectSize() / 2;
+
+ float angle = obj1->GetAngle(this) - obj1->GetAngle(obj2);
+ return abs(sin(angle)) * GetExactDistance2d(obj1->GetPositionX(), obj1->GetPositionY()) < size;
+}
+
void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
{
if(distance==0)
@@ -1367,50 +1547,17 @@ void Object::ForceValuesUpdateAtIndex(uint32 i)
namespace Trinity
{
- class MessageChatLocaleCacheDo
+ class MonsterChatBuilder
{
public:
- MessageChatLocaleCacheDo(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, uint64 targetGUID, float dist)
- : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language),
- i_targetGUID(targetGUID), i_dist(dist)
- {
- }
-
- ~MessageChatLocaleCacheDo()
+ MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, uint64 targetGUID)
+ : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), i_targetGUID(targetGUID) {}
+ void operator()(WorldPacket& data, int32 loc_idx)
{
- for(int i = 0; i < i_data_cache.size(); ++i)
- delete i_data_cache[i];
- }
-
- void operator()(Player* p)
- {
- // skip far away players
- if(p->GetDistance(&i_object) > i_dist)
- return;
-
- uint32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
- uint32 cache_idx = loc_idx+1;
- WorldPacket* data;
-
- // create if not cached yet
- if(i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx])
- {
- if(i_data_cache.size() < cache_idx+1)
- i_data_cache.resize(cache_idx+1);
-
- char const* text = objmgr.GetTrinityString(i_textId,loc_idx);
-
- data = new WorldPacket(SMSG_MESSAGECHAT, 200);
-
- // TODO: i_object.GetName() also must be localized?
- i_object.BuildMonsterChat(data,i_msgtype,text,i_language,i_object.GetNameForLocaleIdx(loc_idx),i_targetGUID);
-
- i_data_cache[cache_idx] = data;
- }
- else
- data = i_data_cache[cache_idx];
+ char const* text = objmgr.GetMangosString(i_textId,loc_idx);
- p->SendDirectMessage(data);
+ // TODO: i_object.GetName() also must be localized?
+ i_object.BuildMonsterChat(&data,i_msgtype,text,i_language,i_object.GetNameForLocaleIdx(loc_idx),i_targetGUID);
}
private:
@@ -1419,8 +1566,6 @@ namespace Trinity
int32 i_textId;
uint32 i_language;
uint64 i_targetGUID;
- float i_dist;
- std::vector<WorldPacket*> i_data_cache; // 0 = default, i => i-1 locale index
};
} // namespace Trinity
@@ -1432,9 +1577,10 @@ void WorldObject::MonsterSay(int32 textId, uint32 language, uint64 TargetGuid)
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
- Trinity::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY));
- Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
- TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
+ MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid);
+ MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
+ MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),say_do);
+ TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> >, WorldTypeMapContainer > message(say_worker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *GetMap());
}
@@ -1447,13 +1593,27 @@ void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid)
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
- Trinity::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL));
- Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
- TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
+ MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid);
+ MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
+ MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),say_do);
+ TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> >, WorldTypeMapContainer > message(say_worker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *GetMap());
}
+void WorldObject::MonsterYellToZone(int32 textId, uint32 language, uint64 TargetGuid)
+{
+ MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid);
+ MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
+
+ uint32 zoneid = GetZoneId();
+
+ Map::PlayerList const& pList = GetMap()->GetPlayers();
+ for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
+ if(itr->getSource()->GetZoneId()==zoneid)
+ say_do(itr->getSource());
+}
+
void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote)
{
CellPair p = Trinity::ComputeCellPair(GetPositionX(), GetPositionY());
@@ -1462,9 +1622,10 @@ void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossE
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
- Trinity::MessageChatLocaleCacheDo say_do(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId,LANG_UNIVERSAL,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
- Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
- TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
+ MaNGOS::MonsterChatBuilder say_build(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId,LANG_UNIVERSAL,TargetGuid);
+ MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
+ MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),say_do);
+ TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> >, WorldTypeMapContainer > message(say_worker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *GetMap());
}
@@ -1479,7 +1640,7 @@ void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisp
char const* text = objmgr.GetTrinityString(textId,loc_idx);
WorldPacket data(SMSG_MESSAGECHAT, 200);
- BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
+ BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetNameForLocaleIdx(loc_idx),receiver);
player->GetSession()->SendPacket(&data);
}
@@ -1516,13 +1677,14 @@ void WorldObject::BuildHeartBeatMsg(WorldPacket *data) const
data->Initialize(MSG_MOVE_HEARTBEAT, 32);
data->append(GetPackGUID());
*data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
- *data << uint8(0); // 2.3.0
+ *data << uint16(0); // 2.3.0
*data << getMSTime(); // time
*data << m_positionX;
*data << m_positionY;
*data << m_positionZ;
*data << m_orientation;
- *data << uint32(0);
+
+ ((Unit*)this)->BuildMovementPacket(data);
}
void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float z, float ang) const
@@ -1535,13 +1697,14 @@ void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float
data->append(GetPackGUID());
*data << uint32(0); // this value increments every time
*data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
- *data << uint8(0); // 2.3.0
+ *data << uint16(0); // 2.3.0
*data << getMSTime(); // time
*data << x;
*data << y;
*data << z;
*data << ang;
- *data << uint32(0);
+
+ ((Unit*)this)->BuildMovementPacket(data);
}
void WorldObject::SendMessageToSet(WorldPacket *data, bool /*fake*/, bool bToPossessor)
@@ -1590,60 +1753,136 @@ void WorldObject::AddObjectToRemoveList()
map->AddObjectToRemoveList(this);
}
-Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
+TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float angle, SummonPropertiesEntry const *properties, uint32 duration, Unit *summoner)
{
- TemporarySummon* pCreature = new TemporarySummon(GetGUID());
+ uint32 mask = SUMMON_MASK_SUMMON;
+ if(properties)
+ {
+ if(properties->Category == SUMMON_CATEGORY_PET
+ || properties->Type == SUMMON_TYPE_GUARDIAN
+ || properties->Type == SUMMON_TYPE_MINION)
+ mask = SUMMON_MASK_GUARDIAN;
+ else if(properties->Type == SUMMON_TYPE_TOTEM)
+ mask = SUMMON_MASK_TOTEM;
+ else if(properties->Category == SUMMON_CATEGORY_VEHICLE
+ || properties->Type == SUMMON_TYPE_VEHICLE
+ || properties->Type == SUMMON_TYPE_VEHICLE2)
+ mask = SUMMON_MASK_VEHICLE;
+ else if(properties->Type == SUMMON_TYPE_MINIPET)
+ mask = SUMMON_MASK_MINION;
+ }
- uint32 team = 0;
- if (GetTypeId()==TYPEID_PLAYER)
- team = ((Player*)this)->GetTeam();
+ uint32 phase = PHASEMASK_NORMAL, team = 0;
+ if(summoner)
+ {
+ phase = summoner->GetPhaseMask();
+ if(summoner->GetTypeId() == TYPEID_PLAYER)
+ team = ((Player*)summoner)->GetTeam();
+ }
+
+ TempSummon *summon = NULL;
+ switch(mask)
+ {
+ case SUMMON_MASK_SUMMON: summon = new TempSummon (properties, summoner); break;
+ case SUMMON_MASK_GUARDIAN: summon = new Guardian (properties, summoner); break;
+ case SUMMON_MASK_TOTEM: summon = new Totem (properties, summoner); break;
+ case SUMMON_MASK_MINION: summon = new Minion (properties, summoner); break;
+ default: return NULL;
+ }
+ if(!summon->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), this, phase, entry, team))
+ {
+ delete summon;
+ return NULL;
+ }
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMap(), id, team))
+ summon->Relocate(x, y, z, angle);
+ if(!summon->IsPositionValid())
{
- delete pCreature;
+ sLog.outError("Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",summon->GetGUIDLow(),summon->GetEntry(),summon->GetPositionX(),summon->GetPositionY());
+ delete summon;
return NULL;
}
+ summon->SetHomePosition(x, y, z, angle);
+
+ summon->InitStats(duration);
+ Add((Creature*)summon);
+ summon->InitSummon();
+
+ //ObjectAccessor::UpdateObjectVisibility(summon);
+
+ return summon;
+}
+
+TempSummon* WorldObject::SummonCreature(uint32 entry, float x, float y, float z, float ang, TempSummonType spwtype, uint32 duration)
+{
+ Map *map = FindMap();
+ if(!map)
+ return NULL;
+
if (x == 0.0f && y == 0.0f && z == 0.0f)
- GetClosePoint(x, y, z, pCreature->GetObjectSize());
+ GetClosePoint(x, y, z, GetObjectSize());
- pCreature->Relocate(x, y, z, ang);
+ TempSummon *pCreature = map->SummonCreature(entry, x, y, z, ang, NULL, duration, isType(TYPEMASK_UNIT) ? (Unit*)this : NULL);
+ if(!pCreature)
+ return NULL;
+
+ pCreature->SetTempSummonType(spwtype);
- if(!pCreature->IsPositionValid())
+ return pCreature;
+}
+
+Vehicle* WorldObject::SummonVehicle(uint32 entry, float x, float y, float z, float ang)
+{
+ CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry);
+ if(!ci)
+ return NULL;
+
+ uint32 id = ci->VehicleId; //temp store id here
+ if(!id) id = 156;
+ VehicleEntry const *ve = sVehicleStore.LookupEntry(id);
+ if(!ve)
+ return NULL;
+
+ Vehicle *v = new Vehicle;
+ Map *map = GetMap();
+ uint32 team = 0;
+ if (GetTypeId()==TYPEID_PLAYER)
+ team = ((Player*)this)->GetTeam();
+ if(!v->Create(objmgr.GenerateLowGuid(HIGHGUID_VEHICLE), map, GetPhaseMask(), entry, id, team))
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
- delete pCreature;
+ delete v;
return NULL;
}
- pCreature->SetHomePosition(x, y, z, ang);
- pCreature->Summon(spwtype, despwtime);
-
- if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->IsAIEnabled)
- ((Creature*)this)->AI()->JustSummoned(pCreature);
+ v->Relocate(x, y, z, ang);
- if(pCreature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && pCreature->m_spells[0])
+ if(!v->IsPositionValid())
{
- if(GetTypeId() == TYPEID_UNIT || GetTypeId() == TYPEID_PLAYER)
- pCreature->setFaction(((Unit*)this)->getFaction());
- pCreature->CastSpell(pCreature, pCreature->m_spells[0], false, 0, 0, GetGUID());
+ sLog.outError("ERROR: Vehicle (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
+ v->GetGUIDLow(), v->GetEntry(), v->GetPositionX(), v->GetPositionY());
+ delete v;
+ return NULL;
}
- //return the creature therewith the summoner has access to it
- return pCreature;
+ map->Add((Creature*)v);
+
+ //ObjectAccessor::UpdateObjectVisibility(v);
+
+ return v;
}
Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 duration)
{
- Pet* pet = new Pet(petType);
+ Pet* pet = new Pet(this, petType);
if(petType == SUMMON_PET && pet->LoadPetFromDB(this, entry))
{
// Remove Demonic Sacrifice auras (known pet)
- Unit::AuraList const& auraClassScripts = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
+ Unit::AuraEffectList const& auraClassScripts = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraEffectList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
{
- if((*itr)->GetModifier()->m_miscvalue==2228)
+ if((*itr)->GetMiscValue()==2228)
{
RemoveAurasDueToSpell((*itr)->GetId());
itr = auraClassScripts.begin();
@@ -1667,7 +1906,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
Map *map = GetMap();
uint32 pet_number = objmgr.GeneratePetNumber();
- if(!pet->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, entry, pet_number))
+ if(!pet->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, GetPhaseMask(), entry, pet_number))
{
sLog.outError("no such creature entry %u", entry);
delete pet;
@@ -1683,38 +1922,44 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
return NULL;
}
- pet->SetOwnerGUID(GetGUID());
pet->SetCreatorGUID(GetGUID());
pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction());
- // this enables pet details window (Shift+P)
- pet->GetCharmInfo()->SetPetNumber(pet_number, false);
-
- pet->AIM_Initialize();
-
- map->Add((Creature*)pet);
-
pet->setPowerType(POWER_MANA);
pet->SetUInt32Value(UNIT_NPC_FLAGS , 0);
pet->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
pet->InitStatsForLevel(getLevel());
+ SetMinion(pet, true);
+
switch(petType)
{
- case GUARDIAN_PET:
case POSSESSED_PET:
- pet->SetUInt32Value(UNIT_FIELD_FLAGS,0);
- AddGuardian(pet);
+ pet->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
break;
case SUMMON_PET:
+ // this enables pet details window (Shift+P)
+ pet->GetCharmInfo()->SetPetNumber(pet_number, true);
pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
pet->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
pet->SetHealth(pet->GetMaxHealth());
pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA));
+ pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
+ break;
+ }
+
+ map->Add((Creature*)pet);
+
+ switch(petType)
+ {
+ case POSSESSED_PET:
+ pet->SetCharmedOrPossessedBy(this, true);
+ break;
+ case SUMMON_PET:
pet->InitPetCreateSpells();
+ pet->InitTalentForLevel();
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
- SetPet(pet);
PetSpellInitialize();
break;
}
@@ -1722,10 +1967,10 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
if(petType == SUMMON_PET)
{
// Remove Demonic Sacrifice auras (known pet)
- Unit::AuraList const& auraClassScripts = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
+ Unit::AuraEffectList const& auraClassScripts = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraEffectList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
{
- if((*itr)->GetModifier()->m_miscvalue==2228)
+ if((*itr)->GetMiscValue()==2228)
{
RemoveAurasDueToSpell((*itr)->GetId());
itr = auraClassScripts.begin();
@@ -1738,6 +1983,8 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
if(duration > 0)
pet->SetDuration(duration);
+ //ObjectAccessor::UpdateObjectVisibility(pet);
+
return pet;
}
@@ -1754,7 +2001,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float
}
Map *map = GetMap();
GameObject *go = new GameObject();
- if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry,map,x,y,z,ang,rotation0,rotation1,rotation2,rotation3,100,1))
+ if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, map, GetPhaseMask(), x,y,z,ang,rotation0,rotation1,rotation2,rotation3,100,GO_STATE_READY))
{
delete go;
return NULL;
@@ -1788,6 +2035,81 @@ Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint3
return summon;
}
+/*
+namespace MaNGOS
+{
+ class NearUsedPosDo
+ {
+ public:
+ NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float angle, ObjectPosSelector& selector)
+ : i_object(obj), i_searcher(searcher), i_angle(angle), i_selector(selector) {}
+
+ void operator()(Corpse*) const {}
+ void operator()(DynamicObject*) const {}
+
+ void operator()(Creature* c) const
+ {
+ // skip self or target
+ if(c==i_searcher || c==&i_object)
+ return;
+
+ float x,y,z;
+
+ if( !c->isAlive() || c->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) ||
+ !c->GetMotionMaster()->GetDestination(x,y,z) )
+ {
+ x = c->GetPositionX();
+ y = c->GetPositionY();
+ }
+
+ add(c,x,y);
+ }
+
+ template<class T>
+ void operator()(T* u) const
+ {
+ // skip self or target
+ if(u==i_searcher || u==&i_object)
+ return;
+
+ float x,y;
+
+ x = u->GetPositionX();
+ y = u->GetPositionY();
+
+ add(u,x,y);
+ }
+
+ // we must add used pos that can fill places around center
+ void add(WorldObject* u, float x, float y) const
+ {
+ // u is too nearest/far away to i_object
+ if(!i_object.IsInRange2d(x,y,i_selector.m_dist - i_selector.m_size,i_selector.m_dist + i_selector.m_size))
+ return;
+
+ float angle = i_object.GetAngle(u)-i_angle;
+
+ // move angle to range -pi ... +pi
+ while( angle > M_PI)
+ angle -= 2.0f * M_PI;
+ while(angle < -M_PI)
+ angle += 2.0f * M_PI;
+
+ // dist include size of u
+ float dist2d = i_object.GetDistance2d(x,y);
+ i_selector.AddUsedPos(u->GetObjectSize(),angle,dist2d + i_object.GetObjectSize());
+ }
+ private:
+ WorldObject const& i_object;
+ WorldObject const* i_searcher;
+ float i_angle;
+ ObjectPosSelector& i_selector;
+ };
+} // namespace MaNGOS
+*/
+
+//===================================================================================================
+
void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const
{
x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle);
@@ -1800,10 +2122,127 @@ void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float abs
void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const
{
GetNearPoint2D(x,y,distance2d+searcher_size,absAngle);
-
z = GetPositionZ();
-
UpdateGroundPositionZ(x,y,z);
+
+ /*
+ // if detection disabled, return first point
+ if(!sWorld.getConfig(CONFIG_DETECT_POS_COLLISION))
+ {
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+ return;
+ }
+
+ // or remember first point
+ float first_x = x;
+ float first_y = y;
+ bool first_los_conflict = false; // first point LOS problems
+
+ // prepare selector for work
+ ObjectPosSelector selector(GetPositionX(),GetPositionY(),GetObjectSize(),distance2d+searcher_size);
+
+ // adding used positions around object
+ {
+ CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::NearUsedPosDo u_do(*this,searcher,absAngle,selector);
+ MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(this,u_do);
+
+ TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, GridTypeMapContainer > grid_obj_worker(worker);
+ TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, WorldTypeMapContainer > world_obj_worker(worker);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap());
+ cell_lock->Visit(cell_lock, world_obj_worker, *GetMap());
+ }
+
+ // maybe can just place in primary position
+ if( selector.CheckOriginal() )
+ {
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+
+ first_los_conflict = true; // first point have LOS problems
+ }
+
+ float angle; // candidate of angle for free pos
+
+ // special case when one from list empty and then empty side preferred
+ if(selector.FirstAngle(angle))
+ {
+ GetNearPoint2D(x,y,distance2d,absAngle+angle);
+ z = GetPositionZ();
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+ }
+
+ // set first used pos in lists
+ selector.InitializeAngle();
+
+ // select in positions after current nodes (selection one by one)
+ while(selector.NextAngle(angle)) // angle for free pos
+ {
+ GetNearPoint2D(x,y,distance2d,absAngle+angle);
+ z = GetPositionZ();
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+ }
+
+ // BAD NEWS: not free pos (or used or have LOS problems)
+ // Attempt find _used_ pos without LOS problem
+
+ if(!first_los_conflict)
+ {
+ x = first_x;
+ y = first_y;
+
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+ return;
+ }
+
+ // special case when one from list empty and then empty side preferred
+ if( selector.IsNonBalanced() )
+ {
+ if(!selector.FirstAngle(angle)) // _used_ pos
+ {
+ GetNearPoint2D(x,y,distance2d,absAngle+angle);
+ z = GetPositionZ();
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+ }
+ }
+
+ // set first used pos in lists
+ selector.InitializeAngle();
+
+ // select in positions after current nodes (selection one by one)
+ while(selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
+ {
+ GetNearPoint2D(x,y,distance2d,absAngle+angle);
+ z = GetPositionZ();
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+ }
+
+ // BAD BAD NEWS: all found pos (free and used) have LOS problem :(
+ x = first_x;
+ y = first_y;
+
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+ */
}
void WorldObject::GetGroundPoint(float &x, float &y, float &z, float dist, float angle)
@@ -1816,5 +2255,31 @@ void WorldObject::GetGroundPoint(float &x, float &y, float &z, float dist, float
UpdateGroundPositionZ(x, y, z);
}
+void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update)
+{
+ m_phaseMask = newPhaseMask;
+
+ if(update && IsInWorld())
+ ObjectAccessor::UpdateObjectVisibility(this);
+}
+void WorldObject::PlayDistanceSound( uint32 sound_id, Player* target /*= NULL*/ )
+{
+ WorldPacket data(SMSG_PLAY_OBJECT_SOUND,4+8);
+ data << uint32(sound_id);
+ data << GetGUID();
+ if (target)
+ target->SendDirectMessage( &data );
+ else
+ SendMessageToSet( &data, true );
+}
+void WorldObject::PlayDirectSound( uint32 sound_id, Player* target /*= NULL*/ )
+{
+ WorldPacket data(SMSG_PLAY_SOUND, 4);
+ data << uint32(sound_id);
+ if (target)
+ target->SendDirectMessage( &data );
+ else
+ SendMessageToSet( &data, true );
+}
diff --git a/src/game/Object.h b/src/game/Object.h
index 328df30492a..2a79d2c22cb 100644
--- a/src/game/Object.h
+++ b/src/game/Object.h
@@ -28,7 +28,6 @@
#include "GameSystem/GridReference.h"
#include "ObjectDefines.h"
#include "GridDefines.h"
-#include "CreatureAI.h"
#include "Map.h"
#include <set>
@@ -36,6 +35,7 @@
#define CONTACT_DISTANCE 0.5f
#define INTERACTION_DISTANCE 5.0f
+#define ATTACK_DISTANCE 5.0f
#define MAX_VISIBILITY_DISTANCE (5*SIZE_OF_GRID_CELL/2.0f) // max distance for visible object show, limited by active zone for player based at cell size (active zone = 5x5 cells)
#define DEFAULT_VISIBILITY_DISTANCE (SIZE_OF_GRID_CELL) // default visible distance
@@ -50,13 +50,14 @@ enum TypeMask
TYPEMASK_OBJECT = 0x0001,
TYPEMASK_ITEM = 0x0002,
TYPEMASK_CONTAINER = 0x0006, // TYPEMASK_ITEM | 0x0004
- TYPEMASK_UNIT = 0x0008,
+ TYPEMASK_UNIT = 0x0008, //creature or player
TYPEMASK_PLAYER = 0x0010,
TYPEMASK_GAMEOBJECT = 0x0020,
TYPEMASK_DYNAMICOBJECT = 0x0040,
TYPEMASK_CORPSE = 0x0080,
TYPEMASK_AIGROUP = 0x0100,
- TYPEMASK_AREATRIGGER = 0x0200
+ TYPEMASK_AREATRIGGER = 0x0200,
+ TYPEMASK_SEER = TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT
};
enum TypeID
@@ -72,6 +73,7 @@ enum TypeID
TYPEID_AIGROUP = 8,
TYPEID_AREATRIGGER = 9
};
+#define MAX_TYPEID 10
uint32 GuidHigh2TypeId(uint32 guid_hi);
@@ -87,6 +89,12 @@ enum TempSummonType
TEMPSUMMON_MANUAL_DESPAWN = 8 // despawns when UnSummon() is called
};
+enum PhaseMasks
+{
+ PHASEMASK_NORMAL = 0x00000001,
+ PHASEMASK_ANYWHERE = 0xFFFFFFFF
+};
+
class WorldPacket;
class UpdateData;
class ByteBuffer;
@@ -96,6 +104,9 @@ class Player;
class UpdateMask;
class InstanceData;
class GameObject;
+class TempSummon;
+class Vehicle;
+class CreatureAI;
typedef UNORDERED_MAP<Player*, UpdateData> UpdateDataMapType;
@@ -117,7 +128,7 @@ class TRINITY_DLL_SPEC Object
public:
virtual ~Object ( );
- const bool& IsInWorld() const { return m_inWorld; }
+ const bool IsInWorld() const { return m_inWorld; }
virtual void AddToWorld()
{
if(m_inWorld)
@@ -193,7 +204,7 @@ class TRINITY_DLL_SPEC Object
return *(((uint8*)&m_uint32Values[ index ])+offset);
}
- uint8 GetUInt16Value( uint16 index, uint8 offset) const
+ uint16 GetUInt16Value( uint16 index, uint8 offset) const
{
ASSERT( index < m_valuesCount || PrintIndexError( index , false) );
ASSERT( offset < 2 );
@@ -210,6 +221,9 @@ class TRINITY_DLL_SPEC Object
void SetStatFloatValue( uint16 index, float value);
void SetStatInt32Value( uint16 index, int32 value);
+ bool AddUInt64Value( uint16 index, const uint64 &value );
+ bool RemoveUInt64Value( uint16 index, const uint64 &value );
+
void ApplyModUInt32Value(uint16 index, int32 val, bool apply);
void ApplyModInt32Value(uint16 index, int32 val, bool apply);
void ApplyModUInt64Value(uint16 index, int32 val, bool apply);
@@ -318,7 +332,7 @@ class TRINITY_DLL_SPEC Object
virtual void _SetUpdateBits(UpdateMask *updateMask, Player *target) const;
virtual void _SetCreateBits(UpdateMask *updateMask, Player *target) const;
- void _BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2 ) const;
+ void _BuildMovementUpdate(ByteBuffer * data, uint8 flags) const;
void _BuildValuesUpdate(uint8 updatetype, ByteBuffer *data, UpdateMask *updateMask, Player *target ) const;
uint16 m_objectType;
@@ -357,7 +371,15 @@ class TRINITY_DLL_SPEC WorldObject : public Object
virtual void Update ( uint32 /*time_diff*/ ) { }
- void _Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid );
+ void _Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask);
+
+ void Relocate(WorldObject *obj)
+ {
+ m_positionX = obj->GetPositionX();
+ m_positionY = obj->GetPositionY();
+ m_positionZ = obj->GetPositionZ();
+ m_orientation = obj->GetOrientation();
+ }
void Relocate(float x, float y, float z, float orientation)
{
@@ -423,8 +445,14 @@ class TRINITY_DLL_SPEC WorldObject : public Object
void SetInstanceId(uint32 val) { m_InstanceId = val; m_map = NULL; }
uint32 GetInstanceId() const { return m_InstanceId; }
+ virtual void SetPhaseMask(uint32 newPhaseMask, bool update);
+ uint32 GetPhaseMask() const { return m_phaseMask; }
+ bool InSamePhase(WorldObject const* obj) const { return InSamePhase(obj->GetPhaseMask()); }
+ bool InSamePhase(uint32 phasemask) const { return (GetPhaseMask() & phasemask); }
+
uint32 GetZoneId() const;
uint32 GetAreaId() const;
+ void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const;
InstanceData* GetInstanceData();
@@ -434,27 +462,47 @@ class TRINITY_DLL_SPEC WorldObject : public Object
virtual const char* GetNameForLocaleIdx(int32 /*locale_idx*/) const { return GetName(); }
float GetDistance( const WorldObject* obj ) const;
- float GetDistance(const float x, const float y, const float z) const;
+ float GetDistance(float x, float y, float z) const;
float GetDistanceSq(const float &x, const float &y, const float &z) const;
+ float GetDistanceSq(const WorldObject *obj) const;
float GetDistance2d(const WorldObject* obj) const;
- float GetDistance2d(const float x, const float y) const;
+ float GetDistance2d(float x, float y) const;
float GetExactDistance2d(const float x, const float y) const;
float GetDistanceZ(const WorldObject* obj) const;
- bool IsInMap(const WorldObject* obj) const { return GetMapId()==obj->GetMapId() && GetInstanceId()==obj->GetInstanceId(); }
- bool IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D = true) const;
- bool IsWithinLOS(const float x, const float y, const float z ) const;
+ bool IsInMap(const WorldObject* obj) const
+ {
+ return IsInWorld() && obj->IsInWorld() && GetMapId()==obj->GetMapId() &&
+ GetInstanceId()==obj->GetInstanceId() && InSamePhase(obj);
+ }
+ bool IsWithinDist3d(float x, float y, float z, float dist2compare) const;
+ bool IsWithinDist2d(float x, float y, float dist2compare) const;
+ bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const;
+ bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const
+ // use only if you will sure about placing both object at same map
+ {
+ return obj && _IsWithinDist(obj,dist2compare,is3D);
+ }
+ bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const
+ {
+ return obj && IsInMap(obj) && _IsWithinDist(obj,dist2compare,is3D);
+ }
+ bool IsWithinLOS(float x, float y, float z) const;
bool IsWithinLOSInMap(const WorldObject* obj) const;
+ bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const;
+ bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const;
+ bool IsInRange2d(float x, float y, float minRange, float maxRange) const;
+ bool IsInRange3d(float x, float y, float z, float minRange, float maxRange) const;
float GetAngle( const WorldObject* obj ) const;
float GetAngle( const float x, const float y ) const;
+ void GetSinCos(const float x, const float y, float &vsin, float &vcos);
bool HasInArc( const float arcangle, const WorldObject* obj ) const;
+ bool IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size = 0) const;
virtual void SendMessageToSet(WorldPacket *data, bool self, bool to_possessor = true);
virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor = true);
void BuildHeartBeatMsg( WorldPacket *data ) const;
void BuildTeleportAckMsg( WorldPacket *data, float x, float y, float z, float ang) const;
- bool IsBeingTeleported() { return mSemaphoreTeleport; }
- void SetSemaphoreTeleport(bool semphsetting) { mSemaphoreTeleport = semphsetting; }
void MonsterSay(const char* text, uint32 language, uint64 TargetGuid);
void MonsterYell(const char* text, uint32 language, uint64 TargetGuid);
@@ -464,8 +512,12 @@ class TRINITY_DLL_SPEC WorldObject : public Object
void MonsterYell(int32 textId, uint32 language, uint64 TargetGuid);
void MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false);
void MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisper = false);
+ void MonsterYellToZone(int32 textId, uint32 language, uint64 TargetGuid);
void BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* text, uint32 language, char const* name, uint64 TargetGuid) const;
+ void PlayDistanceSound(uint32 sound_id, Player* target = NULL);
+ void PlayDirectSound(uint32 sound_id, Player* target = NULL);
+
void SendObjectDeSpawnAnim(uint64 guid);
virtual void SaveRespawnTime() {}
@@ -484,9 +536,10 @@ class TRINITY_DLL_SPEC WorldObject : public Object
Map * GetMap() const { return m_map ? m_map : const_cast<WorldObject*>(this)->_getMap(); }
Map * FindMap() const { return m_map ? m_map : const_cast<WorldObject*>(this)->_findMap(); }
Map const* GetBaseMap() const;
- Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime);
+ TempSummon* SummonCreature(uint32 id, float x, float y, float z, float ang = 0,TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN,uint32 despwtime = 0);
+ Vehicle* SummonVehicle(uint32 entry, float x, float y, float z, float ang = 0);
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime);
- Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, CreatureAI* (*GetAI)(Creature*) = NULL);
+ Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, CreatureAI* (*GetAI)(Creature*) = NULL);
bool isActiveObject() const { return m_isActive; }
void setActive(bool isActiveObject);
void SetWorldObject(bool apply);
@@ -501,8 +554,9 @@ class TRINITY_DLL_SPEC WorldObject : public Object
bool m_isActive;
private:
- uint32 m_mapId;
- uint32 m_InstanceId;
+ uint32 m_mapId; // object at map with map_id
+ uint32 m_InstanceId; // in map copy with instance id
+ uint32 m_phaseMask; // in area phase state
Map *m_map;
Map* _getMap();
@@ -512,8 +566,6 @@ class TRINITY_DLL_SPEC WorldObject : public Object
float m_positionY;
float m_positionZ;
float m_orientation;
-
- bool mSemaphoreTeleport;
};
#endif
diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp
index 2182af0b751..0472c89a59f 100644
--- a/src/game/ObjectAccessor.cpp
+++ b/src/game/ObjectAccessor.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,8 +25,7 @@
#include "Creature.h"
#include "GameObject.h"
#include "DynamicObject.h"
-#include "Corpse.h"
-#include "WorldSession.h"
+#include "Vehicle.h"
#include "WorldPacket.h"
#include "Item.h"
#include "Corpse.h"
@@ -42,118 +41,26 @@
#include <cmath>
-#define CLASS_LOCK Trinity::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex>
+#define CLASS_LOCK MaNGOS::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex>
INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK);
-INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ZThread::FastMutex);
-
-namespace Trinity
-{
- struct TRINITY_DLL_DECL BuildUpdateForPlayer
- {
- Player &i_player;
- UpdateDataMapType &i_updatePlayers;
-
- BuildUpdateForPlayer(Player &player, UpdateDataMapType &data_map) : i_player(player), i_updatePlayers(data_map) {}
-
- void Visit(PlayerMapType &m)
- {
- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
- {
- if( iter->getSource() == &i_player )
- continue;
-
- UpdateDataMapType::iterator iter2 = i_updatePlayers.find(iter->getSource());
- if( iter2 == i_updatePlayers.end() )
- {
- std::pair<UpdateDataMapType::iterator, bool> p = i_updatePlayers.insert( ObjectAccessor::UpdateDataValueType(iter->getSource(), UpdateData()) );
- assert(p.second);
- iter2 = p.first;
- }
-
- i_player.BuildValuesUpdateBlockForPlayer(&iter2->second, iter2->first);
- }
- }
-
- template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
- };
-}
+INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex);
ObjectAccessor::ObjectAccessor() {}
ObjectAccessor::~ObjectAccessor() {}
Creature*
-ObjectAccessor::GetNPCIfCanInteractWith(Player const &player, uint64 guid, uint32 npcflagmask)
-{
- // unit checks
- if (!guid)
- return NULL;
-
- // exist
- Creature *unit = GetCreature(player, guid);
- if (!unit)
- return NULL;
-
- // player check
- if(!player.CanInteractWithNPCs(!unit->isSpiritService()))
- return NULL;
-
- // appropriate npc type
- if(npcflagmask && !unit->HasFlag( UNIT_NPC_FLAGS, npcflagmask ))
- return NULL;
-
- // alive or spirit healer
- if(!unit->isAlive() && (!unit->isSpiritService() || player.isAlive() ))
- return NULL;
-
- // not allow interaction under control
- if(unit->GetCharmerGUID())
- return NULL;
-
- // not enemy
- if( unit->IsHostileTo(&player))
- return NULL;
-
- // not unfriendly
- FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(unit->getFaction());
- if(factionTemplate)
- {
- FactionEntry const* faction = sFactionStore.LookupEntry(factionTemplate->faction);
- if( faction->reputationListID >= 0 && player.GetReputationRank(faction) <= REP_UNFRIENDLY)
- return NULL;
- }
-
- // not too far
- if(!unit->IsWithinDistInMap(&player,INTERACTION_DISTANCE))
- return NULL;
-
- return unit;
-}
-
-Creature*
-ObjectAccessor::GetCreatureOrPet(WorldObject const &u, uint64 guid)
+ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const &u, uint64 guid)
{
if(Creature *unit = GetPet(guid))
return unit;
- return GetCreature(u, guid);
-}
-
-Creature*
-ObjectAccessor::GetCreature(WorldObject const &u, uint64 guid)
-{
- Creature * ret = GetObjectInWorld(guid, (Creature*)NULL);
- if(!ret)
- return NULL;
-
- if(ret->GetMapId() != u.GetMapId())
- return NULL;
-
- if(ret->GetInstanceId() != u.GetInstanceId())
- return NULL;
+ if(Creature *unit = GetVehicle(guid))
+ return unit;
- return ret;
+ return u.GetMap()->GetCreature(guid);
}
+/*
Unit*
ObjectAccessor::GetUnit(WorldObject const &u, uint64 guid)
{
@@ -163,18 +70,24 @@ ObjectAccessor::GetUnit(WorldObject const &u, uint64 guid)
if(IS_PLAYER_GUID(guid))
return FindPlayer(guid);
- return GetCreatureOrPet(u, guid);
+ return GetCreatureOrPetOrVehicle(u, guid);
}
+*/
Corpse*
ObjectAccessor::GetCorpse(WorldObject const &u, uint64 guid)
{
Corpse * ret = GetObjectInWorld(guid, (Corpse*)NULL);
- if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL;
+ if(!ret)
+ return NULL;
+ if(ret->GetMapId() != u.GetMapId())
+ return NULL;
+ if(ret->GetInstanceId() != u.GetInstanceId())
+ return NULL;
return ret;
}
-Object* ObjectAccessor::GetObjectByTypeMask(Player const &p, uint64 guid, uint32 typemask)
+Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const &p, uint64 guid, uint32 typemask)
{
Object *obj = NULL;
@@ -186,47 +99,31 @@ Object* ObjectAccessor::GetObjectByTypeMask(Player const &p, uint64 guid, uint32
if(typemask & TYPEMASK_UNIT)
{
- obj = GetCreatureOrPet(p,guid);
+ obj = GetCreatureOrPetOrVehicle(p,guid);
if(obj) return obj;
}
if(typemask & TYPEMASK_GAMEOBJECT)
{
- obj = GetGameObject(p,guid);
+ obj = p.GetMap()->GetGameObject(guid);
if(obj) return obj;
}
if(typemask & TYPEMASK_DYNAMICOBJECT)
{
- obj = GetDynamicObject(p,guid);
+ obj = p.GetMap()->GetDynamicObject(guid);
if(obj) return obj;
}
- if(typemask & TYPEMASK_ITEM)
+ if(typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER)
{
- obj = p.GetItemByGuid( guid );
+ obj = ((Player const &)p).GetItemByGuid( guid );
if(obj) return obj;
}
return NULL;
}
-GameObject*
-ObjectAccessor::GetGameObject(WorldObject const &u, uint64 guid)
-{
- GameObject * ret = GetObjectInWorld(guid, (GameObject*)NULL);
- if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL;
- return ret;
-}
-
-DynamicObject*
-ObjectAccessor::GetDynamicObject(Unit const &u, uint64 guid)
-{
- DynamicObject * ret = GetObjectInWorld(guid, (DynamicObject*)NULL);
- if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL;
- return ret;
-}
-
Player*
ObjectAccessor::FindPlayer(uint64 guid)
{
@@ -274,48 +171,15 @@ ObjectAccessor::UpdateObject(Object* obj, Player* exceptPlayer)
}
void
-ObjectAccessor::AddUpdateObject(Object *obj)
-{
- Guard guard(i_updateGuard);
- i_objects.insert(obj);
-}
-
-void
-ObjectAccessor::RemoveUpdateObject(Object *obj)
-{
- Guard guard(i_updateGuard);
- std::set<Object *>::iterator iter = i_objects.find(obj);
- if( iter != i_objects.end() )
- i_objects.erase( iter );
-}
-
-void
ObjectAccessor::_buildUpdateObject(Object *obj, UpdateDataMapType &update_players)
{
- bool build_for_all = true;
- Player *pl = NULL;
- if( obj->isType(TYPEMASK_ITEM) )
- {
- Item *item = static_cast<Item *>(obj);
- pl = item->GetOwner();
- build_for_all = false;
- }
-
- if( pl != NULL )
- _buildPacket(pl, obj, update_players);
-
- // Capt: okey for all those fools who think its a real fix
- // THIS IS A TEMP FIX
- if( build_for_all )
+ if(obj->isType(TYPEMASK_ITEM))
{
- WorldObject * temp = dynamic_cast<WorldObject*>(obj);
-
- //assert(dynamic_cast<WorldObject*>(obj)!=NULL);
- if (temp)
- _buildChangeObjectForPlayer(temp, update_players);
- else
- sLog.outDebug("ObjectAccessor: Ln 405 Temp bug fix");
+ if(Player *owner = ((Item*)obj)->GetOwner())
+ _buildPacket(owner, obj, update_players);
}
+ else
+ _buildChangeObjectForPlayer((WorldObject*)obj, update_players);
}
void
@@ -352,6 +216,12 @@ ObjectAccessor::GetPet(uint64 guid)
return GetObjectInWorld(guid, (Pet*)NULL);
}
+Vehicle*
+ObjectAccessor::GetVehicle(uint64 guid)
+{
+ return GetObjectInWorld(guid, (Vehicle*)NULL);
+}
+
Corpse*
ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid)
{
@@ -431,11 +301,11 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia)
{
//in fact this function is called from several places
//even when player doesn't have a corpse, not an error
- //sLog.outError("ERROR: Try remove corpse that not in map for GUID %ul", player_guid);
+ //sLog.outError("Try remove corpse that not in map for GUID %ul", player_guid);
return NULL;
}
- DEBUG_LOG("Deleting Corpse and spawning bones.\n");
+ DEBUG_LOG("Deleting Corpse and spawning bones.");
// remove corpse from player_guid -> corpse map
RemoveCorpse(corpse);
@@ -452,7 +322,7 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia)
// create the bones only if the map and the grid is loaded at the corpse's location
// ignore bones creating option in case insignia
if (map && (insignia ||
- (map->IsBattleGroundOrArena() ? sWorld.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld.getConfig(CONFIG_DEATH_BONES_WORLD))) &&
+ (map->IsBattleGroundOrArena() ? sWorld.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld.getConfig(CONFIG_DEATH_BONES_WORLD))) &&
!map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
{
// Create bones, don't change Corpse
@@ -469,6 +339,7 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia)
bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
bones->SetMapId(corpse->GetMapId());
bones->SetInstanceId(corpse->GetInstanceId());
+ bones->SetPhaseMask(corpse->GetPhaseMask(),false);
bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0);
@@ -498,9 +369,8 @@ ObjectAccessor::Update(uint32 diff)
while(!i_objects.empty())
{
Object* obj = *i_objects.begin();
+ assert(obj && obj->IsInWorld());
i_objects.erase(i_objects.begin());
- if (!obj || !obj->IsInWorld())
- continue;
_buildUpdateObject(obj, update_players);
obj->ClearUpdateMask(false);
}
@@ -558,11 +428,13 @@ ObjectAccessor::WorldObjectChangeAccumulator::Visit(DynamicObjectMapType &m)
{
for(DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
- if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID()))
+ uint64 guid = iter->getSource()->GetCasterGUID();
+ if(IS_PLAYER_GUID(guid))
{
- Player* caster = (Player*)iter->getSource()->GetCaster();
- if (caster->GetUInt64Value(PLAYER_FARSIGHT) == iter->getSource()->GetGUID())
- BuildPacket(caster);
+ //Caster may be NULL if DynObj is in removelist
+ if(Player *caster = FindPlayer(guid))
+ if (caster->GetUInt64Value(PLAYER_FARSIGHT) == iter->getSource()->GetGUID())
+ BuildPacket(caster);
}
}
}
@@ -600,12 +472,13 @@ ObjectAccessor::UpdateObjectVisibility(WorldObject *obj)
/// Define the static member of HashMapHolder
template <class T> UNORDERED_MAP< uint64, T* > HashMapHolder<T>::m_objectMap;
-template <class T> ZThread::FastMutex HashMapHolder<T>::i_lock;
+template <class T> ACE_Thread_Mutex HashMapHolder<T>::i_lock;
/// Global definitions for the hashmap storage
template class HashMapHolder<Player>;
template class HashMapHolder<Pet>;
+template class HashMapHolder<Vehicle>;
template class HashMapHolder<GameObject>;
template class HashMapHolder<DynamicObject>;
template class HashMapHolder<Creature>;
@@ -613,6 +486,7 @@ template class HashMapHolder<Corpse>;
template Player* ObjectAccessor::GetObjectInWorld<Player>(uint32 mapid, float x, float y, uint64 guid, Player* /*fake*/);
template Pet* ObjectAccessor::GetObjectInWorld<Pet>(uint32 mapid, float x, float y, uint64 guid, Pet* /*fake*/);
+template Vehicle* ObjectAccessor::GetObjectInWorld<Vehicle>(uint32 mapid, float x, float y, uint64 guid, Vehicle* /*fake*/);
template Creature* ObjectAccessor::GetObjectInWorld<Creature>(uint32 mapid, float x, float y, uint64 guid, Creature* /*fake*/);
template Corpse* ObjectAccessor::GetObjectInWorld<Corpse>(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/);
template GameObject* ObjectAccessor::GetObjectInWorld<GameObject>(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/);
diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h
index 9399035afd8..1e4074684f1 100644
--- a/src/game/ObjectAccessor.h
+++ b/src/game/ObjectAccessor.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@
#include "Platform/Define.h"
#include "Policies/Singleton.h"
-#include "zthread/FastMutex.h"
+#include <ace/Thread_Mutex.h>
#include "Utilities/UnorderedMap.h"
#include "Policies/ThreadingModel.h"
@@ -41,6 +41,7 @@ class Corpse;
class Unit;
class GameObject;
class DynamicObject;
+class Vehicle;
class WorldObject;
class Map;
@@ -50,17 +51,15 @@ class HashMapHolder
public:
typedef UNORDERED_MAP< uint64, T* > MapType;
- typedef ZThread::FastMutex LockType;
- typedef Trinity::GeneralLock<LockType > Guard;
+ typedef ACE_Thread_Mutex LockType;
+ typedef MaNGOS::GeneralLock<LockType > Guard;
static void Insert(T* o) { m_objectMap[o->GetGUID()] = o; }
static void Remove(T* o)
{
Guard guard(i_lock);
- typename MapType::iterator itr = m_objectMap.find(o->GetGUID());
- if (itr != m_objectMap.end())
- m_objectMap.erase(itr);
+ m_objectMap.erase(o->GetGUID());
}
static T* Find(uint64 guid)
@@ -81,7 +80,7 @@ class HashMapHolder
static MapType m_objectMap;
};
-class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor, Trinity::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex> >
+class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor, MaNGOS::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex> >
{
friend class Trinity::OperatorNew<ObjectAccessor>;
@@ -104,13 +103,16 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
if(!guid)
return NULL;
- if (IS_PLAYER_GUID(guid))
+ if(IS_PLAYER_GUID(guid))
return (Unit*)HashMapHolder<Player>::Find(guid);
- if (Unit* u = (Unit*)HashMapHolder<Pet>::Find(guid))
- return u;
+ if(IS_CREATURE_GUID(guid))
+ return (Unit*)HashMapHolder<Creature>::Find(guid);
- return (Unit*)HashMapHolder<Creature>::Find(guid);
+ if(IS_PET_GUID(guid))
+ return (Unit*)HashMapHolder<Pet>::Find(guid);
+
+ return (Unit*)HashMapHolder<Vehicle>::Find(guid);
}
template<class T> static T* GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, T* /*fake*/)
@@ -139,17 +141,14 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
else return NULL;
}
- static Object* GetObjectByTypeMask(Player const &, uint64, uint32 typemask);
- static Creature* GetNPCIfCanInteractWith(Player const &player, uint64 guid, uint32 npcflagmask);
- static Creature* GetCreature(WorldObject const &, uint64);
- static Creature* GetCreatureOrPet(WorldObject const &, uint64);
- static Unit* GetUnit(WorldObject const &, uint64);
+ static Object* GetObjectByTypeMask(WorldObject const &, uint64, uint32 typemask);
+ static Creature* GetCreatureOrPetOrVehicle(WorldObject const &, uint64);
+ static Unit* GetUnit(WorldObject const &, uint64 guid) { return GetObjectInWorld(guid, (Unit*)NULL); }
static Pet* GetPet(Unit const &, uint64 guid) { return GetPet(guid); }
static Player* GetPlayer(Unit const &, uint64 guid) { return FindPlayer(guid); }
- static GameObject* GetGameObject(WorldObject const &, uint64);
- static DynamicObject* GetDynamicObject(Unit const &, uint64);
static Corpse* GetCorpse(WorldObject const &u, uint64 guid);
static Pet* GetPet(uint64 guid);
+ static Vehicle* GetVehicle(uint64 guid);
static Player* FindPlayer(uint64);
Player* FindPlayerByName(const char *name) ;
@@ -159,6 +158,16 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
return HashMapHolder<Player>::GetContainer();
}
+ HashMapHolder<Creature>::MapType& GetCreatures()
+ {
+ return HashMapHolder<Creature>::GetContainer();
+ }
+
+ HashMapHolder<GameObject>::MapType& GetGameObjects()
+ {
+ return HashMapHolder<GameObject>::GetContainer();
+ }
+
template<class T> void AddObject(T *object)
{
HashMapHolder<T>::Insert(object);
@@ -174,16 +183,22 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
HashMapHolder<Player>::Remove(pl);
Guard guard(i_updateGuard);
-
- std::set<Object *>::iterator iter2 = std::find(i_objects.begin(), i_objects.end(), (Object *)pl);
- if( iter2 != i_objects.end() )
- i_objects.erase(iter2);
+ i_objects.erase((Object *)pl);
}
void SaveAllPlayers();
- void AddUpdateObject(Object *obj);
- void RemoveUpdateObject(Object *obj);
+ void AddUpdateObject(Object *obj)
+ {
+ Guard guard(i_updateGuard);
+ i_objects.insert(obj);
+ }
+
+ void RemoveUpdateObject(Object *obj)
+ {
+ Guard guard(i_updateGuard);
+ i_objects.erase( obj );
+ }
void Update(uint32 diff);
void UpdatePlayers(uint32 diff);
@@ -216,8 +231,8 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
friend struct WorldObjectChangeAccumulator;
Player2CorpsesMapType i_player2corpse;
- typedef ZThread::FastMutex LockType;
- typedef Trinity::GeneralLock<LockType > Guard;
+ typedef ACE_Thread_Mutex LockType;
+ typedef MaNGOS::GeneralLock<LockType > Guard;
static void _buildChangeObjectForPlayer(WorldObject *, UpdateDataMapType &);
static void _buildPacket(Player *, Object *, UpdateDataMapType &);
diff --git a/src/game/ObjectDefines.h b/src/game/ObjectDefines.h
index 53a0174ba2f..ee58e8a5f34 100644
--- a/src/game/ObjectDefines.h
+++ b/src/game/ObjectDefines.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,6 +41,7 @@ enum HighGuid
HIGHGUID_TRANSPORT = 0xF120, // blizz F120 (for GAMEOBJECT_TYPE_TRANSPORT)
HIGHGUID_UNIT = 0xF130, // blizz F130
HIGHGUID_PET = 0xF140, // blizz F140
+ HIGHGUID_VEHICLE = 0xF150, // blizz F550
HIGHGUID_DYNAMICOBJECT = 0xF100, // blizz F100
HIGHGUID_CORPSE = 0xF101, // blizz F100
HIGHGUID_MO_TRANSPORT = 0x1FC0, // blizz 1FC0 (for GAMEOBJECT_TYPE_MO_TRANSPORT)
@@ -50,6 +51,7 @@ enum HighGuid
#define IS_CREATURE_GUID(Guid) ( GUID_HIPART(Guid) == HIGHGUID_UNIT )
#define IS_PET_GUID(Guid) ( GUID_HIPART(Guid) == HIGHGUID_PET )
+#define IS_VEHICLE_GUID(Guid) ( GUID_HIPART(Guid) == HIGHGUID_VEHICLE )
#define IS_CREATURE_OR_PET_GUID(Guid)( IS_CREATURE_GUID(Guid) || IS_PET_GUID(Guid) )
#define IS_PLAYER_GUID(Guid) ( GUID_HIPART(Guid) == HIGHGUID_PLAYER && Guid!=0 )
#define IS_UNIT_GUID(Guid) ( IS_CREATURE_OR_PET_GUID(Guid) || IS_PLAYER_GUID(Guid) )
@@ -87,6 +89,7 @@ inline bool IsGuidHaveEnPart(uint64 const& guid)
case HIGHGUID_TRANSPORT:
case HIGHGUID_UNIT:
case HIGHGUID_PET:
+ case HIGHGUID_VEHICLE:
case HIGHGUID_MO_TRANSPORT:
default:
return true;
@@ -106,6 +109,7 @@ inline char const* GetLogNameForGuid(uint64 guid)
case HIGHGUID_TRANSPORT: return "transport";
case HIGHGUID_UNIT: return "creature";
case HIGHGUID_PET: return "pet";
+ case HIGHGUID_VEHICLE: return "vehicle";
case HIGHGUID_DYNAMICOBJECT:return "dynobject";
case HIGHGUID_CORPSE: return "corpse";
case HIGHGUID_MO_TRANSPORT: return "mo_transport";
diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp
index b819182a50d..368edce0a53 100644
--- a/src/game/ObjectGridLoader.cpp
+++ b/src/game/ObjectGridLoader.cpp
@@ -22,11 +22,13 @@
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Creature.h"
+#include "Vehicle.h"
#include "GameObject.h"
#include "DynamicObject.h"
#include "Corpse.h"
#include "World.h"
#include "CellImpl.h"
+#include "CreatureAI.h"
class TRINITY_DLL_DECL ObjectGridRespawnMover
{
@@ -57,7 +59,7 @@ ObjectGridRespawnMover::Visit(CreatureMapType &m)
Creature * c = iter->getSource();
++iter;
- assert(!c->isPet() && "ObjectGridRespawnMover don't must be called for pets");
+ assert(!c->isWorldCreature() && "ObjectGridRespawnMover don't must be called for pets");
Cell const& cur_cell = c->GetCurrentCell();
@@ -133,6 +135,36 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager<T> &
}
}
+void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, CreatureMapType &m, uint32 &count, Map* map)
+{
+ for(CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid)
+ {
+ Creature* obj = new Creature;
+ uint32 guid = *i_guid;
+ //sLog.outString("DEBUG: LoadHelper from table: %s for (guid: %u) Loading",table,guid);
+ if(!obj->LoadFromDB(guid, map))
+ {
+ delete obj;
+ obj = new Vehicle;
+ if(!((Vehicle*)obj)->LoadFromDB(guid, map))
+ {
+ delete (Vehicle*)obj;
+ continue;
+ }
+ }
+
+ obj->GetGridRef().link(&m, obj);
+
+ addUnitState(obj,cell);
+ obj->AddToWorld();
+ if(obj->isActiveObject())
+ map->AddToActive(obj);
+
+ ++count;
+
+ }
+}
+
void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType &m, uint32 &count, Map* map)
{
if(cell_corpses.empty())
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 227b0f90f28..d7337fadd77 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,14 +30,13 @@
#include "SpellMgr.h"
#include "UpdateMask.h"
#include "World.h"
-#include "WorldSession.h"
#include "Group.h"
#include "Guild.h"
#include "ArenaTeam.h"
#include "Transports.h"
#include "ProgressBar.h"
#include "Language.h"
-#include "GameEvent.h"
+#include "GameEventMgr.h"
#include "Spell.h"
#include "Chat.h"
#include "AccountMgr.h"
@@ -116,6 +115,7 @@ ObjectMgr::ObjectMgr()
m_hiCharGuid = 1;
m_hiCreatureGuid = 1;
m_hiPetGuid = 1;
+ m_hiVehicleGuid = 1;
m_hiItemGuid = 1;
m_hiGoGuid = 1;
m_hiDoGuid = 1;
@@ -127,14 +127,6 @@ ObjectMgr::ObjectMgr()
m_arenaTeamId = 1;
m_auctionid = 1;
- mGuildBankTabPrice.resize(GUILD_BANK_MAX_TABS);
- mGuildBankTabPrice[0] = 100;
- mGuildBankTabPrice[1] = 250;
- mGuildBankTabPrice[2] = 500;
- mGuildBankTabPrice[3] = 1000;
- mGuildBankTabPrice[4] = 2500;
- mGuildBankTabPrice[5] = 5000;
-
// Only zero condition left, others will be added while loading DB tables
mConditions.resize(1);
}
@@ -142,24 +134,10 @@ ObjectMgr::ObjectMgr()
ObjectMgr::~ObjectMgr()
{
for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++i )
- {
- delete i->second;
- }
- mQuestTemplates.clear( );
-
- for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++i )
- {
delete i->second;
- }
- mGossipText.clear( );
-
- mAreaTriggers.clear();
for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++i )
- {
delete[] i->second;
- }
- petInfo.clear();
// free only if loaded
for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
@@ -251,7 +229,7 @@ Group * ObjectMgr::GetGroupByLeader(const uint64 &guid) const
return NULL;
}
-Guild * ObjectMgr::GetGuildById(const uint32 GuildId) const
+Guild * ObjectMgr::GetGuildById(uint32 GuildId) const
{
GuildMap::const_iterator itr = mGuildMap.find(GuildId);
if (itr != mGuildMap.end())
@@ -269,7 +247,7 @@ Guild * ObjectMgr::GetGuildByName(const std::string& guildname) const
return NULL;
}
-std::string ObjectMgr::GetGuildNameById(const uint32 GuildId) const
+std::string ObjectMgr::GetGuildNameById(uint32 GuildId) const
{
GuildMap::const_iterator itr = mGuildMap.find(GuildId);
if (itr != mGuildMap.end())
@@ -296,7 +274,8 @@ void ObjectMgr::RemoveGuild(uint32 Id)
{
mGuildMap.erase(Id);
}
-ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 arenateamid) const
+
+ArenaTeam* ObjectMgr::GetArenaTeamById(uint32 arenateamid) const
{
ArenaTeamMap::const_iterator itr = mArenaTeamMap.find(arenateamid);
if (itr != mArenaTeamMap.end())
@@ -350,7 +329,7 @@ void ObjectMgr::LoadCreatureLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 creature locale strings. DB table `locales_creature` is empty.");
return;
}
@@ -398,7 +377,7 @@ void ObjectMgr::LoadCreatureLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu creature locale strings", (unsigned long)mCreatureLocaleMap.size() );
}
void ObjectMgr::LoadNpcOptionLocales()
@@ -418,7 +397,7 @@ void ObjectMgr::LoadNpcOptionLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 npc_option locale strings. DB table `locales_npc_option` is empty.");
return;
}
@@ -466,13 +445,64 @@ void ObjectMgr::LoadNpcOptionLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u npc_option locale strings", mNpcOptionLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu npc_option locale strings", (unsigned long)mNpcOptionLocaleMap.size() );
+}
+
+void ObjectMgr::LoadPointOfInterestLocales()
+{
+ mPointOfInterestLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,icon_name_loc1,icon_name_loc2,icon_name_loc3,icon_name_loc4,icon_name_loc5,icon_name_loc6,icon_name_loc7,icon_name_loc8 FROM locales_points_of_interest");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded 0 points_of_interest locale strings. DB table `locales_points_of_interest` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ PointOfInterestLocale& data = mPointOfInterestLocaleMap[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[i].GetCppString();
+ if(str.empty())
+ continue;
+
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.IconName.size() <= idx)
+ data.IconName.resize(idx+1);
+
+ data.IconName[idx] = str;
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %lu points_of_interest locale strings", (unsigned long)mPointOfInterestLocaleMap.size() );
}
struct SQLCreatureLoader : public SQLStorageLoaderBase<SQLCreatureLoader>
{
template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
+ void convert_from_str(uint32 /*field_pos*/, char *src, D &dst)
{
dst = D(objmgr.GetScriptId(src));
}
@@ -553,6 +583,18 @@ void ObjectMgr::LoadCreatureTemplates()
continue;
}
+ if(heroicInfo->AIName && *heroicInfo->AIName)
+ {
+ sLog.outErrorDb("Heroic mode creature (Entry: %u) has `AIName`, but in any case will used normal mode creature (Entry: %u) AIName.",cInfo->HeroicEntry,i);
+ continue;
+ }
+
+ if(heroicInfo->ScriptID)
+ {
+ sLog.outErrorDb("Heroic mode creature (Entry: %u) has `ScriptName`, but in any case will used normal mode creature (Entry: %u) ScriptName.",cInfo->HeroicEntry,i);
+ continue;
+ }
+
hasHeroicEntries.insert(i);
heroicEntries.insert(cInfo->HeroicEntry);
}
@@ -602,6 +644,19 @@ void ObjectMgr::LoadCreatureTemplates()
if((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type);
+ if(cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`",cInfo->Entry,cInfo->type);
+ const_cast<CreatureInfo*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
+ }
+
+ // must exist or used hidden but used in data horse case
+ if(cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM )
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`",cInfo->Entry,cInfo->family);
+ const_cast<CreatureInfo*>(cInfo)->family = 0;
+ }
+
if(cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
{
sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType);
@@ -615,6 +670,15 @@ void ObjectMgr::LoadCreatureTemplates()
sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId);
}
+ for(int j = 0; j < CREATURE_MAX_SPELLS; ++j)
+ {
+ if(cInfo->spells[j] && !sSpellStore.LookupEntry(cInfo->spells[j]))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing Spell%d (%u), set to 0", cInfo->Entry, j+1,cInfo->spells[j]);
+ const_cast<CreatureInfo*>(cInfo)->spells[j] = 0;
+ }
+ }
+
if(cInfo->MovementType >= MAX_DB_MOTION_TYPE)
{
sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType);
@@ -763,8 +827,47 @@ void ObjectMgr::LoadEquipmentTemplates()
{
sEquipmentStorage.Load();
+ for(uint32 i=0; i< sEquipmentStorage.MaxEntry; ++i)
+ {
+ EquipmentInfo const* eqInfo = sEquipmentStorage.LookupEntry<EquipmentInfo>(i);
+
+ if(!eqInfo)
+ continue;
+
+ for(uint8 j=0; j<3; j++)
+ {
+ if(!eqInfo->equipentry[j])
+ continue;
+
+ ItemEntry const *dbcitem = sItemStore.LookupEntry(eqInfo->equipentry[j]);
+
+ if(!dbcitem)
+ {
+ sLog.outErrorDb("Unknown item (entry=%u) in creature_equip_template.equipentry%u for entry = %u, forced to 0.", eqInfo->equipentry[j], j+1, i);
+ const_cast<EquipmentInfo*>(eqInfo)->equipentry[j] = 0;
+ continue;
+ }
+
+ if(dbcitem->InventoryType != INVTYPE_WEAPON &&
+ dbcitem->InventoryType != INVTYPE_SHIELD &&
+ dbcitem->InventoryType != INVTYPE_RANGED &&
+ dbcitem->InventoryType != INVTYPE_2HWEAPON &&
+ dbcitem->InventoryType != INVTYPE_WEAPONMAINHAND &&
+ dbcitem->InventoryType != INVTYPE_WEAPONOFFHAND &&
+ dbcitem->InventoryType != INVTYPE_HOLDABLE &&
+ dbcitem->InventoryType != INVTYPE_THROWN &&
+ dbcitem->InventoryType != INVTYPE_RANGEDRIGHT)
+ {
+ sLog.outErrorDb("Item (entry=%u) in creature_equip_template.equipentry%u for entry = %u is not equipable in a hand, forced to 0.", eqInfo->equipentry[j], j+1, i);
+ const_cast<EquipmentInfo*>(eqInfo)->equipentry[j] = 0;
+ }
+ }
+ }
sLog.outString( ">> Loaded %u equipment template", sEquipmentStorage.RecordCount );
sLog.outString();
+
+ // Creature items can be not listed in item_template
+ //sItemStore.Clear(); -- so used in spell casting
}
CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid)
@@ -924,9 +1027,10 @@ void ObjectMgr::LoadCreatures()
QueryResult *result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid,"
// 4 5 6 7 8 9 10 11
"equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint,"
- // 12 13 14 15 16 17
- "curhealth, curmana, DeathState, MovementType, spawnMask, event "
- "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid");
+ // 12 13 14 15 16 17 18 19
+ "curhealth, curmana, DeathState, MovementType, spawnMask, phaseMask, event, pool_entry "
+ "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid "
+ "LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid");
if(!result)
{
@@ -934,7 +1038,7 @@ void ObjectMgr::LoadCreatures()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty.");
return;
}
@@ -953,11 +1057,19 @@ void ObjectMgr::LoadCreatures()
Field *fields = result->Fetch();
bar.step();
- uint32 guid = fields[0].GetUInt32();
+ uint32 guid = fields[ 0].GetUInt32();
+ uint32 entry = fields[ 1].GetUInt32();
+
+ CreatureInfo const* cInfo = GetCreatureTemplate(entry);
+ if(!cInfo)
+ {
+ sLog.outErrorDb("Table `creature` has creature (GUID: %u) with non existing creature entry %u, skipped.", guid, entry);
+ continue;
+ }
CreatureData& data = mCreatureDataMap[guid];
- data.id = fields[ 1].GetUInt32();
+ data.id = entry;
data.mapid = fields[ 2].GetUInt32();
data.displayid = fields[ 3].GetUInt32();
data.equipmentId = fields[ 4].GetUInt32();
@@ -973,14 +1085,9 @@ void ObjectMgr::LoadCreatures()
data.is_dead = fields[14].GetBool();
data.movementType = fields[15].GetUInt8();
data.spawnMask = fields[16].GetUInt8();
- int16 gameEvent = fields[17].GetInt16();
-
- CreatureInfo const* cInfo = GetCreatureTemplate(data.id);
- if(!cInfo)
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u) with not existed creature entry %u, skipped.",guid,data.id );
- continue;
- }
+ data.phaseMask = fields[17].GetUInt16();
+ int16 gameEvent = fields[18].GetInt16();
+ int16 PoolId = fields[19].GetInt16();
if(heroicCreatures.find(data.id)!=heroicCreatures.end())
{
@@ -1003,6 +1110,13 @@ void ObjectMgr::LoadCreatures()
data.curhealth = cInfo->minhealth;
}
+ if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
+ {
+ MapEntry const* map = sMapStore.LookupEntry(data.mapid);
+ if(!map || !map->IsDungeon())
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id);
+ }
+
if(data.curmana < cInfo->minmana)
{
sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana );
@@ -1031,8 +1145,15 @@ void ObjectMgr::LoadCreatures()
}
}
- if (gameEvent==0) // if not this is to be managed by GameEvent System
+ if(data.phaseMask==0)
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.",guid,data.id );
+ data.phaseMask = 1;
+ }
+
+ if (gameEvent==0 && PoolId==0) // if not this is to be managed by GameEvent System or Pool system
AddCreatureToGrid(guid, &data);
+
++count;
} while (result->NextRow());
@@ -1040,7 +1161,7 @@ void ObjectMgr::LoadCreatures()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u creatures", mCreatureDataMap.size() );
+ sLog.outString( ">> Loaded %lu creatures", (unsigned long)mCreatureDataMap.size() );
}
void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data)
@@ -1081,9 +1202,10 @@ void ObjectMgr::LoadGameobjects()
// 0 1 2 3 4 5 6
QueryResult *result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation,"
- // 7 8 9 10 11 12 13 14 15
- "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, event "
- "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid");
+ // 7 8 9 10 11 12 13 14 15 16 17
+ "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, event, pool_entry "
+ "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid "
+ "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid");
if(!result)
{
@@ -1103,11 +1225,19 @@ void ObjectMgr::LoadGameobjects()
Field *fields = result->Fetch();
bar.step();
- uint32 guid = fields[0].GetUInt32();
+ uint32 guid = fields[ 0].GetUInt32();
+ uint32 entry = fields[ 1].GetUInt32();
+
+ GameObjectInfo const* gInfo = GetGameObjectInfo(entry);
+ if(!gInfo)
+ {
+ sLog.outErrorDb("Table `gameobject` has gameobject (GUID: %u) with non existing gameobject entry %u, skipped.", guid, entry);
+ continue;
+ }
GameObjectData& data = mGameObjectDataMap[guid];
- data.id = fields[ 1].GetUInt32();
+ data.id = entry;
data.mapid = fields[ 2].GetUInt32();
data.posX = fields[ 3].GetFloat();
data.posY = fields[ 4].GetFloat();
@@ -1119,19 +1249,46 @@ void ObjectMgr::LoadGameobjects()
data.rotation3 = fields[10].GetFloat();
data.spawntimesecs = fields[11].GetInt32();
data.animprogress = fields[12].GetUInt32();
- data.go_state = fields[13].GetUInt32();
data.ArtKit = 0;
+
+ uint32 go_state = fields[13].GetUInt32();
+ if (go_state >= MAX_GO_STATE)
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid `state` (%u) value, skip",guid,data.id,go_state);
+ continue;
+ }
+ data.go_state = GOState(go_state);
+
data.spawnMask = fields[14].GetUInt8();
- int16 gameEvent = fields[15].GetInt16();
+ data.phaseMask = fields[15].GetUInt16();
+ int16 gameEvent = fields[16].GetInt16();
+ int16 PoolId = fields[17].GetInt16();
- GameObjectInfo const* gInfo = GetGameObjectInfo(data.id);
- if(!gInfo)
+ if(data.rotation2 < -1.0f || data.rotation2 > 1.0f)
{
- sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u) with not existed gameobject entry %u, skipped.",guid,data.id );
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation2 (%f) value, skip",guid,data.id,data.rotation2 );
continue;
}
- if (gameEvent==0) // if not this is to be managed by GameEvent System
+ if(data.rotation3 < -1.0f || data.rotation3 > 1.0f)
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation3 (%f) value, skip",guid,data.id,data.rotation3 );
+ continue;
+ }
+
+ if(!MapManager::IsValidMapCoord(data.mapid,data.posX,data.posY,data.posZ,data.orientation))
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid coordinates, skip",guid,data.id );
+ continue;
+ }
+
+ if(data.phaseMask==0)
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.",guid,data.id );
+ data.phaseMask = 1;
+ }
+
+ if (gameEvent==0 && PoolId==0) // if not this is to be managed by GameEvent System or Pool system
AddGameobjectToGrid(guid, &data);
++count;
@@ -1140,7 +1297,7 @@ void ObjectMgr::LoadGameobjects()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u gameobjects", mGameObjectDataMap.size());
+ sLog.outString( ">> Loaded %lu gameobjects", (unsigned long)mGameObjectDataMap.size());
}
void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data)
@@ -1210,7 +1367,7 @@ void ObjectMgr::LoadCreatureRespawnTimes()
delete result;
- sLog.outString( ">> Loaded %u creature respawn times", mCreatureRespawnTimes.size() );
+ sLog.outString( ">> Loaded %lu creature respawn times", (unsigned long)mCreatureRespawnTimes.size() );
sLog.outString();
}
@@ -1252,7 +1409,7 @@ void ObjectMgr::LoadGameobjectRespawnTimes()
delete result;
- sLog.outString( ">> Loaded %u gameobject respawn times", mGORespawnTimes.size() );
+ sLog.outString( ">> Loaded %lu gameobject respawn times", (unsigned long)mGORespawnTimes.size() );
sLog.outString();
}
@@ -1355,7 +1512,7 @@ void ObjectMgr::LoadItemLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 Item locale strings. DB table `locales_item` is empty.");
return;
}
@@ -1404,13 +1561,13 @@ void ObjectMgr::LoadItemLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u Item locale strings", mItemLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu Item locale strings", (unsigned long)mItemLocaleMap.size() );
}
struct SQLItemLoader : public SQLStorageLoaderBase<SQLItemLoader>
{
template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
+ void convert_from_str(uint32 /*field_pos*/, char *src, D &dst)
{
dst = D(objmgr.GetScriptId(src));
}
@@ -1439,6 +1596,32 @@ void ObjectMgr::LoadItemPrototypes()
if(dbcitem)
{
+ if(proto->Class != dbcitem->Class)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct class %u, must be %u (still using DB value).",i,proto->Class,dbcitem->Class);
+ // It safe let use Class from DB
+ }
+ /* disabled: have some strange wrong cases for Subclass values.
+ for enable also uncomment Subclass field in ItemEntry structure and in Itemfmt[]
+ if(proto->SubClass != dbcitem->SubClass)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct (Class: %u, Sub: %u) pair, must be (Class: %u, Sub: %u) (still using DB value).",i,proto->Class,proto->SubClass,dbcitem->Class,dbcitem->SubClass);
+ // It safe let use Subclass from DB
+ }
+ */
+
+ if(proto->Unk0 != dbcitem->Unk0)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct %i Unk0, must be %i (still using DB value).",i,proto->Unk0,dbcitem->Unk0);
+ // It safe let use Unk0 from DB
+ }
+
+ if(proto->Material != dbcitem->Material)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct %i material, must be %i (still using DB value).",i,proto->Material,dbcitem->Material);
+ // It safe let use Material from DB
+ }
+
if(proto->InventoryType != dbcitem->InventoryType)
{
sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType);
@@ -1464,7 +1647,7 @@ void ObjectMgr::LoadItemPrototypes()
if(proto->Class >= MAX_ITEM_CLASS)
{
sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class);
- const_cast<ItemPrototype*>(proto)->Class = ITEM_CLASS_JUNK;
+ const_cast<ItemPrototype*>(proto)->Class = ITEM_CLASS_MISC;
}
if(proto->SubClass >= MaxItemSubclassValues[proto->Class])
@@ -1497,14 +1680,30 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->RequiredSkill = 0;
}
- if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE))
{
- sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped.",i,proto->AllowableClass);
- }
- if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE))
- {
- sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped.",i,proto->AllowableRace);
+ // can be used in equip slot, as page read use in inventory, or spell casting at use
+ bool req = proto->InventoryType!=INVTYPE_NON_EQUIP || proto->PageText;
+ if(!req)
+ {
+ for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j)
+ {
+ if(proto->Spells[j].SpellId)
+ {
+ req = true;
+ break;
+ }
+ }
+ }
+
+ if(req)
+ {
+ if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE))
+ sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped or use.",i,proto->AllowableClass);
+
+ if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE))
+ sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped or use.",i,proto->AllowableRace);
+ }
}
if(proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell))
@@ -1530,18 +1729,35 @@ void ObjectMgr::LoadItemPrototypes()
else if(proto->RequiredReputationRank > MIN_REPUTATION_RANK)
sLog.outErrorDb("Item (Entry: %u) has RequiredReputationFaction ==0 but RequiredReputationRank > 0, rank setting is useless.",i);
+ if(proto->MaxCount < -1)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large negative in maxcount (%i), replace by value (-1) no storing limits.",i,proto->MaxCount);
+ const_cast<ItemPrototype*>(proto)->MaxCount = -1;
+ }
+
if(proto->Stackable==0)
{
- sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%u), replace by default 1.",i,proto->Stackable);
+ sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%i), replace by default 1.",i,proto->Stackable);
const_cast<ItemPrototype*>(proto)->Stackable = 1;
}
+ else if(proto->Stackable < -1)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large negative in stackable (%i), replace by value (-1) no stacking limits.",i,proto->Stackable);
+ const_cast<ItemPrototype*>(proto)->Stackable = -1;
+ }
else if(proto->Stackable > 255)
{
sLog.outErrorDb("Item (Entry: %u) has too large value in stackable (%u), replace by hardcoded upper limit (255).",i,proto->Stackable);
const_cast<ItemPrototype*>(proto)->Stackable = 255;
}
- for (int j = 0; j < 10; j++)
+ if(proto->StatsCount > MAX_ITEM_PROTO_STATS)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS);
+ const_cast<ItemPrototype*>(proto)->StatsCount = MAX_ITEM_PROTO_STATS;
+ }
+
+ for (int j = 0; j < MAX_ITEM_PROTO_STATS; ++j)
{
// for ItemStatValue != 0
if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD)
@@ -1551,7 +1767,7 @@ void ObjectMgr::LoadItemPrototypes()
}
}
- for (int j = 0; j < 5; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_DAMAGES; ++j)
{
if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL)
{
@@ -1561,7 +1777,7 @@ void ObjectMgr::LoadItemPrototypes()
}
// special format
- if(proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN)
+ if((proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN) || (proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN_PET))
{
// spell_1
if(proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
@@ -1598,7 +1814,7 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
}
// allowed only in special format
- else if(proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN)
+ else if((proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN) || (proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN_PET))
{
sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId);
const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
@@ -1608,7 +1824,7 @@ void ObjectMgr::LoadItemPrototypes()
}
// spell_3*,spell_4*,spell_5* is empty
- for (int j = 2; j < 5; j++)
+ for (int j = 2; j < MAX_ITEM_PROTO_SPELLS; ++j)
{
if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
{
@@ -1626,7 +1842,7 @@ void ObjectMgr::LoadItemPrototypes()
// normal spell list
else
{
- for (int j = 0; j < 5; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j)
{
if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
{
@@ -1644,7 +1860,7 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
}
// allowed only in special format
- else if(proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN)
+ else if((proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN) || (proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN_PET))
{
sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
@@ -1692,10 +1908,39 @@ void ObjectMgr::LoadItemPrototypes()
if(proto->Map && !sMapStore.LookupEntry(proto->Map))
sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map);
+ if(proto->BagFamily)
+ {
+ // check bits
+ for(uint32 j = 0; j < sizeof(proto->BagFamily)*8; ++j)
+ {
+ uint32 mask = 1 << j;
+ if((proto->BagFamily & mask)==0)
+ continue;
+
+ ItemBagFamilyEntry const* bf = sItemBagFamilyStore.LookupEntry(j+1);
+ if(!bf)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has bag family bit set not listed in ItemBagFamily.dbc, remove bit",i);
+ const_cast<ItemPrototype*>(proto)->BagFamily &= ~mask;
+ continue;
+ }
+
+ if(BAG_FAMILY_MASK_CURRENCY_TOKENS & mask)
+ {
+ CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(proto->ItemId);
+ if(!ctEntry)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has currency bag family bit set in BagFamily but not listed in CurrencyTypes.dbc, remove bit",i);
+ const_cast<ItemPrototype*>(proto)->BagFamily &= ~mask;
+ }
+ }
+ }
+ }
+
if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory))
sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory);
- for (int j = 0; j < 3; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_SOCKETS; j++)
{
if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color)
{
@@ -1712,10 +1957,13 @@ void ObjectMgr::LoadItemPrototypes()
sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType);
const_cast<ItemPrototype*>(proto)->FoodType = 0;
}
- }
- // this DBC used currently only for check item templates in DB.
- sItemStore.Clear();
+ if(proto->ItemLimitCategory && !sItemLimitCategoryStore.LookupEntry(proto->ItemLimitCategory))
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong LimitCategory value (%u)",i,proto->ItemLimitCategory);
+ const_cast<ItemPrototype*>(proto)->ItemLimitCategory = 0;
+ }
+ }
}
void ObjectMgr::LoadPetLevelInfo()
@@ -1756,7 +2004,10 @@ void ObjectMgr::LoadPetLevelInfo()
if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
sLog.outErrorDb("Wrong (> %u) level %u in `pet_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level);
else
+ {
sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `pet_levelstats` table, ignoring.",current_level);
+ ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
+ }
continue;
}
else if(current_level < 1)
@@ -1999,7 +2250,7 @@ void ObjectMgr::LoadPlayerInfo()
if(sWorld.getConfig(CONFIG_START_ALL_SPELLS))
result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell_custom");
else
- result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell");
+ result = WorldDatabase.Query("SELECT race, class, Spell FROM playercreateinfo_spell");
uint32 count = 0;
@@ -2034,7 +2285,7 @@ void ObjectMgr::LoadPlayerInfo()
}
PlayerInfo* pInfo = &playerInfo[current_race][current_class];
- pInfo->spell.push_back(CreateSpellPair(fields[2].GetUInt16(), fields[3].GetUInt8()));
+ pInfo->spell.push_back(fields[2].GetUInt32());
bar.step();
++count;
@@ -2139,7 +2390,10 @@ void ObjectMgr::LoadPlayerInfo()
if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
sLog.outErrorDb("Wrong (> %u) level %u in `player_classlevelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level);
else
+ {
sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level);
+ ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
+ }
continue;
}
@@ -2234,7 +2488,10 @@ void ObjectMgr::LoadPlayerInfo()
if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
sLog.outErrorDb("Wrong (> %u) level %u in `player_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level);
else
+ {
sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_levelstats` table, ignoring.",current_level);
+ ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
+ }
continue;
}
@@ -2306,6 +2563,70 @@ void ObjectMgr::LoadPlayerInfo()
}
}
}
+
+ // Loading xp per level data
+ {
+ mPlayerXPperLevel.resize(sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
+ for (uint32 level = 0; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
+ mPlayerXPperLevel[level] = 0;
+
+ // 0 1
+ QueryResult *result = WorldDatabase.Query("SELECT lvl, xp_for_next_level FROM player_xp_for_level");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u xp for level definitions", count );
+ sLog.outErrorDb( "Error loading `player_xp_for_level` table or empty table.");
+ exit(1);
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 current_level = fields[0].GetUInt32();
+ uint32 current_xp = fields[1].GetUInt32();
+
+ if(current_level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
+ sLog.outErrorDb("Wrong (> %u) level %u in `player_xp_for_level` table, ignoring.", STRONG_MAX_LEVEL,current_level);
+ else
+ {
+ sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_xp_for_levels` table, ignoring.",current_level);
+ ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
+ }
+ continue;
+ }
+ //PlayerXPperLevel
+ mPlayerXPperLevel[current_level] = current_xp;
+ bar.step();
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u xp for level definitions", count );
+ }
+
+ // fill level gaps
+ for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
+ {
+ if( mPlayerXPperLevel[level] == 0)
+ {
+ sLog.outErrorDb("Level %i does not have XP for level data. Using data of level [%i] + 100.",level+1, level);
+ mPlayerXPperLevel[level] = mPlayerXPperLevel[level-1]+100;
+ }
+ }
}
void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const
@@ -2550,15 +2871,15 @@ void ObjectMgr::LoadGroups()
result = CharacterDatabase.Query("SELECT memberGuid, assistant, subgroup, leaderGuid FROM group_member ORDER BY leaderGuid");
if(!result)
{
- barGoLink bar( 1 );
- bar.step();
+ barGoLink bar2( 1 );
+ bar2.step();
}
else
{
- barGoLink bar( result->GetRowCount() );
+ barGoLink bar2( result->GetRowCount() );
do
{
- bar.step();
+ bar2.step();
Field *fields = result->Fetch();
count++;
leaderGuid = MAKE_NEW_GUID(fields[3].GetUInt32(), 0, HIGHGUID_PLAYER);
@@ -2610,15 +2931,15 @@ void ObjectMgr::LoadGroups()
if(!result)
{
- barGoLink bar( 1 );
- bar.step();
+ barGoLink bar2( 1 );
+ bar2.step();
}
else
{
- barGoLink bar( result->GetRowCount() );
+ barGoLink bar2( result->GetRowCount() );
do
{
- bar.step();
+ bar2.step();
Field *fields = result->Fetch();
count++;
leaderGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
@@ -2632,7 +2953,14 @@ void ObjectMgr::LoadGroups()
}
}
- InstanceSave *save = sInstanceSaveManager.AddInstanceSave(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
+ MapEntry const* mapEntry = sMapStore.LookupEntry(fields[1].GetUInt32());
+ if(!mapEntry || !mapEntry->IsDungeon())
+ {
+ sLog.outErrorDb("Incorrect entry in group_instance table : no dungeon map %d", fields[1].GetUInt32());
+ continue;
+ }
+
+ InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapEntry->MapID, fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
group->BindToInstance(save, fields[3].GetBool(), true);
}while( result->NextRow() );
delete result;
@@ -2658,31 +2986,31 @@ void ObjectMgr::LoadQuests()
QueryResult *result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, SkillOrClass, MinLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue,"
// 9 10 11 12 13 14 15 16
"RepObjectiveFaction, RepObjectiveValue, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime,"
- // 17 18 19 20 21 22 23 24 25 26
- "QuestFlags, SpecialFlags, CharTitleId, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell,"
- // 27 28 29 30 31 32 33 34 35 36
+ // 17 18 19 20 21 22 23 24 25 26 27 28
+ "QuestFlags, SpecialFlags, CharTitleId, PlayersSlain, BonusTalents, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell,"
+ // 29 30 31 32 33 34 35 36 37 38
"Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4,"
- // 37 38 39 40 41 42 43 44
+ // 39 40 41 42 43 44 45 46
"ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4,"
- // 45 46 47 48 49 50 51 52 53 54 54 55
- "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4, ReqSourceRef1, ReqSourceRef2, ReqSourceRef3, ReqSourceRef4,"
- // 57 58 59 60 61 62 63 64
+ // 47 48 49 50 51 52 53 54
+ "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4,"
+ // 55 56 57 58 59 60 61 62
"ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4,"
- // 65 66 67 68
+ // 63 64 65 66
"ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4,"
- // 69 70 71 72 73 74
+ // 67 68 69 70 71 72
"RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6,"
- // 75 76 77 78 79 80
+ // 73 74 75 76 77 78
"RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6,"
- // 81 82 83 84 85 86 87 88
+ // 79 80 81 82 83 84 85 86
"RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4,"
- // 89 90 91 92 93 94 95 96 97 98
+ // 87 88 89 90 91 92 93 94 95 96
"RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5,"
- // 99 100 101 102 103 104 105 106 107 108 109
+ // 97 98 99 100 101 102 103 104 105 106 107
"RewHonorableKills, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt,"
- // 110 111 112 113 114 115 116 117 118 119
- "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
- // 120 121
+ // 108 109 110 111 112 113 114 115 116 117
+ "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
+ // 118 119
"StartScript, CompleteScript"
" FROM quest_template");
if(result == NULL)
@@ -2854,10 +3182,10 @@ void ObjectMgr::LoadQuests()
// no changes, quest can't be done for this requirement
}
- if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > Player::Reputation_Cap)
+ if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > ReputationMgr::Reputation_Cap)
{
sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RequiredMinRepValue,Player::Reputation_Cap);
+ qinfo->GetQuestId(),qinfo->RequiredMinRepValue,ReputationMgr::Reputation_Cap);
// no changes, quest can't be done for this requirement
}
@@ -2976,20 +3304,6 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(),j+1,id,id);
// no changes, quest can't be done for this requirement
}
-
- if(!qinfo->ReqSourceCount[j])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
-
- if(!qinfo->ReqSourceRef[j])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
}
else
{
@@ -2999,41 +3313,6 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]);
// no changes, quest ignore this data
}
-
- if(qinfo->ReqSourceRef[j]>0)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]);
- // no changes, quest ignore this data
- }
- }
- }
-
- for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
- {
- uint32 ref = qinfo->ReqSourceRef[j];
- if(ref)
- {
- if(ref > QUEST_OBJECTIVES_COUNT)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.",
- qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT);
- // no changes, quest can't be done for this requirement
- }
- else
- if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,ref,ref,ref);
- // no changes, quest can't be done for this requirement
- }
- else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1])
- {
- sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.",
- qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]);
- // no changes, quest can't be done for this requirement
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
}
}
@@ -3047,7 +3326,7 @@ void ObjectMgr::LoadQuests()
{
sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.",
qinfo->GetQuestId(),j+1,id,id);
- // no changes, quest can't be done for this requirement
+ continue;
}
if(!qinfo->ReqCreatureOrGOId[j])
@@ -3254,14 +3533,15 @@ void ObjectMgr::LoadQuests()
if(qinfo->NextQuestInChain)
{
- if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end())
+ QuestMap::iterator qNextItr = mQuestTemplates.find(qinfo->NextQuestInChain);
+ if(qNextItr == mQuestTemplates.end())
{
sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.",
qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain );
qinfo->NextQuestInChain = 0;
}
else
- mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId());
+ qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId());
}
// fill additional data stores
@@ -3279,14 +3559,15 @@ void ObjectMgr::LoadQuests()
if(qinfo->NextQuestId)
{
- if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end())
+ QuestMap::iterator qNextItr = mQuestTemplates.find(abs(qinfo->GetNextQuestId()));
+ if (qNextItr == mQuestTemplates.end())
{
sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
}
else
{
int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
- mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId);
+ qNextItr->second->prevQuests.push_back(signedQuestId);
}
}
@@ -3327,7 +3608,7 @@ void ObjectMgr::LoadQuests()
}
sLog.outString();
- sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() );
+ sLog.outString( ">> Loaded %lu quests definitions", (unsigned long)mQuestTemplates.size() );
}
void ObjectMgr::LoadQuestLocales()
@@ -3352,7 +3633,7 @@ void ObjectMgr::LoadQuestLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty.");
return;
}
@@ -3463,58 +3744,7 @@ void ObjectMgr::LoadQuestLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() );
-}
-
-void ObjectMgr::LoadPetCreateSpells()
-{
- QueryResult *result = WorldDatabase.Query("SELECT entry, Spell1, Spell2, Spell3, Spell4 FROM petcreateinfo_spell");
- if(!result)
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded 0 pet create spells" );
- sLog.outErrorDb("`petcreateinfo_spell` table is empty!");
- return;
- }
-
- uint32 count = 0;
-
- barGoLink bar( result->GetRowCount() );
-
- mPetCreateSpell.clear();
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 creature_id = fields[0].GetUInt32();
-
- if(!creature_id || !sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
- continue;
-
- PetCreateSpellEntry PetCreateSpell;
- for(int i = 0; i < 4; i++)
- {
- PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32();
-
- if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i]))
- sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]);
- }
-
- mPetCreateSpell[creature_id] = PetCreateSpell;
-
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u pet create spells", count );
+ sLog.outString( ">> Loaded %lu Quest locale strings", (unsigned long)mQuestLocaleMap.size() );
}
void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
@@ -3584,6 +3814,16 @@ void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
break;
}
+ case SCRIPT_COMMAND_EMOTE:
+ {
+ if(!sEmotesStore.LookupEntry(tmp.datalong))
+ {
+ sLog.outErrorDb("Table `%s` has invalid emote id (datalong = %u) in SCRIPT_COMMAND_EMOTE for script id %u",tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+ break;
+ }
+
case SCRIPT_COMMAND_TELEPORT_TO:
{
if(!sMapStore.LookupEntry(tmp.datalong))
@@ -3712,6 +3952,21 @@ void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
}
case SCRIPT_COMMAND_REMOVE_AURA:
+ {
+ if(!sSpellStore.LookupEntry(tmp.datalong))
+ {
+ sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u",
+ tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+ if(tmp.datalong2 & ~0x1) // 1 bits (0,1)
+ {
+ sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u",
+ tablename,tmp.datalong2,tmp.id);
+ continue;
+ }
+ break;
+ }
case SCRIPT_COMMAND_CAST_SPELL:
{
if(!sSpellStore.LookupEntry(tmp.datalong))
@@ -3720,6 +3975,12 @@ void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
tablename,tmp.datalong,tmp.id);
continue;
}
+ if(tmp.datalong2 & ~0x3) // 2 bits
+ {
+ sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u",
+ tablename,tmp.datalong2,tmp.id);
+ continue;
+ }
break;
}
}
@@ -3968,7 +4229,7 @@ void ObjectMgr::LoadPageTextLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty.");
return;
}
@@ -4005,13 +4266,13 @@ void ObjectMgr::LoadPageTextLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu PageText locale strings", (unsigned long)mPageTextLocaleMap.size() );
}
struct SQLInstanceLoader : public SQLStorageLoaderBase<SQLInstanceLoader>
{
template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
+ void convert_from_str(uint32 /*field_pos*/, char *src, D &dst)
{
dst = D(objmgr.GetScriptId(src));
}
@@ -4035,14 +4296,20 @@ void ObjectMgr::LoadInstanceTemplate()
else if(!entry->HasResetTime())
continue;
+ //FIXME: now exist heroic instance, normal/heroic raid instances
+ // entry->resetTimeHeroic store reset time for both heroic mode instance (raid and non-raid)
+ // entry->resetTimeRaid store reset time for normal raid only
+ // for current state entry->resetTimeRaid == entry->resetTimeHeroic in case raid instances with heroic mode.
+ // but at some point wee need implement reset time dependent from raid instance mode
if(temp->reset_delay == 0)
{
// use defaults from the DBC
- if(entry->SupportsHeroicMode())
+ if(entry->resetTimeHeroic) // for both raid and non raids, read above
{
temp->reset_delay = entry->resetTimeHeroic / DAY;
}
else if (entry->resetTimeRaid && entry->map_type == MAP_RAID)
+ // for normal raid only
{
temp->reset_delay = entry->resetTimeRaid / DAY;
}
@@ -4056,27 +4323,16 @@ void ObjectMgr::LoadInstanceTemplate()
sLog.outString();
}
-void ObjectMgr::AddGossipText(GossipText *pGText)
-{
- ASSERT( pGText->Text_ID );
- ASSERT( mGossipText.find(pGText->Text_ID) == mGossipText.end() );
- mGossipText[pGText->Text_ID] = pGText;
-}
-
-GossipText *ObjectMgr::GetGossipText(uint32 Text_ID)
+GossipText const *ObjectMgr::GetGossipText(uint32 Text_ID) const
{
- GossipTextMap::const_iterator itr;
- for (itr = mGossipText.begin(); itr != mGossipText.end(); ++itr)
- {
- if(itr->second->Text_ID == Text_ID)
- return itr->second;
- }
+ GossipTextMap::const_iterator itr = mGossipText.find(Text_ID);
+ if(itr != mGossipText.end())
+ return &itr->second;
return NULL;
}
void ObjectMgr::LoadGossipText()
{
- GossipText *pGText;
QueryResult *result = WorldDatabase.Query( "SELECT * FROM npc_text" );
int count = 0;
@@ -4103,34 +4359,29 @@ void ObjectMgr::LoadGossipText()
bar.step();
- pGText = new GossipText;
- pGText->Text_ID = fields[cic++].GetUInt32();
-
- for (int i=0; i< 8; i++)
+ uint32 Text_ID = fields[cic++].GetUInt32();
+ if(!Text_ID)
{
- pGText->Options[i].Text_0 = fields[cic++].GetCppString();
- pGText->Options[i].Text_1 = fields[cic++].GetCppString();
-
- pGText->Options[i].Language = fields[cic++].GetUInt32();
- pGText->Options[i].Probability = fields[cic++].GetFloat();
+ sLog.outErrorDb("Table `npc_text` has record wit reserved id 0, ignore.");
+ continue;
+ }
- pGText->Options[i].Emotes[0]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[0]._Emote = fields[cic++].GetUInt32();
+ GossipText& gText = mGossipText[Text_ID];
- pGText->Options[i].Emotes[1]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[1]._Emote = fields[cic++].GetUInt32();
+ for (int i=0; i< 8; i++)
+ {
+ gText.Options[i].Text_0 = fields[cic++].GetCppString();
+ gText.Options[i].Text_1 = fields[cic++].GetCppString();
- pGText->Options[i].Emotes[2]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[2]._Emote = fields[cic++].GetUInt32();
- }
+ gText.Options[i].Language = fields[cic++].GetUInt32();
+ gText.Options[i].Probability = fields[cic++].GetFloat();
- if ( !pGText->Text_ID ){
- delete pGText;
- continue;
+ for(int j=0; j < 3; ++j)
+ {
+ gText.Options[i].Emotes[j]._Delay = fields[cic++].GetUInt32();
+ gText.Options[i].Emotes[j]._Emote = fields[cic++].GetUInt32();
+ }
}
-
- AddGossipText( pGText );
-
} while( result->NextRow() );
sLog.outString();
@@ -4159,8 +4410,8 @@ void ObjectMgr::LoadNpcTextLocales()
bar.step();
- sLog.outString("");
- sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty.");
+ sLog.outString();
+ sLog.outString(">> Loaded 0 NpcText locale strings. DB table `locales_npc_text` is empty.");
return;
}
@@ -4210,7 +4461,7 @@ void ObjectMgr::LoadNpcTextLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu NpcText locale strings", (unsigned long)mNpcTextLocaleMap.size() );
}
//not very fast function but it is called only once a day, or on starting-up
@@ -4224,14 +4475,27 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
// 0 1 2 3 4 5 6 7 8 9
QueryResult* result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,itemTextId,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" I64FMTD "'", (uint64)basetime);
if ( !result )
+ {
+ barGoLink bar(1);
+ bar.step();
+ sLog.outString();
+ sLog.outString(">> Only expired mails (need to be return or delete) or DB table `mail` is empty.");
return; // any mails need to be returned or deleted
- Field *fields;
+ }
+
//std::ostringstream delitems, delmails; //will be here for optimization
//bool deletemail = false, deleteitem = false;
//delitems << "DELETE FROM item_instance WHERE guid IN ( ";
//delmails << "DELETE FROM mail WHERE id IN ( "
+
+ barGoLink bar( result->GetRowCount() );
+ uint32 count = 0;
+ Field *fields;
+
do
{
+ bar.step();
+
fields = result->Fetch();
Mail *m = new Mail;
m->messageID = fields[0].GetUInt32();
@@ -4297,8 +4561,12 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
//delmails << m->messageID << ", ";
CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID);
delete m;
+ ++count;
} while (result->NextRow());
delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u mails", count );
}
void ObjectMgr::LoadQuestAreaTriggers()
@@ -4455,7 +4723,7 @@ void ObjectMgr::LoadAreaTriggerScripts()
sLog.outString( ">> Loaded %u areatrigger scripts", count );
}
-uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
+uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid, uint32 team )
{
bool found = false;
float dist;
@@ -4464,24 +4732,31 @@ uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
{
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
- if(node && node->map_id == mapid)
+ if(!node || node->map_id != mapid || !node->MountCreatureID[team == ALLIANCE ? 1 : 0])
+ continue;
+
+ uint8 field = (uint8)((i - 1) / 32);
+ uint32 submask = 1<<((i-1)%32);
+
+ // skip not taxi network nodes
+ if((sTaxiNodesMask[field] & submask)==0)
+ continue;
+
+ float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z);
+ if(found)
{
- float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z);
- if(found)
- {
- if(dist2 < dist)
- {
- dist = dist2;
- id = i;
- }
- }
- else
+ if(dist2 < dist)
{
- found = true;
dist = dist2;
id = i;
}
}
+ else
+ {
+ found = true;
+ dist = dist2;
+ id = i;
+ }
}
return id;
@@ -4511,7 +4786,7 @@ void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, ui
path = dest_i->second.ID;
}
-uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
+uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team, bool allowed_alt_team /* = false */)
{
uint16 mount_entry = 0;
uint16 mount_id = 0;
@@ -4519,17 +4794,26 @@ uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id);
if(node)
{
- if (team == ALLIANCE) mount_entry = node->alliance_mount_type;
- else mount_entry = node->horde_mount_type;
+ if (team == ALLIANCE)
+ {
+ mount_entry = node->MountCreatureID[1];
+ if(!mount_entry && allowed_alt_team)
+ mount_entry = node->MountCreatureID[0];
- CreatureInfo const *cinfo = GetCreatureTemplate(mount_entry);
- if (cinfo)
+ CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
+ if(ci)
+ mount_id = ci->Modelid_A1;
+ }
+ if (team == HORDE)
{
- if(! (mount_id = cinfo->GetRandomValidModelId()))
- {
- sLog.outErrorDb("No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry);
- return false;
- }
+ mount_entry = node->MountCreatureID[0];
+
+ if(!mount_entry && allowed_alt_team)
+ mount_entry = node->MountCreatureID[1];
+
+ CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
+ if(ci)
+ mount_id = ci->Modelid_H1;
}
}
@@ -4657,7 +4941,7 @@ void ObjectMgr::LoadGraveyardZones()
WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team)
{
// search for zone associated closest graveyard
- uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y);
+ uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y,z);
// Simulate std. algorithm:
// found some graveyard associated to (ghost_zone,ghost_map)
@@ -4668,7 +4952,10 @@ WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float
// then check faction
GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId);
GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId);
- if(graveLow==graveUp)
+ MapEntry const* map = sMapStore.LookupEntry(MapId);
+ // not need to check validity of map object; MapId _MUST_ be valid here
+
+ if(graveLow==graveUp && !map->IsBattleArena())
{
sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
return NULL;
@@ -4709,8 +4996,10 @@ WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float
if(MapId != entry->map_id)
{
// if find graveyard at different map from where entrance placed (or no entrance data), use any first
- if (!mapEntry || mapEntry->entrance_map < 0 || mapEntry->entrance_map != entry->map_id ||
- mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0)
+ if (!mapEntry ||
+ mapEntry->entrance_map < 0 ||
+ mapEntry->entrance_map != entry->map_id ||
+ (mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0))
{
// not have any corrdinates for check distance anyway
entryFar = entry;
@@ -4855,7 +5144,7 @@ void ObjectMgr::LoadAreaTriggerTeleports()
uint32 count = 0;
- // 0 1 2 3 4 5 6
+ // 0 1 2 3 4 5 6
QueryResult *result = WorldDatabase.Query("SELECT id, access_id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
if( !result )
{
@@ -4896,7 +5185,7 @@ void ObjectMgr::LoadAreaTriggerTeleports()
sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
continue;
}
-
+
MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId);
if(!mapEntry)
{
@@ -5007,7 +5296,8 @@ void ObjectMgr::LoadAccessRequirements()
if(ar.heroicQuest)
{
- if(!GetQuestTemplate(ar.heroicQuest))
+ QuestMap::iterator qReqItr = mQuestTemplates.find(ar.heroicQuest);
+ if(qReqItr == mQuestTemplates.end())
{
sLog.outErrorDb("Required Heroic Quest %u not exist for trigger %u, remove heroic quest done requirement.",ar.heroicQuest,requiremt_ID);
ar.heroicQuest = 0;
@@ -5016,7 +5306,8 @@ void ObjectMgr::LoadAccessRequirements()
if(ar.quest)
{
- if(!GetQuestTemplate(ar.quest))
+ QuestMap::iterator qReqItr = mQuestTemplates.find(ar.quest);
+ if(qReqItr == mQuestTemplates.end())
{
sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",ar.quest,requiremt_ID);
ar.quest = 0;
@@ -5033,6 +5324,9 @@ void ObjectMgr::LoadAccessRequirements()
sLog.outString( ">> Loaded %u access requirement definitions", count );
}
+/*
+ * Searches for the areatrigger which teleports players out of the given map
+ */
AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const
{
const MapEntry *mapEntry = sMapStore.LookupEntry(Map);
@@ -5049,6 +5343,23 @@ AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const
return NULL;
}
+/**
+ * Searches for the areatrigger which teleports players to the given map
+ */
+AreaTrigger const* ObjectMgr::GetMapEntranceTrigger(uint32 Map) const
+{
+ for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); ++itr)
+ {
+ if(itr->second.target_mapId == Map)
+ {
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first);
+ if(atEntry)
+ return &itr->second;
+ }
+ }
+ return NULL;
+}
+
void ObjectMgr::SetHighestGuids()
{
QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" );
@@ -5065,9 +5376,6 @@ void ObjectMgr::SetHighestGuids()
delete result;
}
- // pet guids are not saved to DB, set to 0 (pet guid != pet id)
- m_hiPetGuid = 0;
-
result = CharacterDatabase.Query( "SELECT MAX(guid) FROM item_instance" );
if( result )
{
@@ -5141,24 +5449,24 @@ uint32 ObjectMgr::GenerateArenaTeamId()
return m_arenaTeamId++;
}
-uint32 ObjectMgr::GenerateGuildId()
+uint32 ObjectMgr::GenerateAuctionID()
{
- if(m_guildId>=0xFFFFFFFE)
+ if(m_auctionid>=0xFFFFFFFE)
{
- sLog.outError("Guild ids overflow!! Can't continue, shutting down server. ");
+ sLog.outError("Auctions ids overflow!! Can't continue, shutting down server. ");
World::StopNow(ERROR_EXIT_CODE);
}
- return m_guildId++;
+ return m_auctionid++;
}
-uint32 ObjectMgr::GenerateAuctionID()
+uint32 ObjectMgr::GenerateGuildId()
{
- if(m_auctionid>=0xFFFFFFFE)
+ if(m_guildId>=0xFFFFFFFE)
{
- sLog.outError("Auctions ids overflow!! Can't continue, shutting down server. ");
+ sLog.outError("Guild ids overflow!! Can't continue, shutting down server. ");
World::StopNow(ERROR_EXIT_CODE);
}
- return m_auctionid++;
+ return m_guildId++;
}
uint32 ObjectMgr::GenerateMailID()
@@ -5220,6 +5528,13 @@ uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh)
World::StopNow(ERROR_EXIT_CODE);
}
return m_hiPetGuid++;
+ case HIGHGUID_VEHICLE:
+ if(m_hiVehicleGuid>=0x00FFFFFF)
+ {
+ sLog.outError("Vehicle guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiVehicleGuid++;
case HIGHGUID_PLAYER:
if(m_hiCharGuid>=0xFFFFFFFE)
{
@@ -5271,7 +5586,7 @@ void ObjectMgr::LoadGameObjectLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty.");
return;
}
@@ -5303,9 +5618,9 @@ void ObjectMgr::LoadGameObjectLocales()
}
}
- for(int i = MAX_LOCALE; i < MAX_LOCALE*2-1; ++i)
+ for(int i = 1; i < MAX_LOCALE; ++i)
{
- std::string str = fields[i].GetCppString();
+ std::string str = fields[i+(MAX_LOCALE-1)].GetCppString();
if(!str.empty())
{
int idx = GetOrNewIndexForLocale(LocaleConstant(i));
@@ -5324,18 +5639,73 @@ void ObjectMgr::LoadGameObjectLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu gameobject locale strings", (unsigned long)mGameObjectLocaleMap.size() );
}
struct SQLGameObjectLoader : public SQLStorageLoaderBase<SQLGameObjectLoader>
{
template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
+ void convert_from_str(uint32 /*field_pos*/, char *src, D &dst)
{
dst = D(objmgr.GetScriptId(src));
}
};
+inline void CheckGOLockId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ if (sLockStore.LookupEntry(dataN))
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but lock (Id: %u) not found.",
+ goInfo->id,goInfo->type,N,goInfo->door.lockId,goInfo->door.lockId);
+}
+
+inline void CheckGOLinkedTrapId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ if (GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(dataN))
+ {
+ if (trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
+ goInfo->id,goInfo->type,N,dataN,dataN,GAMEOBJECT_TYPE_TRAP);
+ }
+ /* disable check for while (too many error reports baout not existed in trap templates
+ else
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
+ goInfo->id,goInfo->type,N,dataN,dataN);
+ */
+}
+
+inline void CheckGOSpellId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ if (sSpellStore.LookupEntry(dataN))
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but Spell (Entry %u) not exist.",
+ goInfo->id,goInfo->type,N,dataN,dataN);
+}
+
+inline void CheckAndFixGOChairHeightId(GameObjectInfo const* goInfo,uint32 const& dataN,uint32 N)
+{
+ if (dataN <= (UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR) )
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but correct chair height in range 0..%i.",
+ goInfo->id,goInfo->type,N,dataN,UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR);
+
+ // prevent client and server unexpected work
+ const_cast<uint32&>(dataN) = 0;
+}
+
+inline void CheckGONoDamageImmuneId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ // 0/1 correct values
+ if (dataN <= 1)
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) noDamageImmune field value.",
+ goInfo->id,goInfo->type,N,dataN);
+}
+
void ObjectMgr::LoadGameobjectInfo()
{
SQLGameObjectLoader loader;
@@ -5345,139 +5715,104 @@ void ObjectMgr::LoadGameobjectInfo()
for(uint32 id = 1; id < sGOStorage.MaxEntry; id++)
{
GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(id);
- if(!goInfo)
+ if (!goInfo)
continue;
switch(goInfo->type)
{
case GAMEOBJECT_TYPE_DOOR: //0
{
- if(goInfo->door.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->door.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId);
- }
+ if (goInfo->door.lockId)
+ CheckGOLockId(goInfo,goInfo->door.lockId,1);
+ CheckGONoDamageImmuneId(goInfo,goInfo->door.noDamageImmune,3);
break;
}
case GAMEOBJECT_TYPE_BUTTON: //1
{
- if(goInfo->button.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->button.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId);
- }
+ if (goInfo->button.lockId)
+ CheckGOLockId(goInfo,goInfo->button.lockId,1);
+ CheckGONoDamageImmuneId(goInfo,goInfo->button.noDamageImmune,4);
+ break;
+ }
+ case GAMEOBJECT_TYPE_QUESTGIVER: //2
+ {
+ if (goInfo->questgiver.lockId)
+ CheckGOLockId(goInfo,goInfo->questgiver.lockId,0);
+ CheckGONoDamageImmuneId(goInfo,goInfo->questgiver.noDamageImmune,5);
break;
}
case GAMEOBJECT_TYPE_CHEST: //3
{
- if(goInfo->chest.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->chest.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId);
- }
- if(goInfo->chest.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->chest.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId);
- */
- }
+ if (goInfo->chest.lockId)
+ CheckGOLockId(goInfo,goInfo->chest.lockId,0);
+
+ if (goInfo->chest.linkedTrapId) // linked trap
+ CheckGOLinkedTrapId(goInfo,goInfo->chest.linkedTrapId,7);
break;
}
case GAMEOBJECT_TYPE_TRAP: //6
{
- /* disable check for while
- if(goInfo->trap.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->trap.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId);
- }
+ if (goInfo->trap.lockId)
+ CheckGOLockId(goInfo,goInfo->trap.lockId,0);
+ /* disable check for while, too many not existed spells
+ if (goInfo->trap.spellId) // spell
+ CheckGOSpellId(goInfo,goInfo->trap.spellId,3);
*/
break;
}
case GAMEOBJECT_TYPE_CHAIR: //7
- if(goInfo->chair.height > 2)
- {
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..2.",
- id,goInfo->type,goInfo->chair.height);
-
- // prevent client and server unexpected work
- const_cast<GameObjectInfo*>(goInfo)->chair.height = 0;
- }
+ CheckAndFixGOChairHeightId(goInfo,goInfo->chair.height,1);
break;
case GAMEOBJECT_TYPE_SPELL_FOCUS: //8
{
- if(goInfo->spellFocus.focusId)
+ if (goInfo->spellFocus.focusId)
{
- if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId))
+ if (!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId))
sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.",
id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId);
}
- if(goInfo->spellFocus.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->spellFocus.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId);
- */
- }
+ if (goInfo->spellFocus.linkedTrapId) // linked trap
+ CheckGOLinkedTrapId(goInfo,goInfo->spellFocus.linkedTrapId,2);
break;
}
case GAMEOBJECT_TYPE_GOOBER: //10
{
- if(goInfo->goober.pageId) // pageId
+ if (goInfo->goober.lockId)
+ CheckGOLockId(goInfo,goInfo->goober.lockId,0);
+
+ if (goInfo->goober.pageId) // pageId
{
- if(!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
+ if (!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.",
id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId);
}
- /* disable check for while
- if(goInfo->goober.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->goober.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId);
- }
+ /* disable check for while, too many not existed spells
+ if (goInfo->goober.spellId) // spell
+ CheckGOSpellId(goInfo,goInfo->goober.spellId,10);
*/
- if(goInfo->goober.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->goober.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId);
- */
- }
+ CheckGONoDamageImmuneId(goInfo,goInfo->goober.noDamageImmune,11);
+ if (goInfo->goober.linkedTrapId) // linked trap
+ CheckGOLinkedTrapId(goInfo,goInfo->goober.linkedTrapId,12);
+ break;
+ }
+ case GAMEOBJECT_TYPE_AREADAMAGE: //12
+ {
+ if (goInfo->areadamage.lockId)
+ CheckGOLockId(goInfo,goInfo->areadamage.lockId,0);
+ break;
+ }
+ case GAMEOBJECT_TYPE_CAMERA: //13
+ {
+ if (goInfo->camera.lockId)
+ CheckGOLockId(goInfo,goInfo->camera.lockId,0);
break;
}
case GAMEOBJECT_TYPE_MO_TRANSPORT: //15
{
- if(goInfo->moTransport.taxiPathId)
+ if (goInfo->moTransport.taxiPathId)
{
- if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty())
+ if (goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty())
sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId);
}
@@ -5485,26 +5820,41 @@ void ObjectMgr::LoadGameobjectInfo()
}
case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18
{
- /* disabled
- if(goInfo->summoningRitual.spellId)
- {
- if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId);
- }
+ /* disable check for while, too many not existed spells
+ // always must have spell
+ CheckGOSpellId(goInfo,goInfo->summoningRitual.spellId,1);
*/
break;
}
case GAMEOBJECT_TYPE_SPELLCASTER: //22
{
- if(goInfo->spellcaster.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId);
- }
+ // always must have spell
+ CheckGOSpellId(goInfo,goInfo->spellcaster.spellId,0);
break;
}
+ case GAMEOBJECT_TYPE_FLAGSTAND: //24
+ {
+ if (goInfo->flagstand.lockId)
+ CheckGOLockId(goInfo,goInfo->flagstand.lockId,0);
+ CheckGONoDamageImmuneId(goInfo,goInfo->flagstand.noDamageImmune,5);
+ break;
+ }
+ case GAMEOBJECT_TYPE_FISHINGHOLE: //25
+ {
+ if (goInfo->fishinghole.lockId)
+ CheckGOLockId(goInfo,goInfo->fishinghole.lockId,4);
+ break;
+ }
+ case GAMEOBJECT_TYPE_FLAGDROP: //26
+ {
+ if (goInfo->flagdrop.lockId)
+ CheckGOLockId(goInfo,goInfo->flagdrop.lockId,0);
+ CheckGONoDamageImmuneId(goInfo,goInfo->flagdrop.noDamageImmune,3);
+ break;
+ }
+ case GAMEOBJECT_TYPE_BARBER_CHAIR: //32
+ CheckAndFixGOChairHeightId(goInfo,goInfo->barberChair.chairheight,0);
+ break;
}
}
@@ -5553,6 +5903,13 @@ uint32 ObjectMgr::GetBaseXP(uint32 level)
return mBaseXPTable[level] ? mBaseXPTable[level] : 0;
}
+uint32 ObjectMgr::GetXPForLevel(uint32 level)
+{
+ if (level < mPlayerXPperLevel.size())
+ return mPlayerXPperLevel[level];
+ return 0;
+}
+
void ObjectMgr::LoadPetNames()
{
uint32 count = 0;
@@ -5754,6 +6111,131 @@ void ObjectMgr::LoadReputationOnKill()
sLog.outString(">> Loaded %u creature award reputation definitions", count);
}
+void ObjectMgr::LoadPointsOfInterest()
+{
+ uint32 count = 0;
+
+ // 0 1 2 3 4 5
+ QueryResult *result = WorldDatabase.Query("SELECT entry, x, y, icon, flags, data, icon_name FROM points_of_interest");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 Points of Interest definitions. DB table `points_of_interest` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 point_id = fields[0].GetUInt32();
+
+ PointOfInterest POI;
+ POI.x = fields[1].GetFloat();
+ POI.y = fields[2].GetFloat();
+ POI.icon = fields[3].GetUInt32();
+ POI.flags = fields[4].GetUInt32();
+ POI.data = fields[5].GetUInt32();
+ POI.icon_name = fields[6].GetCppString();
+
+ if(!MaNGOS::IsValidMapCoord(POI.x,POI.y))
+ {
+ sLog.outErrorDb("Table `points_of_interest` (Entry: %u) have invalid coordinates (X: %f Y: %f), ignored.",point_id,POI.x,POI.y);
+ continue;
+ }
+
+ mPointsOfInterest[point_id] = POI;
+
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u Points of Interest definitions", count);
+}
+
+void ObjectMgr::LoadNPCSpellClickSpells()
+{
+ uint32 count = 0;
+
+ mSpellClickInfoMap.clear();
+
+ QueryResult *result = WorldDatabase.Query("SELECT npc_entry, spell_id, quest_id, quest_status, cast_flags FROM npc_spellclick_spells");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 npc_entry = fields[0].GetUInt32();
+ CreatureInfo const* cInfo = GetCreatureTemplate(npc_entry);
+ if (!cInfo)
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown creature_template %u. Skipping entry.", npc_entry);
+ continue;
+ }
+
+ uint32 spellid = fields[1].GetUInt32();
+ SpellEntry const *spellinfo = sSpellStore.LookupEntry(spellid);
+ if (!spellinfo)
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown spellid %u. Skipping entry.", spellid);
+ continue;
+ }
+
+ uint32 quest = fields[2].GetUInt32();
+
+ // quest might be 0 to enable spellclick independent of any quest
+ if (quest)
+ {
+ if(mQuestTemplates.find(quest) == mQuestTemplates.end())
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown quest %u. Skipping entry.", spellid);
+ continue;
+ }
+
+ }
+
+ uint32 queststatus = fields[3].GetUInt32();
+
+ uint8 castFlags = fields[4].GetUInt8();
+ SpellClickInfo info;
+ info.spellId = spellid;
+ info.questId = quest;
+ info.questStatus = queststatus;
+ info.castFlags = castFlags;
+ mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info));
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u spellclick definitions", count);
+}
+
void ObjectMgr::LoadWeatherZoneChances()
{
uint32 count = 0;
@@ -5792,19 +6274,19 @@ void ObjectMgr::LoadWeatherZoneChances()
if(wzc.data[season].rainChance > 100)
{
wzc.data[season].rainChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%",zone_id,season);
+ sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%%",zone_id,season);
}
if(wzc.data[season].snowChance > 100)
{
wzc.data[season].snowChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%",zone_id,season);
+ sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%%",zone_id,season);
}
if(wzc.data[season].stormChance > 100)
{
wzc.data[season].stormChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%",zone_id,season);
+ sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%%",zone_id,season);
}
}
@@ -6021,11 +6503,18 @@ void ObjectMgr::LoadReservedPlayersNames()
bar.step();
fields = result->Fetch();
std::string name= fields[0].GetCppString();
- if(normalizePlayerName(name))
+
+ std::wstring wstr;
+ if(!Utf8toWStr (name,wstr))
{
- m_ReservedNames.insert(name);
- ++count;
+ sLog.outError("Table `reserved_name` have invalid name: %s", name.c_str() );
+ continue;
}
+
+ wstrToLower(wstr);
+
+ m_ReservedNames.insert(wstr);
+ ++count;
} while ( result->NextRow() );
delete result;
@@ -6034,6 +6523,17 @@ void ObjectMgr::LoadReservedPlayersNames()
sLog.outString( ">> Loaded %u reserved player names", count );
}
+bool ObjectMgr::IsReservedName( const std::string& name ) const
+{
+ std::wstring wstr;
+ if(!Utf8toWStr (name,wstr))
+ return false;
+
+ wstrToLower(wstr);
+
+ return m_ReservedNames.find(wstr) != m_ReservedNames.end();
+}
+
enum LanguageType
{
LT_BASIC_LATIN = 0x0000,
@@ -6182,55 +6682,26 @@ int ObjectMgr::GetOrNewIndexForLocale( LocaleConstant loc )
return m_LocalForIndex.size()-1;
}
-void ObjectMgr::LoadBattleMastersEntry()
+void ObjectMgr::LoadGameObjectForQuests()
{
- mBattleMastersMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
-
- uint32 count = 0;
+ mGameObjectForQuestSet.clear(); // need for reload case
- if( !result )
+ if( !sGOStorage.MaxEntry )
{
barGoLink bar( 1 );
bar.step();
-
sLog.outString();
- sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
+ sLog.outString( ">> Loaded 0 GameObjects for quests" );
return;
}
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- ++count;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 entry = fields[0].GetUInt32();
- uint32 bgTypeId = fields[1].GetUInt32();
-
- mBattleMastersMap[entry] = bgTypeId;
-
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u battlemaster entries", count );
-}
-
-void ObjectMgr::LoadGameObjectForQuests()
-{
- mGameObjectForQuestSet.clear(); // need for reload case
-
+ barGoLink bar( sGOStorage.MaxEntry - 1 );
uint32 count = 0;
// collect GO entries for GO that must activated
for(uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry)
{
+ bar.step();
GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(go_entry);
if(!goInfo)
continue;
@@ -6265,34 +6736,55 @@ void ObjectMgr::LoadGameObjectForQuests()
}
sLog.outString();
- sLog.outString( ">> Loaded %u GameObject for quests", count );
+ sLog.outString( ">> Loaded %u GameObjects for quests", count );
}
bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value)
{
- // cleanup affected map part for reloading case
- for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();)
+ int32 start_value = min_value;
+ int32 end_value = max_value;
+ // some string can have negative indexes range
+ if (start_value < 0)
{
- if(itr->first >= min_value && itr->first <= max_value)
+ if (end_value >= start_value)
{
- TrinityStringLocaleMap::iterator itr2 = itr;
- ++itr;
- mTrinityStringLocaleMap.erase(itr2);
+ sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.",table,min_value,max_value);
+ return false;
+ }
+
+ // real range (max+1,min+1) exaple: (-10,-1000) -> -999...-10+1
+ std::swap(start_value,end_value);
+ ++start_value;
+ ++end_value;
+ }
+ else
+ {
+ if (start_value >= end_value)
+ {
+ sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.",table,min_value,max_value);
+ return false;
}
+ }
+
+ // cleanup affected map part for reloading case
+ for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();)
+ {
+ if (itr->first >= start_value && itr->first < end_value)
+ mTrinityStringLocaleMap.erase(itr++);
else
++itr;
}
QueryResult *result = db.PQuery("SELECT entry,content_default,content_loc1,content_loc2,content_loc3,content_loc4,content_loc5,content_loc6,content_loc7,content_loc8 FROM %s",table);
- if(!result)
+ if (!result)
{
barGoLink bar(1);
bar.step();
- sLog.outString("");
- if(min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings
+ sLog.outString();
+ if (min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings
sLog.outErrorDb(">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.",table);
else
sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table);
@@ -6310,22 +6802,20 @@ bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 mi
int32 entry = fields[0].GetInt32();
- if(entry==0)
+ if (entry==0)
{
sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.",table);
continue;
}
- else if(entry < min_value || entry > max_value)
+ else if (entry < start_value || entry >= end_value)
{
- int32 start = min_value > 0 ? min_value : max_value;
- int32 end = min_value > 0 ? max_value : min_value;
- sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,start,end);
+ sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,min_value,max_value);
continue;
}
TrinityStringLocale& data = mTrinityStringLocaleMap[entry];
- if(data.Content.size() > 0)
+ if (data.Content.size() > 0)
{
sLog.outErrorDb("Table `%s` contain data for already loaded entry %i (from another table?), ignored.",table,entry);
continue;
@@ -6340,13 +6830,13 @@ bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 mi
for(int i = 1; i < MAX_LOCALE; ++i)
{
std::string str = fields[i+1].GetCppString();
- if(!str.empty())
+ if (!str.empty())
{
int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
+ if (idx >= 0)
{
// 0 -> default, idx in to idx+1
- if(data.Content.size() <= idx+1)
+ if (data.Content.size() <= idx+1)
data.Content.resize(idx+2);
data.Content[idx+1] = str;
@@ -6358,7 +6848,7 @@ bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 mi
delete result;
sLog.outString();
- if(min_value == MIN_TRINITY_STRING_ID) // internal Trinity strings
+ if (min_value == MIN_TRINITY_STRING_ID)
sLog.outString( ">> Loaded %u Trinity strings from table %s", count,table);
else
sLog.outString( ">> Loaded %u string templates from %s", count,table);
@@ -6534,17 +7024,17 @@ bool PlayerCondition::Meets(Player const * player) const
case CONDITION_NONE:
return true; // empty condition, always met
case CONDITION_AURA:
- return player->HasAura(value1, value2);
+ return player->HasAuraEffect(value1, value2);
case CONDITION_ITEM:
return player->HasItemCount(value1, value2);
case CONDITION_ITEM_EQUIPPED:
- return player->GetItemOrItemWithGemEquipped(value1) != NULL;
+ return player->HasItemOrGemWithIdEquipped(value1,1);
case CONDITION_ZONEID:
return player->GetZoneId() == value1;
case CONDITION_REPUTATION_RANK:
{
FactionEntry const* faction = sFactionStore.LookupEntry(value1);
- return faction && player->GetReputationRank(faction) >= value2;
+ return faction && player->GetReputationMgr().GetRank(faction) >= value2;
}
case CONDITION_TEAM:
return player->GetTeam() == value1;
@@ -6561,12 +7051,12 @@ bool PlayerCondition::Meets(Player const * player) const
{
Unit::AuraMap const& auras = player->GetAuras();
for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual==3580)
+ if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual[0]==3580)
return true;
return false;
}
case CONDITION_NO_AURA:
- return !player->HasAura(value1, value2);
+ return !player->HasAuraEffect(value1, value2);
case CONDITION_ACTIVE_EVENT:
return gameeventmgr.IsActiveEvent(value1);
case CONDITION_INSTANCE_DATA:
@@ -6711,7 +7201,7 @@ bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 val
}
case CONDITION_ACTIVE_EVENT:
{
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
if(value1 >=events.size() || !events[value1].isValid())
{
sLog.outErrorDb("Active event condition requires existed event id (%u), skipped", value1);
@@ -6722,6 +7212,8 @@ bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 val
case CONDITION_INSTANCE_DATA:
//TODO: need some check
break;
+ case CONDITION_NONE:
+ break;
}
return true;
}
@@ -6738,7 +7230,7 @@ SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
return SKILL_RANGE_MONO;
case SKILL_CATEGORY_ARMOR:
case SKILL_CATEGORY_CLASS:
- if(pSkill->id != SKILL_POISONS && pSkill->id != SKILL_LOCKPICKING)
+ if(pSkill->id != SKILL_LOCKPICKING)
return SKILL_RANGE_MONO;
else
return SKILL_RANGE_LEVEL;
@@ -6753,7 +7245,7 @@ SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
return SKILL_RANGE_MONO;
default:
case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc
- case SKILL_CATEGORY_NOT_DISPLAYED: //only GENEREC(DND)
+ case SKILL_CATEGORY_GENERIC: //only GENERIC(DND)
return SKILL_RANGE_NONE;
}
}
@@ -6814,11 +7306,10 @@ void ObjectMgr::LoadGameTele()
++count;
}
while (result->NextRow());
-
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u game tele's", count );
+ sLog.outString( ">> Loaded %u GameTeleports", count );
}
GameTele const* ObjectMgr::GetGameTele(const std::string& name) const
@@ -6954,30 +7445,41 @@ void ObjectMgr::LoadTrainerSpell()
continue;
}
- TrainerSpell* pTrainerSpell = new TrainerSpell();
- pTrainerSpell->spell = spell;
- pTrainerSpell->spellcost = fields[2].GetUInt32();
- pTrainerSpell->reqskill = fields[3].GetUInt32();
- pTrainerSpell->reqskillvalue = fields[4].GetUInt32();
- pTrainerSpell->reqlevel = fields[5].GetUInt32();
+ TrainerSpellData& data = m_mCacheTrainerSpellMap[entry];
- if(!pTrainerSpell->reqlevel)
- pTrainerSpell->reqlevel = spellinfo->spellLevel;
+ TrainerSpell& trainerSpell = data.spellList[spell];
+ trainerSpell.spell = spell;
+ trainerSpell.spellCost = fields[2].GetUInt32();
+ trainerSpell.reqSkill = fields[3].GetUInt32();
+ trainerSpell.reqSkillValue = fields[4].GetUInt32();
+ trainerSpell.reqLevel = fields[5].GetUInt32();
+ if(!trainerSpell.reqLevel)
+ trainerSpell.reqLevel = spellinfo->spellLevel;
- TrainerSpellData& data = m_mCacheTrainerSpellMap[entry];
+ // calculate learned spell for profession case when stored cast-spell
+ trainerSpell.learnedSpell = spell;
+ for(int i = 0; i <3; ++i)
+ {
+ if(spellinfo->Effect[i] != SPELL_EFFECT_LEARN_SPELL)
+ continue;
+ if(SpellMgr::IsProfessionOrRidingSpell(spellinfo->EffectTriggerSpell[i]))
+ {
+ trainerSpell.learnedSpell = spellinfo->EffectTriggerSpell[i];
+ break;
+ }
+ }
- if(SpellMgr::IsProfessionSpell(spell))
+ if(SpellMgr::IsProfessionSpell(trainerSpell.learnedSpell))
data.trainerType = 2;
- data.spellList.push_back(pTrainerSpell);
++count;
} while (result->NextRow());
delete result;
sLog.outString();
- sLog.outString( ">> Loaded Trainers %d", count );
+ sLog.outString( ">> Loaded %d Trainers", count );
}
void ObjectMgr::LoadVendors()
@@ -7255,16 +7757,30 @@ void ObjectMgr::LoadScriptNames()
"SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' "
"UNION "
"SELECT DISTINCT(script) FROM instance_template WHERE script <> ''");
- if(result)
+
+ if( !result )
{
- do
- {
- m_scriptNames.push_back((*result)[0].GetString());
- } while (result->NextRow());
- delete result;
+ barGoLink bar( 1 );
+ bar.step();
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded empty set of Script Names!");
+ return;
}
+ barGoLink bar( result->GetRowCount() );
+ uint32 count = 0;
+
+ do
+ {
+ bar.step();
+ m_scriptNames.push_back((*result)[0].GetString());
+ ++count;
+ } while (result->NextRow());
+ delete result;
+
std::sort(m_scriptNames.begin(), m_scriptNames.end());
+ sLog.outString();
+ sLog.outString( ">> Loaded %d Script Names", count );
}
uint32 ObjectMgr::GetScriptId(const char *name)
@@ -7284,13 +7800,16 @@ void ObjectMgr::CheckScripts(ScriptMapMap const& scripts,std::set<int32>& ids)
{
for(ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM)
{
- if(itrM->second.dataint)
+ switch(itrM->second.command)
{
- if(!GetTrinityStringLocale (itrM->second.dataint))
- sLog.outErrorDb( "Table `db_script_string` has not existed string id %u", itrM->first);
+ case SCRIPT_COMMAND_TALK:
+ {
+ if(!GetTrinityStringLocale (itrM->second.dataint))
+ sLog.outErrorDb( "Table `db_script_string` not has string id %u used db script (ID: %u)", itrM->second.dataint, itrMM->first);
- if(ids.count(itrM->second.dataint))
- ids.erase(itrM->second.dataint);
+ if(ids.count(itrM->second.dataint))
+ ids.erase(itrM->second.dataint);
+ }
}
}
}
@@ -7326,15 +7845,15 @@ uint32 GetAreaTriggerScriptId(uint32 trigger_id)
bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value)
{
- if(start_value >= 0 || start_value <= end_value) // start/end reversed for negative values
+ // MAX_DB_SCRIPT_STRING_ID is max allowed negative value for scripts (scrpts can use only more deep negative values
+ // start/end reversed for negative values
+ if (start_value > MAX_DB_SCRIPT_STRING_ID || end_value >= start_value)
{
- sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), use (%d - %d) instead.",table,start_value,end_value,-1,std::numeric_limits<int32>::min());
- start_value = -1;
- end_value = std::numeric_limits<int32>::min();
+ sLog.outErrorDb("Table '%s' attempt loaded with reserved by mangos range (%d - %d), strings not loaded.",table,start_value,end_value+1);
+ return false;
}
- // for scripting localized strings allowed use _only_ negative entries
- return objmgr.LoadTrinityStrings(db,table,end_value,start_value);
+ return objmgr.LoadTrinityStrings(db,table,start_value,end_value);
}
uint32 TRINITY_DLL_SPEC GetScriptId(const char *name)
@@ -7357,16 +7876,6 @@ CreatureInfo const *GetCreatureInfo(uint32 id)
return objmgr.GetCreatureTemplate(id);
}
-CreatureInfo const* GetCreatureTemplateStore(uint32 entry)
-{
- return sCreatureStorage.LookupEntry<CreatureInfo>(entry);
-}
-
-Quest const* GetQuestTemplateStore(uint32 entry)
-{
- return objmgr.GetQuestTemplate(entry);
-}
-
void ObjectMgr::LoadTransportEvents()
{
@@ -7403,3 +7912,12 @@ void ObjectMgr::LoadTransportEvents()
delete result;
}
+CreatureInfo const* GetCreatureTemplateStore(uint32 entry)
+{
+ return sCreatureStorage.LookupEntry<CreatureInfo>(entry);
+}
+
+Quest const* GetQuestTemplateStore(uint32 entry)
+{
+ return objmgr.GetQuestTemplate(entry);
+}
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index 8de6c3333b3..ca4093f875a 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -99,6 +99,16 @@ extern ScriptMapMap sGameObjectScripts;
extern ScriptMapMap sEventScripts;
extern ScriptMapMap sWaypointScripts;
+struct SpellClickInfo
+{
+ uint32 spellId;
+ uint32 questId;
+ uint32 questStatus;
+ uint8 castFlags;
+};
+
+typedef std::multimap<uint32, SpellClickInfo> SpellClickInfoMap;
+
struct AreaTrigger
{
uint32 access_id;
@@ -124,10 +134,12 @@ typedef UNORDERED_MAP<uint64/*(instance,guid) pair*/,time_t> RespawnTimes;
// mangos string ranges
-#define MIN_TRINITY_STRING_ID 1
-#define MAX_TRINITY_STRING_ID 2000000000
-#define MIN_DB_SCRIPT_STRING_ID MAX_TRINITY_STRING_ID
-#define MAX_DB_SCRIPT_STRING_ID 2000010000
+#define MIN_TRINITY_STRING_ID 1 // 'mangos_string'
+#define MAX_TRINITY_STRING_ID 2000000000
+#define MIN_DB_SCRIPT_STRING_ID MAX_TRINITY_STRING_ID // 'db_script_string'
+#define MAX_DB_SCRIPT_STRING_ID 2000010000
+#define MIN_CREATURE_AI_TEXT_STRING_ID (-1) // 'creature_ai_texts'
+#define MAX_CREATURE_AI_TEXT_STRING_ID (-1000000)
struct TrinityStringLocale
{
@@ -143,8 +155,9 @@ typedef UNORDERED_MAP<uint32,ItemLocale> ItemLocaleMap;
typedef UNORDERED_MAP<uint32,QuestLocale> QuestLocaleMap;
typedef UNORDERED_MAP<uint32,NpcTextLocale> NpcTextLocaleMap;
typedef UNORDERED_MAP<uint32,PageTextLocale> PageTextLocaleMap;
-typedef UNORDERED_MAP<uint32,TrinityStringLocale> TrinityStringLocaleMap;
+typedef UNORDERED_MAP<int32,TrinityStringLocale> TrinityStringLocaleMap;
typedef UNORDERED_MAP<uint32,NpcOptionLocale> NpcOptionLocaleMap;
+typedef UNORDERED_MAP<uint32,PointOfInterestLocale> PointOfInterestLocaleMap;
typedef std::multimap<uint32,uint32> QuestRelations;
@@ -171,9 +184,15 @@ struct ReputationOnKillEntry
bool team_dependent;
};
-struct PetCreateSpellEntry
+struct PointOfInterest
{
- uint32 spellid[4];
+ uint32 entry;
+ float x;
+ float y;
+ uint32 icon;
+ uint32 flags;
+ uint32 data;
+ std::string icon_name;
};
#define WEATHER_SEASONS 4
@@ -208,7 +227,7 @@ enum ConditionType
CONDITION_SKILL = 7, // skill_id skill_value
CONDITION_QUESTREWARDED = 8, // quest_id 0
CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active.
- CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD ñommission aura active
+ CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD ńommission aura active
CONDITION_NO_AURA = 11, // spell_id effindex
CONDITION_ACTIVE_EVENT = 12, // event_id
CONDITION_INSTANCE_DATA = 13, // entry data
@@ -311,11 +330,10 @@ class ObjectMgr
typedef UNORDERED_MAP<uint32, AccessRequirement> AccessRequirementMap;
typedef UNORDERED_MAP<uint32, ReputationOnKillEntry> RepOnKillMap;
+ typedef UNORDERED_MAP<uint32, PointOfInterest> PointOfInterestMap;
typedef UNORDERED_MAP<uint32, WeatherZoneChances> WeatherZoneMap;
- typedef UNORDERED_MAP<uint32, PetCreateSpellEntry> PetCreateSpellMap;
-
typedef std::vector<std::string> ScriptNameMap;
UNORDERED_MAP<uint32, uint32> TransportEventMap;
@@ -333,13 +351,13 @@ class ObjectMgr
void RemoveGroup(Group* group) { mGroupSet.erase( group ); }
Guild* GetGuildByLeader(uint64 const&guid) const;
- Guild* GetGuildById(const uint32 GuildId) const;
+ Guild* GetGuildById(uint32 GuildId) const;
Guild* GetGuildByName(const std::string& guildname) const;
- std::string GetGuildNameById(const uint32 GuildId) const;
+ std::string GetGuildNameById(uint32 GuildId) const;
void AddGuild(Guild* guild);
void RemoveGuild(uint32 Id);
- ArenaTeam* GetArenaTeamById(const uint32 arenateamid) const;
+ ArenaTeam* GetArenaTeamById(uint32 arenateamid) const;
ArenaTeam* GetArenaTeamByName(const std::string& arenateamname) const;
ArenaTeam* GetArenaTeamByCaptain(uint64 const& guid) const;
void AddArenaTeam(ArenaTeam* arenaTeam);
@@ -394,9 +412,9 @@ class ObjectMgr
uint32 GetPlayerAccountIdByGUID(const uint64 &guid) const;
uint32 GetPlayerAccountIdByPlayerName(const std::string& name) const;
- uint32 GetNearestTaxiNode( float x, float y, float z, uint32 mapid );
+ uint32 GetNearestTaxiNode( float x, float y, float z, uint32 mapid, uint32 team );
void GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost);
- uint16 GetTaxiMount( uint32 id, uint32 team );
+ uint16 GetTaxiMount( uint32 id, uint32 team, bool allowed_alt_team = false);
void GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds );
void GetTransportPathNodes( uint32 path, TransportPath &pathnodes );
@@ -414,26 +432,17 @@ class ObjectMgr
return itr->second;
return 0;
}
- bool IsTavernAreaTrigger(uint32 Trigger_ID) const { return mTavernAreaTriggerSet.count(Trigger_ID) != 0; }
- bool IsGameObjectForQuests(uint32 entry) const { return mGameObjectForQuestSet.count(entry) != 0; }
- bool IsGuildVaultGameObject(Player *player, uint64 guid) const
+ bool IsTavernAreaTrigger(uint32 Trigger_ID) const
{
- if(GameObject *go = ObjectAccessor::GetGameObject(*player, guid))
- if(go->GetGoType() == GAMEOBJECT_TYPE_GUILD_BANK)
- return true;
- return false;
+ return mTavernAreaTriggerSet.find(Trigger_ID) != mTavernAreaTriggerSet.end();
}
- uint32 GetBattleMasterBG(uint32 entry) const
+ bool IsGameObjectForQuests(uint32 entry) const
{
- BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry);
- if(itr != mBattleMastersMap.end())
- return itr->second;
- return 2; //BATTLEGROUND_WS - i will not add include only for constant usage!
+ return mGameObjectForQuestSet.find(entry) != mGameObjectForQuestSet.end();
}
- void AddGossipText(GossipText *pGText);
- GossipText *GetGossipText(uint32 Text_ID);
+ GossipText const* GetGossipText(uint32 Text_ID) const;
WorldSafeLocsEntry const *GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team);
bool AddGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = true);
@@ -458,6 +467,7 @@ class ObjectMgr
}
AreaTrigger const* GetGoBackTrigger(uint32 Map) const;
+ AreaTrigger const* GetMapEntranceTrigger(uint32 Map) const;
uint32 GetAreaTriggerScriptId(uint32 trigger_id);
@@ -469,10 +479,10 @@ class ObjectMgr
return NULL;
}
- PetCreateSpellEntry const* GetPetCreateSpellEntry(uint32 id) const
+ PointOfInterest const* GetPointOfInterest(uint32 id) const
{
- PetCreateSpellMap::const_iterator itr = mPetCreateSpell.find(id);
- if(itr != mPetCreateSpell.end())
+ PointOfInterestMap::const_iterator itr = mPointsOfInterest.find(id);
+ if(itr != mPointsOfInterest.end())
return &itr->second;
return NULL;
}
@@ -509,8 +519,7 @@ class ObjectMgr
bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value);
bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); }
- void LoadDbScriptStrings();
- void LoadPetCreateSpells();
+ void LoadDbScriptStrings();
void LoadCreatureLocales();
void LoadCreatureTemplates();
void LoadCreatures();
@@ -530,6 +539,7 @@ class ObjectMgr
void LoadNpcTextLocales();
void LoadPageTextLocales();
void LoadNpcOptionLocales();
+ void LoadPointOfInterestLocales();
void LoadInstanceTemplate();
void LoadGossipText();
@@ -539,7 +549,6 @@ class ObjectMgr
void LoadQuestAreaTriggers();
void LoadAreaTriggerScripts();
void LoadTavernAreaTriggers();
- void LoadBattleMastersEntry();
void LoadGameObjectForQuests();
void LoadItemTexts();
@@ -554,6 +563,10 @@ class ObjectMgr
void LoadFishingBaseSkillLevel();
void LoadReputationOnKill();
+ void LoadPointsOfInterest();
+
+ SpellClickInfoMap mSpellClickInfoMap;
+ void LoadNPCSpellClickSpells();
void LoadWeatherZoneChances();
void LoadGameTele();
@@ -565,6 +578,7 @@ class ObjectMgr
std::string GeneratePetName(uint32 entry);
uint32 GetBaseXP(uint32 level);
+ uint32 GetXPForLevel(uint32 level);
int32 GetFishingBaseSkillLevel(uint32 entry) const
{
@@ -576,12 +590,12 @@ class ObjectMgr
void SetHighestGuids();
uint32 GenerateLowGuid(HighGuid guidhigh);
+ uint32 GenerateArenaTeamId();
uint32 GenerateAuctionID();
- uint32 GenerateMailID();
+ uint32 GenerateGuildId();
uint32 GenerateItemTextID();
+ uint32 GenerateMailID();
uint32 GeneratePetNumber();
- uint32 GenerateArenaTeamId();
- uint32 GenerateGuildId();
void LoadPlayerInfoInCache();
PCachePlayerInfo GetPlayerInfoFromCache(uint32 unPlayerGuid) const;
@@ -670,6 +684,12 @@ class ObjectMgr
if(itr==mNpcOptionLocaleMap.end()) return NULL;
return &itr->second;
}
+ PointOfInterestLocale const* GetPointOfInterestLocale(uint32 poi_id) const
+ {
+ PointOfInterestLocaleMap::const_iterator itr = mPointOfInterestLocaleMap.find(poi_id);
+ if(itr==mPointOfInterestLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
GameObjectData const* GetGOData(uint32 guid) const
{
@@ -708,10 +728,7 @@ class ObjectMgr
// reserved names
void LoadReservedPlayersNames();
- bool IsReservedName(const std::string& name) const
- {
- return m_ReservedNames.find(name) != m_ReservedNames.end();
- }
+ bool IsReservedName(const std::string& name) const;
// name with valid structure and symbols
static bool IsValidName( const std::string& name, bool create = false );
@@ -727,8 +744,6 @@ class ObjectMgr
int GetIndexForLocale(LocaleConstant loc);
LocaleConstant GetLocaleForIndex(int i);
- // guild bank tabs
- uint32 GetGuildBankTabPrice(uint8 Index) const { return Index < GUILD_BANK_MAX_TABS ? mGuildBankTabPrice[Index] : 0; }
uint16 GetConditionId(ConditionType condition, uint32 value1, uint32 value2);
bool IsPlayerMeetToCondition(Player const* player, uint16 condition_id) const
@@ -786,20 +801,23 @@ class ObjectMgr
ScriptNameMap &GetScriptNames() { return m_scriptNames; }
const char * GetScriptName(uint32 id) { return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; }
uint32 GetScriptId(const char *name);
+
+ int GetOrNewIndexForLocale(LocaleConstant loc);
protected:
// first free id for selected id type
- uint32 m_auctionid;
- uint32 m_mailid;
- uint32 m_ItemTextId;
uint32 m_arenaTeamId;
+ uint32 m_auctionid;
uint32 m_guildId;
+ uint32 m_ItemTextId;
+ uint32 m_mailid;
uint32 m_hiPetNumber;
// first free low guid for seelcted guid type
uint32 m_hiCharGuid;
uint32 m_hiCreatureGuid;
uint32 m_hiPetGuid;
+ uint32 m_hiVehicleGuid;
uint32 m_hiItemGuid;
uint32 m_hiGoGuid;
uint32 m_hiDoGuid;
@@ -807,9 +825,8 @@ class ObjectMgr
QuestMap mQuestTemplates;
- typedef UNORDERED_MAP<uint32, GossipText*> GossipTextMap;
+ typedef UNORDERED_MAP<uint32, GossipText> GossipTextMap;
typedef UNORDERED_MAP<uint32, uint32> QuestAreaTriggerMap;
- typedef UNORDERED_MAP<uint32, uint32> BattleMastersMap;
typedef UNORDERED_MAP<uint32, std::string> ItemTextMap;
typedef std::set<uint32> TavernAreaTriggerSet;
typedef std::set<uint32> GameObjectForQuestSet;
@@ -818,12 +835,9 @@ class ObjectMgr
GuildMap mGuildMap;
ArenaTeamMap mArenaTeamMap;
- ItemMap mItems;
-
ItemTextMap mItemTexts;
QuestAreaTriggerMap mQuestAreaTriggerMap;
- BattleMastersMap mBattleMastersMap;
TavernAreaTriggerSet mTavernAreaTriggerSet;
GameObjectForQuestSet mGameObjectForQuestSet;
GossipTextMap mGossipText;
@@ -833,12 +847,12 @@ class ObjectMgr
RepOnKillMap mRepOnKill;
- WeatherZoneMap mWeatherZoneMap;
+ PointOfInterestMap mPointsOfInterest;
- PetCreateSpellMap mPetCreateSpell;
+ WeatherZoneMap mWeatherZoneMap;
//character reserved names
- typedef std::set<std::string> ReservedNamesMap;
+ typedef std::set<std::wstring> ReservedNamesMap;
ReservedNamesMap m_ReservedNames;
std::set<uint32> m_DisabledPlayerSpells;
@@ -853,7 +867,6 @@ class ObjectMgr
typedef std::vector<LocaleConstant> LocalForIndex;
LocalForIndex m_LocalForIndex;
- int GetOrNewIndexForLocale(LocaleConstant loc);
int DBCLocaleIndex;
@@ -872,6 +885,9 @@ class ObjectMgr
void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const;
PlayerInfo playerInfo[MAX_RACES][MAX_CLASSES];
+ typedef std::vector<uint32> PlayerXPperLevel; // [level]
+ PlayerXPperLevel mPlayerXPperLevel;
+
typedef std::map<uint32,uint32> BaseXPMap; // [area level][base xp]
BaseXPMap mBaseXPTable;
@@ -894,12 +910,10 @@ class ObjectMgr
PageTextLocaleMap mPageTextLocaleMap;
TrinityStringLocaleMap mTrinityStringLocaleMap;
NpcOptionLocaleMap mNpcOptionLocaleMap;
+ PointOfInterestLocaleMap mPointOfInterestLocaleMap;
RespawnTimes mCreatureRespawnTimes;
RespawnTimes mGORespawnTimes;
- typedef std::vector<uint32> GuildBankTabPriceMap;
- GuildBankTabPriceMap mGuildBankTabPrice;
-
// Storage for Conditions. First element (index 0) is reserved for zero-condition (nothing required)
typedef std::vector<PlayerCondition> ConditionStore;
ConditionStore mConditions;
@@ -913,7 +927,7 @@ class ObjectMgr
#define objmgr Trinity::Singleton<ObjectMgr>::Instance()
// scripting access functions
-TRINITY_DLL_SPEC bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value = -1, int32 end_value = std::numeric_limits<int32>::min());
+TRINITY_DLL_SPEC bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value = MAX_CREATURE_AI_TEXT_STRING_ID, int32 end_value = std::numeric_limits<int32>::min());
TRINITY_DLL_SPEC uint32 GetAreaTriggerScriptId(uint32 trigger_id);
TRINITY_DLL_SPEC uint32 GetScriptId(const char *name);
TRINITY_DLL_SPEC ObjectMgr::ScriptNameMap& GetScriptNames();
@@ -923,4 +937,3 @@ TRINITY_DLL_SPEC CreatureInfo const* GetCreatureTemplateStore(uint32 entry);
TRINITY_DLL_SPEC Quest const* GetQuestTemplateStore(uint32 entry);
#endif
-
diff --git a/src/game/ObjectPosSelector.cpp b/src/game/ObjectPosSelector.cpp
new file mode 100644
index 00000000000..899dfec3fdb
--- /dev/null
+++ b/src/game/ObjectPosSelector.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ObjectPosSelector.h"
+
+ObjectPosSelector::ObjectPosSelector(float x,float y,float size,float dist)
+: m_center_x(x),m_center_y(y),m_size(size),m_dist(dist)
+{
+ m_anglestep = acos(m_dist/(m_dist+2*m_size));
+
+ m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].end();
+ m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].end();
+
+ m_smallStepAngle[USED_POS_PLUS] = 0;
+ m_smallStepAngle[USED_POS_MINUS] = 0;
+
+ m_smallStepOk[USED_POS_PLUS] = false;
+ m_smallStepOk[USED_POS_MINUS] = false;
+
+ m_smallStepNextUsedPos[USED_POS_PLUS] = NULL;
+ m_smallStepNextUsedPos[USED_POS_MINUS] = NULL;
+}
+
+ObjectPosSelector::UsedPosList::value_type const* ObjectPosSelector::nextUsedPos(UsedPosType uptype)
+{
+ UsedPosList::const_iterator itr = m_nextUsedPos[uptype];
+ if(itr!=m_UsedPosLists[uptype].end())
+ ++itr;
+
+ if(itr==m_UsedPosLists[uptype].end())
+ {
+ if(!m_UsedPosLists[~uptype].empty())
+ return &*m_UsedPosLists[~uptype].rbegin();
+ else
+ return NULL;
+ }
+ else
+ return &*itr;
+}
+
+void ObjectPosSelector::AddUsedPos(float size,float angle,float dist)
+{
+ if(angle>=0)
+ m_UsedPosLists[USED_POS_PLUS].insert(UsedPosList::value_type(angle,UsedPos(1.0,size,dist)));
+ else
+ m_UsedPosLists[USED_POS_MINUS].insert(UsedPosList::value_type(-angle,UsedPos(-1.0,size,dist)));
+}
+
+void ObjectPosSelector::InitializeAngle()
+{
+ m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].begin();
+ m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].begin();
+
+ m_smallStepAngle[USED_POS_PLUS] = 0;
+ m_smallStepAngle[USED_POS_MINUS] = 0;
+
+ m_smallStepOk[USED_POS_PLUS] = true;
+ m_smallStepOk[USED_POS_MINUS] = true;
+}
+
+bool ObjectPosSelector::FirstAngle(float& angle)
+{
+ if(m_UsedPosLists[USED_POS_PLUS].empty() && !m_UsedPosLists[USED_POS_MINUS].empty() )
+ return NextAngleFor(*m_UsedPosLists[USED_POS_MINUS].begin(),1.0,USED_POS_PLUS,angle);
+ else if(m_UsedPosLists[USED_POS_MINUS].empty() && !m_UsedPosLists[USED_POS_PLUS].empty() )
+ return NextAngleFor(*m_UsedPosLists[USED_POS_PLUS].begin(),-1.0,USED_POS_MINUS,angle);
+
+ return false;
+}
+
+bool ObjectPosSelector::NextAngle(float& angle)
+{
+ while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() ||
+ m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() ||
+ m_smallStepOk[USED_POS_PLUS] || m_smallStepOk[USED_POS_MINUS] )
+ {
+ // calculate next possible angle
+ if(NextPosibleAngle(angle))
+ return true;
+ }
+
+ return false;
+}
+
+bool ObjectPosSelector::NextUsedAngle(float& angle)
+{
+ while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() ||
+ m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() )
+ {
+ // calculate next possible angle
+ if(!NextPosibleAngle(angle))
+ return true;
+ }
+
+ return false;
+}
+
+bool ObjectPosSelector::NextPosibleAngle( float& angle )
+{
+ // ++ direction less updated
+ if( m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() &&
+ (m_nextUsedPos[USED_POS_MINUS]==m_UsedPosLists[USED_POS_MINUS].end() || m_nextUsedPos[USED_POS_PLUS]->first <= m_nextUsedPos[USED_POS_MINUS]->first) )
+ {
+ bool ok;
+ if(m_smallStepOk[USED_POS_PLUS])
+ ok = NextSmallStepAngle(1.0,USED_POS_PLUS,angle);
+ else
+ ok = NextAngleFor(*m_nextUsedPos[USED_POS_PLUS],1.0,USED_POS_PLUS,angle);
+
+ if(!ok)
+ ++m_nextUsedPos[USED_POS_PLUS]; // increase. only at fail (original or checked)
+ return ok;
+ }
+ // -- direction less updated
+ else if( m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end())
+ {
+ bool ok;
+ if(m_smallStepOk[USED_POS_MINUS])
+ ok = NextSmallStepAngle(-1.0,USED_POS_MINUS,angle);
+ else
+ ok = NextAngleFor(*m_nextUsedPos[USED_POS_MINUS],-1.0,USED_POS_MINUS,angle);
+
+ if(!ok)
+ ++m_nextUsedPos[USED_POS_MINUS];
+ return ok;
+ }
+ else // both list empty
+ {
+ if( m_smallStepOk[USED_POS_PLUS] && (!m_smallStepOk[USED_POS_MINUS] || m_smallStepAngle[USED_POS_PLUS] <= m_smallStepAngle[USED_POS_MINUS]) )
+ {
+ return NextSmallStepAngle(1.0,USED_POS_PLUS,angle);
+ }
+ // -- direction less updated
+ else if( m_smallStepOk[USED_POS_MINUS] )
+ {
+ return NextSmallStepAngle(-1.0,USED_POS_MINUS,angle);
+ }
+ }
+
+ // no angles
+ return false;
+}
diff --git a/src/game/ObjectPosSelector.h b/src/game/ObjectPosSelector.h
new file mode 100644
index 00000000000..84050611121
--- /dev/null
+++ b/src/game/ObjectPosSelector.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _OBJECT_POS_SELECTOR_H
+#define _OBJECT_POS_SELECTOR_H
+
+#include<Common.h>
+
+#include<map>
+
+enum UsedPosType { USED_POS_PLUS, USED_POS_MINUS };
+
+inline UsedPosType operator ~(UsedPosType uptype)
+{
+ return uptype==USED_POS_PLUS ? USED_POS_MINUS : USED_POS_PLUS;
+}
+
+struct ObjectPosSelector
+{
+ struct UsedPos
+ {
+ UsedPos(float sign_, float size_,float dist_) : sign(sign_), size(size_),dist(dist_) {}
+
+ float sign;
+
+ float size; // size of point
+ float dist; // dist to central point (including central point size)
+ };
+
+ typedef std::multimap<float,UsedPos> UsedPosList; // abs(angle)->Node
+
+ ObjectPosSelector(float x,float y,float size,float dist);
+
+ void AddUsedPos(float size,float angle,float dist);
+ void InitializeAngle();
+
+ bool FirstAngle(float& angle);
+ bool NextAngle(float& angle);
+ bool NextUsedAngle(float& angle);
+
+ bool NextPosibleAngle( float& angle );
+
+ bool CheckAngle(UsedPosList::value_type const& nextUsedPos, float sign, float angle ) const
+ {
+ float angle_step2 = GetAngle(nextUsedPos.second);
+
+ float next_angle = nextUsedPos.first;
+ if(nextUsedPos.second.sign * sign < 0) // last node from diff. list (-pi+alpha)
+ next_angle = 2*M_PI-next_angle; // move to positive
+
+ return fabs(angle)+angle_step2 <= next_angle;
+ }
+
+ bool CheckOriginal() const
+ {
+ return (m_UsedPosLists[USED_POS_PLUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_PLUS].begin(),1.0,0)) &&
+ (m_UsedPosLists[USED_POS_MINUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_MINUS].begin(),-1.0,0));
+ }
+
+ bool IsNonBalanced() const { return m_UsedPosLists[USED_POS_PLUS].empty() != m_UsedPosLists[USED_POS_MINUS].empty(); }
+
+ bool NextAngleFor( UsedPosList::value_type const& usedPos, float sign, UsedPosType uptype, float &angle )
+ {
+ float angle_step = GetAngle(usedPos.second);
+
+ // next possible angle
+ angle = usedPos.first * usedPos.second.sign + angle_step * sign;
+
+ UsedPosList::value_type const* nextNode = nextUsedPos(uptype);
+ if(nextNode)
+ {
+ // if next node permit use selected angle, then do it
+ if(!CheckAngle(*nextNode, sign, angle))
+ {
+ m_smallStepOk[uptype] = false;
+ return false;
+ }
+ }
+
+ // possible more points
+ m_smallStepOk[uptype] = true;
+ m_smallStepAngle[uptype] = angle;
+ m_smallStepNextUsedPos[uptype] = nextNode;
+
+ return true;
+ }
+
+ bool NextSmallStepAngle( float sign, UsedPosType uptype, float &angle )
+ {
+ // next possible angle
+ angle = m_smallStepAngle[uptype] + m_anglestep * sign;
+
+ if(fabs(angle) > M_PI)
+ {
+ m_smallStepOk[uptype] = false;
+ return false;
+ }
+
+ if(m_smallStepNextUsedPos[uptype])
+ {
+ if(fabs(angle) >= m_smallStepNextUsedPos[uptype]->first)
+ {
+ m_smallStepOk[uptype] = false;
+ return false;
+ }
+
+ // if next node permit use selected angle, then do it
+ if(!CheckAngle(*m_smallStepNextUsedPos[uptype], sign, angle))
+ {
+ m_smallStepOk[uptype] = false;
+ return false;
+ }
+ }
+
+ // possible more points
+ m_smallStepAngle[uptype] = angle;
+ return true;
+ }
+
+ // next used post for m_nextUsedPos[uptype]
+ UsedPosList::value_type const* nextUsedPos(UsedPosType uptype);
+
+ // angle from used pos to next possible free pos
+ float GetAngle(UsedPos const& usedPos) const { return acos(m_dist/(usedPos.dist+usedPos.size+m_size)); }
+
+ float m_center_x;
+ float m_center_y;
+ float m_size; // size of object in center
+ float m_dist; // distance for searching pos (including central object size)
+ float m_anglestep;
+
+ UsedPosList m_UsedPosLists[2];
+ UsedPosList::const_iterator m_nextUsedPos[2];
+
+ // field for small step from first after next used pos until next pos
+ float m_smallStepAngle[2];
+ bool m_smallStepOk[2];
+ UsedPosList::value_type const* m_smallStepNextUsedPos[2];
+};
+#endif
diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp
index eebe4343797..536423345c6 100644
--- a/src/game/Opcodes.cpp
+++ b/src/game/Opcodes.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,1065 +28,1202 @@
/// Correspondence between opcodes and their names
OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
{
- /*0x000*/ { "MSG_NULL_ACTION", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x001*/ { "CMSG_BOOTME", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x002*/ { "CMSG_DBLOOKUP", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x003*/ { "SMSG_DBLOOKUP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x004*/ { "CMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x005*/ { "SMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x006*/ { "CMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x007*/ { "SMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x008*/ { "CMSG_WORLD_TELEPORT", STATUS_LOGGEDIN, &WorldSession::HandleWorldTeleportOpcode },
- /*0x009*/ { "CMSG_TELEPORT_TO_UNIT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL },
- /*0x00A*/ { "CMSG_ZONE_MAP", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x00B*/ { "SMSG_ZONE_MAP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x00C*/ { "CMSG_DEBUG_CHANGECELLZONE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x00D*/ { "CMSG_EMBLAZON_TABARD_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x00E*/ { "CMSG_UNEMBLAZON_TABARD_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x00F*/ { "CMSG_RECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x010*/ { "CMSG_LEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x011*/ { "CMSG_CREATEMONSTER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x012*/ { "CMSG_DESTROYMONSTER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x013*/ { "CMSG_CREATEITEM", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x014*/ { "CMSG_CREATEGAMEOBJECT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x015*/ { "SMSG_CHECK_FOR_BOTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x016*/ { "CMSG_MAKEMONSTERATTACKGUID", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x017*/ { "CMSG_BOT_DETECTED2", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x018*/ { "CMSG_FORCEACTION", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x019*/ { "CMSG_FORCEACTIONONOTHER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x01A*/ { "CMSG_FORCEACTIONSHOW", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x01B*/ { "SMSG_FORCEACTIONSHOW", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x01C*/ { "CMSG_PETGODMODE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x01D*/ { "SMSG_PETGODMODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x01E*/ { "SMSG_DEBUGINFOSPELLMISS_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x01F*/ { "CMSG_WEATHER_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x020*/ { "CMSG_UNDRESSPLAYER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x021*/ { "CMSG_BEASTMASTER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x022*/ { "CMSG_GODMODE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x023*/ { "SMSG_GODMODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x024*/ { "CMSG_CHEAT_SETMONEY", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x025*/ { "CMSG_LEVEL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x026*/ { "CMSG_PET_LEVEL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x027*/ { "CMSG_SET_WORLDSTATE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x028*/ { "CMSG_COOLDOWN_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x029*/ { "CMSG_USE_SKILL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x02A*/ { "CMSG_FLAG_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x02B*/ { "CMSG_FLAG_QUEST_FINISH", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x02C*/ { "CMSG_CLEAR_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x02D*/ { "CMSG_SEND_EVENT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x02E*/ { "CMSG_DEBUG_AISTATE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x02F*/ { "SMSG_DEBUG_AISTATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x030*/ { "CMSG_DISABLE_PVP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x031*/ { "CMSG_ADVANCE_SPAWN_TIME", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x032*/ { "CMSG_PVP_PORT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x033*/ { "CMSG_AUTH_SRP6_BEGIN", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x034*/ { "CMSG_AUTH_SRP6_PROOF", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x035*/ { "CMSG_AUTH_SRP6_RECODE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x036*/ { "CMSG_CHAR_CREATE", STATUS_AUTHED, &WorldSession::HandleCharCreateOpcode },
- /*0x037*/ { "CMSG_CHAR_ENUM", STATUS_AUTHED, &WorldSession::HandleCharEnumOpcode },
- /*0x038*/ { "CMSG_CHAR_DELETE", STATUS_AUTHED, &WorldSession::HandleCharDeleteOpcode },
- /*0x039*/ { "SMSG_AUTH_SRP6_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x03A*/ { "SMSG_CHAR_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x03B*/ { "SMSG_CHAR_ENUM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x03C*/ { "SMSG_CHAR_DELETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x03D*/ { "CMSG_PLAYER_LOGIN", STATUS_AUTHED, &WorldSession::HandlePlayerLoginOpcode },
- /*0x03E*/ { "SMSG_NEW_WORLD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x03F*/ { "SMSG_TRANSFER_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x040*/ { "SMSG_TRANSFER_ABORTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x041*/ { "SMSG_CHARACTER_LOGIN_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x042*/ { "SMSG_LOGIN_SETTIMESPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x043*/ { "SMSG_GAMETIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x044*/ { "CMSG_GAMETIME_SET", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x045*/ { "SMSG_GAMETIME_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x046*/ { "CMSG_GAMESPEED_SET", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x047*/ { "SMSG_GAMESPEED_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x048*/ { "CMSG_SERVERTIME", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x049*/ { "SMSG_SERVERTIME", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x04A*/ { "CMSG_PLAYER_LOGOUT", STATUS_LOGGEDIN, &WorldSession::HandlePlayerLogoutOpcode },
- /*0x04B*/ { "CMSG_LOGOUT_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLogoutRequestOpcode },
- /*0x04C*/ { "SMSG_LOGOUT_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x04D*/ { "SMSG_LOGOUT_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x04E*/ { "CMSG_LOGOUT_CANCEL", STATUS_LOGGEDIN, &WorldSession::HandleLogoutCancelOpcode },
- /*0x04F*/ { "SMSG_LOGOUT_CANCEL_ACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x050*/ { "CMSG_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleNameQueryOpcode },
- /*0x051*/ { "SMSG_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x052*/ { "CMSG_PET_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePetNameQuery },
- /*0x053*/ { "SMSG_PET_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x054*/ { "CMSG_GUILD_QUERY", STATUS_AUTHED, &WorldSession::HandleGuildQueryOpcode },
- /*0x055*/ { "SMSG_GUILD_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x056*/ { "CMSG_ITEM_QUERY_SINGLE", STATUS_LOGGEDIN, &WorldSession::HandleItemQuerySingleOpcode },
- /*0x057*/ { "CMSG_ITEM_QUERY_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x058*/ { "SMSG_ITEM_QUERY_SINGLE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x059*/ { "SMSG_ITEM_QUERY_MULTIPLE_RESPONSE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x05A*/ { "CMSG_PAGE_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePageQueryOpcode },
- /*0x05B*/ { "SMSG_PAGE_TEXT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x05C*/ { "CMSG_QUEST_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestQueryOpcode },
- /*0x05D*/ { "SMSG_QUEST_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x05E*/ { "CMSG_GAMEOBJECT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGameObjectQueryOpcode },
- /*0x05F*/ { "SMSG_GAMEOBJECT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x060*/ { "CMSG_CREATURE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCreatureQueryOpcode },
- /*0x061*/ { "SMSG_CREATURE_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x062*/ { "CMSG_WHO", STATUS_LOGGEDIN, &WorldSession::HandleWhoOpcode },
- /*0x063*/ { "SMSG_WHO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x064*/ { "CMSG_WHOIS", STATUS_LOGGEDIN, &WorldSession::HandleWhoisOpcode },
- /*0x065*/ { "SMSG_WHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x066*/ { "CMSG_CONTACT_LIST", STATUS_LOGGEDIN, &WorldSession::HandleFriendListOpcode },
- /*0x067*/ { "SMSG_CONTACT_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x068*/ { "SMSG_FRIEND_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x069*/ { "CMSG_ADD_FRIEND", STATUS_LOGGEDIN, &WorldSession::HandleAddFriendOpcode },
- /*0x06A*/ { "CMSG_DEL_FRIEND", STATUS_LOGGEDIN, &WorldSession::HandleDelFriendOpcode },
- /*0x06B*/ { "CMSG_SET_CONTACT_NOTES", STATUS_LOGGEDIN, &WorldSession::HandleSetFriendNoteOpcode },
- /*0x06C*/ { "CMSG_ADD_IGNORE", STATUS_LOGGEDIN, &WorldSession::HandleAddIgnoreOpcode },
- /*0x06D*/ { "CMSG_DEL_IGNORE", STATUS_LOGGEDIN, &WorldSession::HandleDelIgnoreOpcode },
- /*0x06E*/ { "CMSG_GROUP_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleGroupInviteOpcode },
- /*0x06F*/ { "SMSG_GROUP_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x070*/ { "CMSG_GROUP_CANCEL", STATUS_LOGGEDIN, &WorldSession::Handle_Deprecated },
- /*0x071*/ { "SMSG_GROUP_CANCEL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x072*/ { "CMSG_GROUP_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleGroupAcceptOpcode },
- /*0x073*/ { "CMSG_GROUP_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleGroupDeclineOpcode },
- /*0x074*/ { "SMSG_GROUP_DECLINE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x075*/ { "CMSG_GROUP_UNINVITE", STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteNameOpcode },
- /*0x076*/ { "CMSG_GROUP_UNINVITE_GUID", STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteGuidOpcode },
- /*0x077*/ { "SMSG_GROUP_UNINVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x078*/ { "CMSG_GROUP_SET_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupSetLeaderOpcode },
- /*0x079*/ { "SMSG_GROUP_SET_LEADER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x07A*/ { "CMSG_LOOT_METHOD", STATUS_LOGGEDIN, &WorldSession::HandleLootMethodOpcode },
- /*0x07B*/ { "CMSG_GROUP_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleGroupLeaveOpcode },
- /*0x07C*/ { "SMSG_GROUP_DESTROYED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x07D*/ { "SMSG_GROUP_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x07E*/ { "SMSG_PARTY_MEMBER_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x07F*/ { "SMSG_PARTY_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x080*/ { "UMSG_UPDATE_GROUP_MEMBERS", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x081*/ { "CMSG_GUILD_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildCreateOpcode },
- /*0x082*/ { "CMSG_GUILD_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleGuildInviteOpcode },
- /*0x083*/ { "SMSG_GUILD_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x084*/ { "CMSG_GUILD_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleGuildAcceptOpcode },
- /*0x085*/ { "CMSG_GUILD_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleGuildDeclineOpcode },
- /*0x086*/ { "SMSG_GUILD_DECLINE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x087*/ { "CMSG_GUILD_INFO", STATUS_LOGGEDIN, &WorldSession::HandleGuildInfoOpcode },
- /*0x088*/ { "SMSG_GUILD_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x089*/ { "CMSG_GUILD_ROSTER", STATUS_LOGGEDIN, &WorldSession::HandleGuildRosterOpcode },
- /*0x08A*/ { "SMSG_GUILD_ROSTER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x08B*/ { "CMSG_GUILD_PROMOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildPromoteOpcode },
- /*0x08C*/ { "CMSG_GUILD_DEMOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildDemoteOpcode },
- /*0x08D*/ { "CMSG_GUILD_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleGuildLeaveOpcode },
- /*0x08E*/ { "CMSG_GUILD_REMOVE", STATUS_LOGGEDIN, &WorldSession::HandleGuildRemoveOpcode },
- /*0x08F*/ { "CMSG_GUILD_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleGuildDisbandOpcode },
- /*0x090*/ { "CMSG_GUILD_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGuildLeaderOpcode },
- /*0x091*/ { "CMSG_GUILD_MOTD", STATUS_LOGGEDIN, &WorldSession::HandleGuildMOTDOpcode },
- /*0x092*/ { "SMSG_GUILD_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x093*/ { "SMSG_GUILD_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x094*/ { "UMSG_UPDATE_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x095*/ { "CMSG_MESSAGECHAT", STATUS_LOGGEDIN, &WorldSession::HandleMessagechatOpcode },
- /*0x096*/ { "SMSG_MESSAGECHAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x097*/ { "CMSG_JOIN_CHANNEL", STATUS_LOGGEDIN, &WorldSession::HandleChannelJoin },
- /*0x098*/ { "CMSG_LEAVE_CHANNEL", STATUS_LOGGEDIN, &WorldSession::HandleChannelLeave },
- /*0x099*/ { "SMSG_CHANNEL_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x09A*/ { "CMSG_CHANNEL_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelList },
- /*0x09B*/ { "SMSG_CHANNEL_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x09C*/ { "CMSG_CHANNEL_PASSWORD", STATUS_LOGGEDIN, &WorldSession::HandleChannelPassword },
- /*0x09D*/ { "CMSG_CHANNEL_SET_OWNER", STATUS_LOGGEDIN, &WorldSession::HandleChannelSetOwner },
- /*0x09E*/ { "CMSG_CHANNEL_OWNER", STATUS_LOGGEDIN, &WorldSession::HandleChannelOwner },
- /*0x09F*/ { "CMSG_CHANNEL_MODERATOR", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerator },
- /*0x0A0*/ { "CMSG_CHANNEL_UNMODERATOR", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnmoderator },
- /*0x0A1*/ { "CMSG_CHANNEL_MUTE", STATUS_LOGGEDIN, &WorldSession::HandleChannelMute },
- /*0x0A2*/ { "CMSG_CHANNEL_UNMUTE", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnmute },
- /*0x0A3*/ { "CMSG_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelInvite },
- /*0x0A4*/ { "CMSG_CHANNEL_KICK", STATUS_LOGGEDIN, &WorldSession::HandleChannelKick },
- /*0x0A5*/ { "CMSG_CHANNEL_BAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelBan },
- /*0x0A6*/ { "CMSG_CHANNEL_UNBAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnban },
- /*0x0A7*/ { "CMSG_CHANNEL_ANNOUNCEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleChannelAnnounce },
- /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerate },
- /*0x0A9*/ { "SMSG_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0AA*/ { "SMSG_DESTROY_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0AB*/ { "CMSG_USE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleUseItemOpcode },
- /*0x0AC*/ { "CMSG_OPEN_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleOpenItemOpcode },
- /*0x0AD*/ { "CMSG_READ_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleReadItem },
- /*0x0AE*/ { "SMSG_READ_ITEM_OK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0AF*/ { "SMSG_READ_ITEM_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0B0*/ { "SMSG_ITEM_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0B1*/ { "CMSG_GAMEOBJ_USE", STATUS_LOGGEDIN, &WorldSession::HandleGameObjectUseOpcode },
- /*0x0B2*/ { "CMSG_GAMEOBJ_CHAIR_USE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0B3*/ { "SMSG_GAMEOBJECT_CUSTOM_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0B4*/ { "CMSG_AREATRIGGER", STATUS_LOGGEDIN, &WorldSession::HandleAreaTriggerOpcode },
- /*0x0B5*/ { "MSG_MOVE_START_FORWARD", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0B6*/ { "MSG_MOVE_START_BACKWARD", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0B7*/ { "MSG_MOVE_STOP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0B8*/ { "MSG_MOVE_START_STRAFE_LEFT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0B9*/ { "MSG_MOVE_START_STRAFE_RIGHT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0BA*/ { "MSG_MOVE_STOP_STRAFE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0BB*/ { "MSG_MOVE_JUMP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0BC*/ { "MSG_MOVE_START_TURN_LEFT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0BD*/ { "MSG_MOVE_START_TURN_RIGHT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0BE*/ { "MSG_MOVE_STOP_TURN", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0BF*/ { "MSG_MOVE_START_PITCH_UP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0C0*/ { "MSG_MOVE_START_PITCH_DOWN", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0C1*/ { "MSG_MOVE_STOP_PITCH", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0C2*/ { "MSG_MOVE_SET_RUN_MODE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0C3*/ { "MSG_MOVE_SET_WALK_MODE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0C4*/ { "MSG_MOVE_TOGGLE_LOGGING", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0C5*/ { "MSG_MOVE_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0C6*/ { "MSG_MOVE_TELEPORT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0C7*/ { "MSG_MOVE_TELEPORT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveTeleportAck },
- /*0x0C8*/ { "MSG_MOVE_TOGGLE_FALL_LOGGING", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0C9*/ { "MSG_MOVE_FALL_LAND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0CA*/ { "MSG_MOVE_START_SWIM", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0CB*/ { "MSG_MOVE_STOP_SWIM", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0CC*/ { "MSG_MOVE_SET_RUN_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0CD*/ { "MSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0CE*/ { "MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT",STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0CF*/ { "MSG_MOVE_SET_RUN_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D0*/ { "MSG_MOVE_SET_WALK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D1*/ { "MSG_MOVE_SET_WALK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D2*/ { "MSG_MOVE_SET_SWIM_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D3*/ { "MSG_MOVE_SET_SWIM_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D4*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT",STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D5*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D6*/ { "MSG_MOVE_SET_ALL_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D7*/ { "MSG_MOVE_SET_TURN_RATE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D8*/ { "MSG_MOVE_SET_TURN_RATE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0D9*/ { "MSG_MOVE_TOGGLE_COLLISION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0DA*/ { "MSG_MOVE_SET_FACING", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0DB*/ { "MSG_MOVE_SET_PITCH", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0DC*/ { "MSG_MOVE_WORLDPORT_ACK", STATUS_TRANSFER_PENDING, &WorldSession::HandleMoveWorldportAckOpcode},
- /*0x0DD*/ { "SMSG_MONSTER_MOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0DE*/ { "SMSG_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0DF*/ { "SMSG_MOVE_LAND_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0E0*/ { "MSG_MOVE_SET_RAW_POSITION_ACK", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0E1*/ { "CMSG_MOVE_SET_RAW_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0E2*/ { "SMSG_FORCE_RUN_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0E3*/ { "CMSG_FORCE_RUN_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
- /*0x0E4*/ { "SMSG_FORCE_RUN_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0E5*/ { "CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK",STATUS_LOGGEDIN,&WorldSession::HandleForceSpeedChangeAck },
- /*0x0E6*/ { "SMSG_FORCE_SWIM_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0E7*/ { "CMSG_FORCE_SWIM_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
- /*0x0E8*/ { "SMSG_FORCE_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0E9*/ { "CMSG_FORCE_MOVE_ROOT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveRootAck },
- /*0x0EA*/ { "SMSG_FORCE_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0EB*/ { "CMSG_FORCE_MOVE_UNROOT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveUnRootAck },
- /*0x0EC*/ { "MSG_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0ED*/ { "MSG_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0EE*/ { "MSG_MOVE_HEARTBEAT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x0EF*/ { "SMSG_MOVE_KNOCK_BACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0F0*/ { "CMSG_MOVE_KNOCK_BACK_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveKnockBackAck },
- /*0x0F1*/ { "MSG_MOVE_KNOCK_BACK", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0F2*/ { "SMSG_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0F3*/ { "SMSG_MOVE_NORMAL_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0F4*/ { "SMSG_MOVE_SET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0F5*/ { "SMSG_MOVE_UNSET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0F6*/ { "CMSG_MOVE_HOVER_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveHoverAck },
- /*0x0F7*/ { "MSG_MOVE_HOVER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0F8*/ { "CMSG_TRIGGER_CINEMATIC_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0F9*/ { "CMSG_OPENING_CINEMATIC", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x0FA*/ { "SMSG_TRIGGER_CINEMATIC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0FB*/ { "CMSG_NEXT_CINEMATIC_CAMERA", STATUS_LOGGEDIN, &WorldSession::HandleNextCinematicCamera },
- /*0x0FC*/ { "CMSG_COMPLETE_CINEMATIC", STATUS_LOGGEDIN, &WorldSession::HandleCompleteCinema },
- /*0x0FD*/ { "SMSG_TUTORIAL_FLAGS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x0FE*/ { "CMSG_TUTORIAL_FLAG", STATUS_LOGGEDIN, &WorldSession::HandleTutorialFlag },
- /*0x0FF*/ { "CMSG_TUTORIAL_CLEAR", STATUS_LOGGEDIN, &WorldSession::HandleTutorialClear },
- /*0x100*/ { "CMSG_TUTORIAL_RESET", STATUS_LOGGEDIN, &WorldSession::HandleTutorialReset },
- /*0x101*/ { "CMSG_STANDSTATECHANGE", STATUS_LOGGEDIN, &WorldSession::HandleStandStateChangeOpcode },
- /*0x102*/ { "CMSG_EMOTE", STATUS_LOGGEDIN, &WorldSession::HandleEmoteOpcode },
- /*0x103*/ { "SMSG_EMOTE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x104*/ { "CMSG_TEXT_EMOTE", STATUS_LOGGEDIN, &WorldSession::HandleTextEmoteOpcode },
- /*0x105*/ { "SMSG_TEXT_EMOTE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x106*/ { "CMSG_AUTOEQUIP_GROUND_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x107*/ { "CMSG_AUTOSTORE_GROUND_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x108*/ { "CMSG_AUTOSTORE_LOOT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutostoreLootItemOpcode },
- /*0x109*/ { "CMSG_STORE_LOOT_IN_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x10A*/ { "CMSG_AUTOEQUIP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoEquipItemOpcode },
- /*0x10B*/ { "CMSG_AUTOSTORE_BAG_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBagItemOpcode },
- /*0x10C*/ { "CMSG_SWAP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSwapItem },
- /*0x10D*/ { "CMSG_SWAP_INV_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSwapInvItemOpcode },
- /*0x10E*/ { "CMSG_SPLIT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSplitItemOpcode },
- /*0x10F*/ { "CMSG_AUTOEQUIP_ITEM_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleAutoEquipItemSlotOpcode },
- /*0x110*/ { "OBSOLETE_DROP_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x111*/ { "CMSG_DESTROYITEM", STATUS_LOGGEDIN, &WorldSession::HandleDestroyItemOpcode },
- /*0x112*/ { "SMSG_INVENTORY_CHANGE_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x113*/ { "SMSG_OPEN_CONTAINER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x114*/ { "CMSG_INSPECT", STATUS_LOGGEDIN, &WorldSession::HandleInspectOpcode },
- /*0x115*/ { "SMSG_INSPECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x116*/ { "CMSG_INITIATE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleInitiateTradeOpcode },
- /*0x117*/ { "CMSG_BEGIN_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleBeginTradeOpcode },
- /*0x118*/ { "CMSG_BUSY_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleBusyTradeOpcode },
- /*0x119*/ { "CMSG_IGNORE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleIgnoreTradeOpcode },
- /*0x11A*/ { "CMSG_ACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleAcceptTradeOpcode },
- /*0x11B*/ { "CMSG_UNACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleUnacceptTradeOpcode },
- /*0x11C*/ { "CMSG_CANCEL_TRADE", STATUS_AUTHED, &WorldSession::HandleCancelTradeOpcode },
- /*0x11D*/ { "CMSG_SET_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeItemOpcode },
- /*0x11E*/ { "CMSG_CLEAR_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleClearTradeItemOpcode },
- /*0x11F*/ { "CMSG_SET_TRADE_GOLD", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeGoldOpcode },
- /*0x120*/ { "SMSG_TRADE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x121*/ { "SMSG_TRADE_STATUS_EXTENDED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x122*/ { "SMSG_INITIALIZE_FACTIONS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x123*/ { "SMSG_SET_FACTION_VISIBLE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x124*/ { "SMSG_SET_FACTION_STANDING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x125*/ { "CMSG_SET_FACTION_ATWAR", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionAtWar },
- /*0x126*/ { "CMSG_SET_FACTION_CHEAT", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionCheat },
- /*0x127*/ { "SMSG_SET_PROFICIENCY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x128*/ { "CMSG_SET_ACTION_BUTTON", STATUS_LOGGEDIN, &WorldSession::HandleSetActionButtonOpcode },
- /*0x129*/ { "SMSG_ACTION_BUTTONS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x12A*/ { "SMSG_INITIAL_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x12B*/ { "SMSG_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x12C*/ { "SMSG_SUPERCEDED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x12D*/ { "CMSG_NEW_SPELL_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x12E*/ { "CMSG_CAST_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleCastSpellOpcode },
- /*0x12F*/ { "CMSG_CANCEL_CAST", STATUS_LOGGEDIN, &WorldSession::HandleCancelCastOpcode },
- /*0x130*/ { "SMSG_CAST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x131*/ { "SMSG_SPELL_START", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x132*/ { "SMSG_SPELL_GO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x133*/ { "SMSG_SPELL_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x134*/ { "SMSG_SPELL_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x135*/ { "SMSG_COOLDOWN_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x136*/ { "CMSG_CANCEL_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelAuraOpcode },
- /*0x137*/ { "SMSG_UPDATE_AURA_DURATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x138*/ { "SMSG_PET_CAST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x139*/ { "MSG_CHANNEL_START", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x13A*/ { "MSG_CHANNEL_UPDATE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x13B*/ { "CMSG_CANCEL_CHANNELLING", STATUS_LOGGEDIN, &WorldSession::HandleCancelChanneling },
- /*0x13C*/ { "SMSG_AI_REACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x13D*/ { "CMSG_SET_SELECTION", STATUS_LOGGEDIN, &WorldSession::HandleSetSelectionOpcode },
- /*0x13E*/ { "CMSG_SET_TARGET_OBSOLETE", STATUS_LOGGEDIN, &WorldSession::HandleSetTargetOpcode },
- /*0x13F*/ { "CMSG_UNUSED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x140*/ { "CMSG_UNUSED2", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x141*/ { "CMSG_ATTACKSWING", STATUS_LOGGEDIN, &WorldSession::HandleAttackSwingOpcode },
- /*0x142*/ { "CMSG_ATTACKSTOP", STATUS_LOGGEDIN, &WorldSession::HandleAttackStopOpcode },
- /*0x143*/ { "SMSG_ATTACKSTART", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x144*/ { "SMSG_ATTACKSTOP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x145*/ { "SMSG_ATTACKSWING_NOTINRANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x146*/ { "SMSG_ATTACKSWING_BADFACING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x147*/ { "SMSG_ATTACKSWING_NOTSTANDING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x148*/ { "SMSG_ATTACKSWING_DEADTARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x149*/ { "SMSG_ATTACKSWING_CANT_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x14A*/ { "SMSG_ATTACKERSTATEUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x14B*/ { "SMSG_VICTIMSTATEUPDATE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x14C*/ { "SMSG_DAMAGE_DONE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x14D*/ { "SMSG_DAMAGE_TAKEN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x14E*/ { "SMSG_CANCEL_COMBAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x14F*/ { "SMSG_PLAYER_COMBAT_XP_GAIN_OBSOLETE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x150*/ { "SMSG_SPELLHEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x151*/ { "SMSG_SPELLENERGIZELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x152*/ { "CMSG_SHEATHE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x153*/ { "CMSG_SAVE_PLAYER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x154*/ { "CMSG_SETDEATHBINDPOINT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x155*/ { "SMSG_BINDPOINTUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x156*/ { "CMSG_GETDEATHBINDZONE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x157*/ { "SMSG_BINDZONEREPLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x158*/ { "SMSG_PLAYERBOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x159*/ { "SMSG_CLIENT_CONTROL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x15A*/ { "CMSG_REPOP_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleRepopRequestOpcode },
- /*0x15B*/ { "SMSG_RESURRECT_REQUEST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x15C*/ { "CMSG_RESURRECT_RESPONSE", STATUS_LOGGEDIN, &WorldSession::HandleResurrectResponseOpcode },
- /*0x15D*/ { "CMSG_LOOT", STATUS_LOGGEDIN, &WorldSession::HandleLootOpcode },
- /*0x15E*/ { "CMSG_LOOT_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleLootMoneyOpcode },
- /*0x15F*/ { "CMSG_LOOT_RELEASE", STATUS_LOGGEDIN, &WorldSession::HandleLootReleaseOpcode },
- /*0x160*/ { "SMSG_LOOT_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x161*/ { "SMSG_LOOT_RELEASE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x162*/ { "SMSG_LOOT_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x163*/ { "SMSG_LOOT_MONEY_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x164*/ { "SMSG_LOOT_ITEM_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x165*/ { "SMSG_LOOT_CLEAR_MONEY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x166*/ { "SMSG_ITEM_PUSH_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x167*/ { "SMSG_DUEL_REQUESTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x168*/ { "SMSG_DUEL_OUTOFBOUNDS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x169*/ { "SMSG_DUEL_INBOUNDS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x16A*/ { "SMSG_DUEL_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x16B*/ { "SMSG_DUEL_WINNER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x16C*/ { "CMSG_DUEL_ACCEPTED", STATUS_LOGGEDIN, &WorldSession::HandleDuelAcceptedOpcode },
- /*0x16D*/ { "CMSG_DUEL_CANCELLED", STATUS_LOGGEDIN, &WorldSession::HandleDuelCancelledOpcode },
- /*0x16E*/ { "SMSG_MOUNTRESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x16F*/ { "SMSG_DISMOUNTRESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x170*/ { "SMSG_PUREMOUNT_CANCELLED_OBSOLETE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x171*/ { "CMSG_MOUNTSPECIAL_ANIM", STATUS_LOGGEDIN, &WorldSession::HandleMountSpecialAnimOpcode },
- /*0x172*/ { "SMSG_MOUNTSPECIAL_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x173*/ { "SMSG_PET_TAME_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x174*/ { "CMSG_PET_SET_ACTION", STATUS_LOGGEDIN, &WorldSession::HandlePetSetAction },
- /*0x175*/ { "CMSG_PET_ACTION", STATUS_LOGGEDIN, &WorldSession::HandlePetAction },
- /*0x176*/ { "CMSG_PET_ABANDON", STATUS_LOGGEDIN, &WorldSession::HandlePetAbandon },
- /*0x177*/ { "CMSG_PET_RENAME", STATUS_LOGGEDIN, &WorldSession::HandlePetRename },
- /*0x178*/ { "SMSG_PET_NAME_INVALID", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x179*/ { "SMSG_PET_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x17A*/ { "SMSG_PET_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x17B*/ { "CMSG_GOSSIP_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleGossipHelloOpcode },
- /*0x17C*/ { "CMSG_GOSSIP_SELECT_OPTION", STATUS_LOGGEDIN, &WorldSession::HandleGossipSelectOptionOpcode },
- /*0x17D*/ { "SMSG_GOSSIP_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x17E*/ { "SMSG_GOSSIP_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x17F*/ { "CMSG_NPC_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleNpcTextQueryOpcode },
- /*0x180*/ { "SMSG_NPC_TEXT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x181*/ { "SMSG_NPC_WONT_TALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x182*/ { "CMSG_QUESTGIVER_STATUS_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverStatusQueryOpcode},
- /*0x183*/ { "SMSG_QUESTGIVER_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x184*/ { "CMSG_QUESTGIVER_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverHelloOpcode },
- /*0x185*/ { "SMSG_QUESTGIVER_QUEST_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x186*/ { "CMSG_QUESTGIVER_QUERY_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverQuestQueryOpcode},
- /*0x187*/ { "CMSG_QUESTGIVER_QUEST_AUTOLAUNCH", STATUS_LOGGEDIN, &WorldSession::HandleQuestAutoLaunch },
- /*0x188*/ { "SMSG_QUESTGIVER_QUEST_DETAILS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x189*/ { "CMSG_QUESTGIVER_ACCEPT_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverAcceptQuestOpcode},
- /*0x18A*/ { "CMSG_QUESTGIVER_COMPLETE_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestComplete },
- /*0x18B*/ { "SMSG_QUESTGIVER_REQUEST_ITEMS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x18C*/ { "CMSG_QUESTGIVER_REQUEST_REWARD", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverRequestRewardOpcode},
- /*0x18D*/ { "SMSG_QUESTGIVER_OFFER_REWARD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x18E*/ { "CMSG_QUESTGIVER_CHOOSE_REWARD", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverChooseRewardOpcode},
- /*0x18F*/ { "SMSG_QUESTGIVER_QUEST_INVALID", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x190*/ { "CMSG_QUESTGIVER_CANCEL", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverCancel },
- /*0x191*/ { "SMSG_QUESTGIVER_QUEST_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x192*/ { "SMSG_QUESTGIVER_QUEST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x193*/ { "CMSG_QUESTLOG_SWAP_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestLogSwapQuest },
- /*0x194*/ { "CMSG_QUESTLOG_REMOVE_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestLogRemoveQuest },
- /*0x195*/ { "SMSG_QUESTLOG_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x196*/ { "SMSG_QUESTUPDATE_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x197*/ { "SMSG_QUESTUPDATE_FAILEDTIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x198*/ { "SMSG_QUESTUPDATE_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x199*/ { "SMSG_QUESTUPDATE_ADD_KILL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x19A*/ { "SMSG_QUESTUPDATE_ADD_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x19B*/ { "CMSG_QUEST_CONFIRM_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleQuestConfirmAccept },
- /*0x19C*/ { "SMSG_QUEST_CONFIRM_ACCEPT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x19D*/ { "CMSG_PUSHQUESTTOPARTY", STATUS_LOGGEDIN, &WorldSession::HandleQuestPushToParty },
- /*0x19E*/ { "CMSG_LIST_INVENTORY", STATUS_LOGGEDIN, &WorldSession::HandleListInventoryOpcode },
- /*0x19F*/ { "SMSG_LIST_INVENTORY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1A0*/ { "CMSG_SELL_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSellItemOpcode },
- /*0x1A1*/ { "SMSG_SELL_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1A2*/ { "CMSG_BUY_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuyItemOpcode },
- /*0x1A3*/ { "CMSG_BUY_ITEM_IN_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyItemInSlotOpcode },
- /*0x1A4*/ { "SMSG_BUY_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1A5*/ { "SMSG_BUY_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1A6*/ { "CMSG_TAXICLEARALLNODES", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1A7*/ { "CMSG_TAXIENABLEALLNODES", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1A8*/ { "CMSG_TAXISHOWNODES", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1A9*/ { "SMSG_SHOWTAXINODES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1AA*/ { "CMSG_TAXINODE_STATUS_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleTaxiNodeStatusQueryOpcode },
- /*0x1AB*/ { "SMSG_TAXINODE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1AC*/ { "CMSG_TAXIQUERYAVAILABLENODES", STATUS_LOGGEDIN, &WorldSession::HandleTaxiQueryAvailableNodesOpcode},
- /*0x1AD*/ { "CMSG_ACTIVATETAXI", STATUS_LOGGEDIN, &WorldSession::HandleActivateTaxiOpcode },
- /*0x1AE*/ { "SMSG_ACTIVATETAXIREPLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1AF*/ { "SMSG_NEW_TAXI_PATH", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1B0*/ { "CMSG_TRAINER_LIST", STATUS_LOGGEDIN, &WorldSession::HandleTrainerListOpcode },
- /*0x1B1*/ { "SMSG_TRAINER_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1B2*/ { "CMSG_TRAINER_BUY_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleTrainerBuySpellOpcode },
- /*0x1B3*/ { "SMSG_TRAINER_BUY_SUCCEEDED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1B4*/ { "SMSG_TRAINER_BUY_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1B5*/ { "CMSG_BINDER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleBinderActivateOpcode },
- /*0x1B6*/ { "SMSG_PLAYERBINDERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1B7*/ { "CMSG_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleBankerActivateOpcode },
- /*0x1B8*/ { "SMSG_SHOW_BANK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1B9*/ { "CMSG_BUY_BANK_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyBankSlotOpcode },
- /*0x1BA*/ { "SMSG_BUY_BANK_SLOT_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1BB*/ { "CMSG_PETITION_SHOWLIST", STATUS_LOGGEDIN, &WorldSession::HandlePetitionShowListOpcode },
- /*0x1BC*/ { "SMSG_PETITION_SHOWLIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1BD*/ { "CMSG_PETITION_BUY", STATUS_LOGGEDIN, &WorldSession::HandlePetitionBuyOpcode },
- /*0x1BE*/ { "CMSG_PETITION_SHOW_SIGNATURES", STATUS_LOGGEDIN, &WorldSession::HandlePetitionShowSignOpcode },
- /*0x1BF*/ { "SMSG_PETITION_SHOW_SIGNATURES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1C0*/ { "CMSG_PETITION_SIGN", STATUS_LOGGEDIN, &WorldSession::HandlePetitionSignOpcode },
- /*0x1C1*/ { "SMSG_PETITION_SIGN_RESULTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1C2*/ { "MSG_PETITION_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandlePetitionDeclineOpcode },
- /*0x1C3*/ { "CMSG_OFFER_PETITION", STATUS_LOGGEDIN, &WorldSession::HandleOfferPetitionOpcode },
- /*0x1C4*/ { "CMSG_TURN_IN_PETITION", STATUS_LOGGEDIN, &WorldSession::HandleTurnInPetitionOpcode },
- /*0x1C5*/ { "SMSG_TURN_IN_PETITION_RESULTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1C6*/ { "CMSG_PETITION_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePetitionQueryOpcode },
- /*0x1C7*/ { "SMSG_PETITION_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1C8*/ { "SMSG_FISH_NOT_HOOKED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1C9*/ { "SMSG_FISH_ESCAPED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1CA*/ { "CMSG_BUG", STATUS_LOGGEDIN, &WorldSession::HandleBugOpcode },
- /*0x1CB*/ { "SMSG_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1CC*/ { "CMSG_PLAYED_TIME", STATUS_LOGGEDIN, &WorldSession::HandlePlayedTime },
- /*0x1CD*/ { "SMSG_PLAYED_TIME", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1CE*/ { "CMSG_QUERY_TIME", STATUS_LOGGEDIN, &WorldSession::HandleQueryTimeOpcode },
- /*0x1CF*/ { "SMSG_QUERY_TIME_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1D0*/ { "SMSG_LOG_XPGAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1D1*/ { "SMSG_AURACASTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1D2*/ { "CMSG_RECLAIM_CORPSE", STATUS_LOGGEDIN, &WorldSession::HandleCorpseReclaimOpcode },
- /*0x1D3*/ { "CMSG_WRAP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleWrapItemOpcode },
- /*0x1D4*/ { "SMSG_LEVELUP_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1D5*/ { "MSG_MINIMAP_PING", STATUS_LOGGEDIN, &WorldSession::HandleMinimapPingOpcode },
- /*0x1D6*/ { "SMSG_RESISTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1D7*/ { "SMSG_ENCHANTMENTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1D8*/ { "CMSG_SET_SKILL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1D9*/ { "SMSG_START_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1DA*/ { "SMSG_PAUSE_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1DB*/ { "SMSG_STOP_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1DC*/ { "CMSG_PING", STATUS_NEVER, &WorldSession::Handle_EarlyProccess },
- /*0x1DD*/ { "SMSG_PONG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1DE*/ { "SMSG_CLEAR_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1DF*/ { "SMSG_GAMEOBJECT_PAGETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1E0*/ { "CMSG_SETSHEATHED", STATUS_LOGGEDIN, &WorldSession::HandleSetSheathedOpcode },
- /*0x1E1*/ { "SMSG_COOLDOWN_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1E2*/ { "SMSG_SPELL_DELAYED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1E3*/ { "CMSG_PLAYER_MACRO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1E4*/ { "SMSG_PLAYER_MACRO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1E5*/ { "CMSG_GHOST", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1E6*/ { "CMSG_GM_INVIS", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1E7*/ { "SMSG_INVALID_PROMOTION_CODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1E8*/ { "MSG_GM_BIND_OTHER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1E9*/ { "MSG_GM_SUMMON", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1EA*/ { "SMSG_ITEM_TIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1EB*/ { "SMSG_ITEM_ENCHANT_TIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1EC*/ { "SMSG_AUTH_CHALLENGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1ED*/ { "CMSG_AUTH_SESSION", STATUS_NEVER, &WorldSession::Handle_EarlyProccess },
- /*0x1EE*/ { "SMSG_AUTH_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1EF*/ { "MSG_GM_SHOWLABEL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1F0*/ { "CMSG_PET_CAST_SPELL", STATUS_LOGGEDIN, &WorldSession::HandlePetCastSpellOpcode },
- /*0x1F1*/ { "MSG_SAVE_GUILD_EMBLEM", STATUS_LOGGEDIN, &WorldSession::HandleGuildSaveEmblemOpcode },
- /*0x1F2*/ { "MSG_TABARDVENDOR_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleTabardVendorActivateOpcode},
- /*0x1F3*/ { "SMSG_PLAY_SPELL_VISUAL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1F4*/ { "CMSG_ZONEUPDATE", STATUS_LOGGEDIN, &WorldSession::HandleZoneUpdateOpcode },
- /*0x1F5*/ { "SMSG_PARTYKILLLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1F6*/ { "SMSG_COMPRESSED_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1F7*/ { "SMSG_PLAY_SPELL_IMPACT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1F8*/ { "SMSG_EXPLORATION_EXPERIENCE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1F9*/ { "CMSG_GM_SET_SECURITY_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1FA*/ { "CMSG_GM_NUKE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1FB*/ { "MSG_RANDOM_ROLL", STATUS_LOGGEDIN, &WorldSession::HandleRandomRollOpcode },
- /*0x1FC*/ { "SMSG_ENVIRONMENTALDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1FD*/ { "CMSG_RWHOIS_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x1FE*/ { "SMSG_RWHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x1FF*/ { "MSG_LOOKING_FOR_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleLookingForGroup },
- /*0x200*/ { "CMSG_SET_LOOKING_FOR_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleSetLfgOpcode },
- /*0x201*/ { "CMSG_UNLEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x202*/ { "CMSG_UNLEARN_SKILL", STATUS_LOGGEDIN, &WorldSession::HandleUnlearnSkillOpcode },
- /*0x203*/ { "SMSG_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x204*/ { "CMSG_DECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x205*/ { "CMSG_GMTICKET_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketCreateOpcode },
- /*0x206*/ { "SMSG_GMTICKET_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x207*/ { "CMSG_GMTICKET_UPDATETEXT", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketUpdateOpcode },
- /*0x208*/ { "SMSG_GMTICKET_UPDATETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x209*/ { "SMSG_ACCOUNT_DATA_TIMES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x20A*/ { "CMSG_REQUEST_ACCOUNT_DATA", STATUS_LOGGEDIN, &WorldSession::HandleRequestAccountData },
- /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_LOGGEDIN, &WorldSession::HandleUpdateAccountData },
- /*0x20C*/ { "SMSG_UPDATE_ACCOUNT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x20D*/ { "SMSG_CLEAR_FAR_SIGHT_IMMEDIATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x20E*/ { "SMSG_POWERGAINLOG_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x20F*/ { "CMSG_GM_TEACH", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x210*/ { "CMSG_GM_CREATE_ITEM_TARGET", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x211*/ { "CMSG_GMTICKET_GETTICKET", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketGetTicketOpcode },
- /*0x212*/ { "SMSG_GMTICKET_GETTICKET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x213*/ { "CMSG_UNLEARN_TALENTS", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x214*/ { "SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x215*/ { "SMSG_GAMEOBJECT_DESPAWN_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x216*/ { "MSG_CORPSE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCorpseQueryOpcode },
- /*0x217*/ { "CMSG_GMTICKET_DELETETICKET", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketDeleteOpcode },
- /*0x218*/ { "SMSG_GMTICKET_DELETETICKET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x219*/ { "SMSG_CHAT_WRONG_FACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x21A*/ { "CMSG_GMTICKET_SYSTEMSTATUS", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketSystemStatusOpcode},
- /*0x21B*/ { "SMSG_GMTICKET_SYSTEMSTATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x21C*/ { "CMSG_SPIRIT_HEALER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleSpiritHealerActivateOpcode},
- /*0x21D*/ { "CMSG_SET_STAT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x21E*/ { "SMSG_SET_REST_START", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x21F*/ { "CMSG_SKILL_BUY_STEP", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x220*/ { "CMSG_SKILL_BUY_RANK", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x221*/ { "CMSG_XP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x222*/ { "SMSG_SPIRIT_HEALER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x223*/ { "CMSG_CHARACTER_POINT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x224*/ { "SMSG_GOSSIP_POI", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x225*/ { "CMSG_CHAT_IGNORED", STATUS_LOGGEDIN, &WorldSession::HandleChatIgnoredOpcode },
- /*0x226*/ { "CMSG_GM_VISION", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x227*/ { "CMSG_SERVER_COMMAND", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x228*/ { "CMSG_GM_SILENCE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x229*/ { "CMSG_GM_REVEALTO", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x22A*/ { "CMSG_GM_RESURRECT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x22B*/ { "CMSG_GM_SUMMONMOB", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x22C*/ { "CMSG_GM_MOVECORPSE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x22D*/ { "CMSG_GM_FREEZE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x22E*/ { "CMSG_GM_UBERINVIS", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x22F*/ { "CMSG_GM_REQUEST_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x230*/ { "SMSG_GM_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x231*/ { "CMSG_GUILD_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildRankOpcode },
- /*0x232*/ { "CMSG_GUILD_ADD_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildAddRankOpcode },
- /*0x233*/ { "CMSG_GUILD_DEL_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildDelRankOpcode },
- /*0x234*/ { "CMSG_GUILD_SET_PUBLIC_NOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildSetPublicNoteOpcode },
- /*0x235*/ { "CMSG_GUILD_SET_OFFICER_NOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildSetOfficerNoteOpcode },
- /*0x236*/ { "SMSG_LOGIN_VERIFY_WORLD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x237*/ { "CMSG_CLEAR_EXPLORATION", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x238*/ { "CMSG_SEND_MAIL", STATUS_LOGGEDIN, &WorldSession::HandleSendMail },
- /*0x239*/ { "SMSG_SEND_MAIL_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x23A*/ { "CMSG_GET_MAIL_LIST", STATUS_LOGGEDIN, &WorldSession::HandleGetMail },
- /*0x23B*/ { "SMSG_MAIL_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x23C*/ { "CMSG_BATTLEFIELD_LIST", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundListOpcode },
- /*0x23D*/ { "SMSG_BATTLEFIELD_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x23E*/ { "CMSG_BATTLEFIELD_JOIN", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x23F*/ { "SMSG_BATTLEFIELD_WIN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x240*/ { "SMSG_BATTLEFIELD_LOSE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x241*/ { "CMSG_TAXICLEARNODE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x242*/ { "CMSG_TAXIENABLENODE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x243*/ { "CMSG_ITEM_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleItemTextQuery },
- /*0x244*/ { "SMSG_ITEM_TEXT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x245*/ { "CMSG_MAIL_TAKE_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleTakeMoney },
- /*0x246*/ { "CMSG_MAIL_TAKE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleTakeItem },
- /*0x247*/ { "CMSG_MAIL_MARK_AS_READ", STATUS_LOGGEDIN, &WorldSession::HandleMarkAsRead },
- /*0x248*/ { "CMSG_MAIL_RETURN_TO_SENDER", STATUS_LOGGEDIN, &WorldSession::HandleReturnToSender },
- /*0x249*/ { "CMSG_MAIL_DELETE", STATUS_LOGGEDIN, &WorldSession::HandleMailDelete },
- /*0x24A*/ { "CMSG_MAIL_CREATE_TEXT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleMailCreateTextItem },
- /*0x24B*/ { "SMSG_SPELLLOGMISS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x24C*/ { "SMSG_SPELLLOGEXECUTE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x24D*/ { "SMSG_DEBUGAURAPROC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x24E*/ { "SMSG_PERIODICAURALOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x24F*/ { "SMSG_SPELLDAMAGESHIELD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x250*/ { "SMSG_SPELLNONMELEEDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x251*/ { "CMSG_LEARN_TALENT", STATUS_LOGGEDIN, &WorldSession::HandleLearnTalentOpcode },
- /*0x252*/ { "SMSG_RESURRECT_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x253*/ { "CMSG_TOGGLE_PVP", STATUS_LOGGEDIN, &WorldSession::HandleTogglePvP },
- /*0x254*/ { "SMSG_ZONE_UNDER_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x255*/ { "MSG_AUCTION_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleAuctionHelloOpcode },
- /*0x256*/ { "CMSG_AUCTION_SELL_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAuctionSellItem },
- /*0x257*/ { "CMSG_AUCTION_REMOVE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAuctionRemoveItem },
- /*0x258*/ { "CMSG_AUCTION_LIST_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListItems },
- /*0x259*/ { "CMSG_AUCTION_LIST_OWNER_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListOwnerItems },
- /*0x25A*/ { "CMSG_AUCTION_PLACE_BID", STATUS_LOGGEDIN, &WorldSession::HandleAuctionPlaceBid },
- /*0x25B*/ { "SMSG_AUCTION_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x25C*/ { "SMSG_AUCTION_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x25D*/ { "SMSG_AUCTION_OWNER_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x25E*/ { "SMSG_AUCTION_BIDDER_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x25F*/ { "SMSG_AUCTION_OWNER_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x260*/ { "SMSG_PROCRESIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x261*/ { "SMSG_STANDSTATE_CHANGE_FAILURE_OBSOLETE",STATUS_NEVER,&WorldSession::Handle_ServerSide },
- /*0x262*/ { "SMSG_DISPEL_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x263*/ { "SMSG_SPELLORDAMAGE_IMMUNE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x264*/ { "CMSG_AUCTION_LIST_BIDDER_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListBidderItems },
- /*0x265*/ { "SMSG_AUCTION_BIDDER_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x266*/ { "SMSG_SET_FLAT_SPELL_MODIFIER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x267*/ { "SMSG_SET_PCT_SPELL_MODIFIER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x268*/ { "CMSG_SET_AMMO", STATUS_LOGGEDIN, &WorldSession::HandleSetAmmoOpcode },
- /*0x269*/ { "SMSG_CORPSE_RECLAIM_DELAY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x26A*/ { "CMSG_SET_ACTIVE_MOVER", STATUS_LOGGEDIN, &WorldSession::HandleSetActiveMoverOpcode },
- /*0x26B*/ { "CMSG_PET_CANCEL_AURA", STATUS_LOGGEDIN, &WorldSession::HandlePetCancelAuraOpcode },
- /*0x26C*/ { "CMSG_PLAYER_AI_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x26D*/ { "CMSG_CANCEL_AUTO_REPEAT_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleCancelAutoRepeatSpellOpcode},
- /*0x26E*/ { "MSG_GM_ACCOUNT_ONLINE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x26F*/ { "MSG_LIST_STABLED_PETS", STATUS_LOGGEDIN, &WorldSession::HandleListStabledPetsOpcode },
- /*0x270*/ { "CMSG_STABLE_PET", STATUS_LOGGEDIN, &WorldSession::HandleStablePet },
- /*0x271*/ { "CMSG_UNSTABLE_PET", STATUS_LOGGEDIN, &WorldSession::HandleUnstablePet },
- /*0x272*/ { "CMSG_BUY_STABLE_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyStableSlot },
- /*0x273*/ { "SMSG_STABLE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x274*/ { "CMSG_STABLE_REVIVE_PET", STATUS_LOGGEDIN, &WorldSession::HandleStableRevivePet },
- /*0x275*/ { "CMSG_STABLE_SWAP_PET", STATUS_LOGGEDIN, &WorldSession::HandleStableSwapPet },
- /*0x276*/ { "MSG_QUEST_PUSH_RESULT", STATUS_LOGGEDIN, &WorldSession::HandleQuestPushResult },
- /*0x277*/ { "SMSG_PLAY_MUSIC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x278*/ { "SMSG_PLAY_OBJECT_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x279*/ { "CMSG_REQUEST_PET_INFO", STATUS_LOGGEDIN, &WorldSession::HandleRequestPetInfoOpcode },
- /*0x27A*/ { "CMSG_FAR_SIGHT", STATUS_LOGGEDIN, &WorldSession::HandleFarSightOpcode },
- /*0x27B*/ { "SMSG_SPELLDISPELLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x27C*/ { "SMSG_DAMAGE_CALC_LOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x27D*/ { "CMSG_ENABLE_DAMAGE_LOG", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x27E*/ { "CMSG_GROUP_CHANGE_SUB_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleGroupChangeSubGroupOpcode },
- /*0x27F*/ { "CMSG_REQUEST_PARTY_MEMBER_STATS", STATUS_LOGGEDIN, &WorldSession::HandleRequestPartyMemberStatsOpcode},
- /*0x280*/ { "CMSG_GROUP_SWAP_SUB_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x281*/ { "CMSG_RESET_FACTION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x282*/ { "CMSG_AUTOSTORE_BANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBankItemOpcode },
- /*0x283*/ { "CMSG_AUTOBANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoBankItemOpcode },
- /*0x284*/ { "MSG_QUERY_NEXT_MAIL_TIME", STATUS_LOGGEDIN, &WorldSession::HandleMsgQueryNextMailtime },
- /*0x285*/ { "SMSG_RECEIVED_MAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x286*/ { "SMSG_RAID_GROUP_ONLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x287*/ { "CMSG_SET_DURABILITY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x288*/ { "CMSG_SET_PVP_RANK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x289*/ { "CMSG_ADD_PVP_MEDAL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x28A*/ { "CMSG_DEL_PVP_MEDAL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x28B*/ { "CMSG_SET_PVP_TITLE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x28C*/ { "SMSG_PVP_CREDIT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x28D*/ { "SMSG_AUCTION_REMOVED_NOTIFICATION",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x28E*/ { "CMSG_GROUP_RAID_CONVERT", STATUS_LOGGEDIN, &WorldSession::HandleRaidConvertOpcode },
- /*0x28F*/ { "CMSG_GROUP_ASSISTANT_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupAssistantOpcode },
- /*0x290*/ { "CMSG_BUYBACK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuybackItem },
- /*0x291*/ { "SMSG_SERVER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x292*/ { "CMSG_MEETINGSTONE_JOIN", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x293*/ { "CMSG_MEETINGSTONE_LEAVE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x294*/ { "CMSG_MEETINGSTONE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x295*/ { "SMSG_MEETINGSTONE_SETQUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x296*/ { "CMSG_MEETINGSTONE_INFO", STATUS_LOGGEDIN, &WorldSession::HandleMeetingStoneInfo },
- /*0x297*/ { "SMSG_MEETINGSTONE_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x298*/ { "SMSG_MEETINGSTONE_IN_PROGRESS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x299*/ { "SMSG_MEETINGSTONE_MEMBER_ADDED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x29A*/ { "CMSG_GMTICKETSYSTEM_TOGGLE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x29B*/ { "CMSG_CANCEL_GROWTH_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelGrowthAuraOpcode },
- /*0x29C*/ { "SMSG_CANCEL_AUTO_REPEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x29D*/ { "SMSG_STANDSTATE_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x29E*/ { "SMSG_LOOT_ALL_PASSED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x29F*/ { "SMSG_LOOT_ROLL_WON", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2A0*/ { "CMSG_LOOT_ROLL", STATUS_LOGGEDIN, &WorldSession::HandleLootRoll },
- /*0x2A1*/ { "SMSG_LOOT_START_ROLL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2A2*/ { "SMSG_LOOT_ROLL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2A3*/ { "CMSG_LOOT_MASTER_GIVE", STATUS_LOGGEDIN, &WorldSession::HandleLootMasterGiveOpcode },
- /*0x2A4*/ { "SMSG_LOOT_MASTER_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2A5*/ { "SMSG_SET_FORCED_REACTIONS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2A6*/ { "SMSG_SPELL_FAILED_OTHER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2A7*/ { "SMSG_GAMEOBJECT_RESET_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2A8*/ { "CMSG_REPAIR_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleRepairItemOpcode },
- /*0x2A9*/ { "SMSG_CHAT_PLAYER_NOT_FOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2AA*/ { "MSG_TALENT_WIPE_CONFIRM", STATUS_LOGGEDIN, &WorldSession::HandleTalentWipeOpcode },
- /*0x2AB*/ { "SMSG_SUMMON_REQUEST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2AC*/ { "CMSG_SUMMON_RESPONSE", STATUS_LOGGEDIN, &WorldSession::HandleSummonResponseOpcode },
- /*0x2AD*/ { "MSG_MOVE_TOGGLE_GRAVITY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2AE*/ { "SMSG_MONSTER_MOVE_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2AF*/ { "SMSG_PET_BROKEN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2B0*/ { "MSG_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2B1*/ { "MSG_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2B2*/ { "CMSG_SERVER_BROADCAST", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2B3*/ { "CMSG_SELF_RES", STATUS_LOGGEDIN, &WorldSession::HandleSelfResOpcode },
- /*0x2B4*/ { "SMSG_FEIGN_DEATH_RESISTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2B5*/ { "CMSG_RUN_SCRIPT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2B6*/ { "SMSG_SCRIPT_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2B7*/ { "SMSG_DUEL_COUNTDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2B8*/ { "SMSG_AREA_TRIGGER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2B9*/ { "CMSG_TOGGLE_HELM", STATUS_LOGGEDIN, &WorldSession::HandleToggleHelmOpcode },
- /*0x2BA*/ { "CMSG_TOGGLE_CLOAK", STATUS_LOGGEDIN, &WorldSession::HandleToggleCloakOpcode },
- /*0x2BB*/ { "SMSG_MEETINGSTONE_JOINFAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2BC*/ { "SMSG_PLAYER_SKINNED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2BD*/ { "SMSG_DURABILITY_DAMAGE_DEATH", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2BE*/ { "CMSG_SET_EXPLORATION", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2BF*/ { "CMSG_SET_ACTIONBAR_TOGGLES", STATUS_AUTHED, &WorldSession::HandleSetActionBar },
- /*0x2C0*/ { "UMSG_DELETE_GUILD_CHARTER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2C1*/ { "MSG_PETITION_RENAME", STATUS_LOGGEDIN, &WorldSession::HandlePetitionRenameOpcode },
- /*0x2C2*/ { "SMSG_INIT_WORLD_STATES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2C3*/ { "SMSG_UPDATE_WORLD_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2C4*/ { "CMSG_ITEM_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleItemNameQueryOpcode },
- /*0x2C5*/ { "SMSG_ITEM_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2C6*/ { "SMSG_PET_ACTION_FEEDBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2C7*/ { "CMSG_CHAR_RENAME", STATUS_AUTHED, &WorldSession::HandleChangePlayerNameOpcode },
- /*0x2C8*/ { "SMSG_CHAR_RENAME", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2C9*/ { "CMSG_MOVE_SPLINE_DONE", STATUS_LOGGEDIN, &WorldSession::HandleTaxiNextDestinationOpcode },
- /*0x2CA*/ { "CMSG_MOVE_FALL_RESET", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x2CB*/ { "SMSG_INSTANCE_SAVE_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2CC*/ { "SMSG_RAID_INSTANCE_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2CD*/ { "CMSG_REQUEST_RAID_INFO", STATUS_LOGGEDIN, &WorldSession::HandleRequestRaidInfoOpcode },
- /*0x2CE*/ { "CMSG_MOVE_TIME_SKIPPED", STATUS_LOGGEDIN, &WorldSession::HandleMoveTimeSkippedOpcode },
- /*0x2CF*/ { "CMSG_MOVE_FEATHER_FALL_ACK", STATUS_LOGGEDIN, &WorldSession::HandleFeatherFallAck },
- /*0x2D0*/ { "CMSG_MOVE_WATER_WALK_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveWaterWalkAck },
- /*0x2D1*/ { "CMSG_MOVE_NOT_ACTIVE_MOVER", STATUS_LOGGEDIN, &WorldSession::HandleNotActiveMoverOpcode },
- /*0x2D2*/ { "SMSG_PLAY_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2D3*/ { "CMSG_BATTLEFIELD_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleBattlefieldStatusOpcode },
- /*0x2D4*/ { "SMSG_BATTLEFIELD_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2D5*/ { "CMSG_BATTLEFIELD_PORT", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPlayerPortOpcode},
- /*0x2D6*/ { "MSG_INSPECT_HONOR_STATS", STATUS_LOGGEDIN, &WorldSession::HandleInspectHonorStatsOpcode },
- /*0x2D7*/ { "CMSG_BATTLEMASTER_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundHelloOpcode },
- /*0x2D8*/ { "CMSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2D9*/ { "CMSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2DA*/ { "SMSG_FORCE_WALK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2DB*/ { "CMSG_FORCE_WALK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
- /*0x2DC*/ { "SMSG_FORCE_SWIM_BACK_SPEED_CHANGE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2DD*/ { "CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK",STATUS_LOGGEDIN,&WorldSession::HandleForceSpeedChangeAck },
- /*0x2DE*/ { "SMSG_FORCE_TURN_RATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2DF*/ { "CMSG_FORCE_TURN_RATE_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
- /*0x2E0*/ { "MSG_PVP_LOG_DATA", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPVPlogdataOpcode},
- /*0x2E1*/ { "CMSG_LEAVE_BATTLEFIELD", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundLeaveOpcode },
- /*0x2E2*/ { "CMSG_AREA_SPIRIT_HEALER_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleAreaSpiritHealerQueryOpcode},
- /*0x2E3*/ { "CMSG_AREA_SPIRIT_HEALER_QUEUE", STATUS_LOGGEDIN, &WorldSession::HandleAreaSpiritHealerQueueOpcode},
- /*0x2E4*/ { "SMSG_AREA_SPIRIT_HEALER_TIME", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2E5*/ { "CMSG_GM_UNTEACH", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2E6*/ { "SMSG_WARDEN_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2E7*/ { "CMSG_WARDEN_DATA", STATUS_LOGGEDIN, &WorldSession::HandleWardenDataOpcode },
- /*0x2E8*/ { "SMSG_GROUP_JOINED_BATTLEGROUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2E9*/ { "MSG_BATTLEGROUND_PLAYER_POSITIONS",STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPlayerPositionsOpcode},
- /*0x2EA*/ { "CMSG_PET_STOP_ATTACK", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2EB*/ { "SMSG_BINDER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2EC*/ { "SMSG_BATTLEGROUND_PLAYER_JOINED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2ED*/ { "SMSG_BATTLEGROUND_PLAYER_LEFT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2EE*/ { "CMSG_BATTLEMASTER_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundJoinOpcode },
- /*0x2EF*/ { "SMSG_ADDON_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2F0*/ { "CMSG_PET_UNLEARN", STATUS_LOGGEDIN, &WorldSession::HandlePetUnlearnOpcode },
- /*0x2F1*/ { "SMSG_PET_UNLEARN_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2F2*/ { "SMSG_PARTY_MEMBER_STATS_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2F3*/ { "CMSG_PET_SPELL_AUTOCAST", STATUS_LOGGEDIN, &WorldSession::HandlePetSpellAutocastOpcode },
- /*0x2F4*/ { "SMSG_WEATHER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2F5*/ { "SMSG_PLAY_TIME_WARNING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2F6*/ { "SMSG_MINIGAME_SETUP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2F7*/ { "SMSG_MINIGAME_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2F8*/ { "CMSG_MINIGAME_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x2F9*/ { "SMSG_MINIGAME_MOVE_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2FA*/ { "SMSG_RAID_INSTANCE_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2FB*/ { "SMSG_COMPRESSED_MOVES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2FC*/ { "CMSG_GUILD_INFO_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleGuildChangeInfoOpcode },
- /*0x2FD*/ { "SMSG_CHAT_RESTRICTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2FE*/ { "SMSG_SPLINE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x2FF*/ { "SMSG_SPLINE_SET_RUN_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x300*/ { "SMSG_SPLINE_SET_SWIM_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x301*/ { "SMSG_SPLINE_SET_WALK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x302*/ { "SMSG_SPLINE_SET_SWIM_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x303*/ { "SMSG_SPLINE_SET_TURN_RATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x304*/ { "SMSG_SPLINE_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x305*/ { "SMSG_SPLINE_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x306*/ { "SMSG_SPLINE_MOVE_NORMAL_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x307*/ { "SMSG_SPLINE_MOVE_SET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x308*/ { "SMSG_SPLINE_MOVE_UNSET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x309*/ { "SMSG_SPLINE_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x30A*/ { "SMSG_SPLINE_MOVE_LAND_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x30B*/ { "SMSG_SPLINE_MOVE_START_SWIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x30C*/ { "SMSG_SPLINE_MOVE_STOP_SWIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x30D*/ { "SMSG_SPLINE_MOVE_SET_RUN_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x30E*/ { "SMSG_SPLINE_MOVE_SET_WALK_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x30F*/ { "CMSG_GM_NUKE_ACCOUNT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x310*/ { "MSG_GM_DESTROY_CORPSE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x311*/ { "CMSG_GM_DESTROY_ONLINE_CORPSE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x312*/ { "CMSG_ACTIVATETAXIEXPRESS", STATUS_LOGGEDIN, &WorldSession::HandleActivateTaxiFarOpcode },
- /*0x313*/ { "SMSG_SET_FACTION_ATWAR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x314*/ { "SMSG_GAMETIMEBIAS_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x315*/ { "CMSG_DEBUG_ACTIONS_START", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x316*/ { "CMSG_DEBUG_ACTIONS_STOP", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x317*/ { "CMSG_SET_FACTION_INACTIVE", STATUS_LOGGEDIN, &WorldSession::HandleSetWatchedFactionInactiveOpcode},
- /*0x318*/ { "CMSG_SET_WATCHED_FACTION", STATUS_LOGGEDIN, &WorldSession::HandleSetWatchedFactionIndexOpcode},
- /*0x319*/ { "MSG_MOVE_TIME_SKIPPED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x31A*/ { "SMSG_SPLINE_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x31B*/ { "CMSG_SET_EXPLORATION_ALL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x31C*/ { "SMSG_INVALIDATE_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x31D*/ { "CMSG_RESET_INSTANCES", STATUS_LOGGEDIN, &WorldSession::HandleResetInstancesOpcode },
- /*0x31E*/ { "SMSG_INSTANCE_RESET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x31F*/ { "SMSG_INSTANCE_RESET_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x320*/ { "SMSG_UPDATE_LAST_INSTANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x321*/ { "MSG_RAID_TARGET_UPDATE", STATUS_LOGGEDIN, &WorldSession::HandleRaidIconTargetOpcode },
- /*0x322*/ { "MSG_RAID_READY_CHECK", STATUS_LOGGEDIN, &WorldSession::HandleRaidReadyCheckOpcode },
- /*0x323*/ { "CMSG_LUA_USAGE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x324*/ { "SMSG_PET_ACTION_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x325*/ { "SMSG_PET_DISMISS_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x326*/ { "SMSG_GHOSTEE_GONE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x327*/ { "CMSG_GM_UPDATE_TICKET_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x328*/ { "SMSG_GM_TICKET_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x329*/ { "MSG_SET_DUNGEON_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleDungeonDifficultyOpcode },
- /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL },//&WorldSession::HandleGMSurveySubmit
- /*0x32B*/ { "SMSG_UPDATE_INSTANCE_OWNERSHIP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x32C*/ { "CMSG_IGNORE_KNOCKBACK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x32D*/ { "SMSG_CHAT_PLAYER_AMBIGUOUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x32E*/ { "MSG_DELAY_GHOST_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x32F*/ { "SMSG_SPELLINSTAKILLLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x330*/ { "SMSG_SPELL_UPDATE_CHAIN_TARGETS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x331*/ { "CMSG_CHAT_FILTERED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x332*/ { "SMSG_EXPECTED_SPAM_RECORDS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x333*/ { "SMSG_SPELLSTEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x334*/ { "CMSG_LOTTERY_QUERY_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x335*/ { "SMSG_LOTTERY_QUERY_RESULT_OBSOLETE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x336*/ { "CMSG_BUY_LOTTERY_TICKET_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x337*/ { "SMSG_LOTTERY_RESULT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x338*/ { "SMSG_CHARACTER_PROFILE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x339*/ { "SMSG_CHARACTER_PROFILE_REALM_CONNECTED",STATUS_NEVER,&WorldSession::Handle_ServerSide },
- /*0x33A*/ { "SMSG_DEFENSE_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x33B*/ { "SMSG_INSTANCE_DIFFICULTY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x33C*/ { "MSG_GM_RESETINSTANCELIMIT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x33D*/ { "SMSG_MOTD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x33E*/ { "SMSG_MOVE_SET_FLIGHT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x33F*/ { "SMSG_MOVE_UNSET_FLIGHT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x340*/ { "CMSG_MOVE_FLIGHT_ACK_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x341*/ { "MSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x342*/ { "MSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x343*/ { "SMSG_MOVE_SET_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x344*/ { "SMSG_MOVE_UNSET_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x345*/ { "CMSG_MOVE_SET_CAN_FLY_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveFlyModeChangeAckOpcode},
- /*0x346*/ { "CMSG_MOVE_SET_FLY", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x347*/ { "CMSG_SOCKET_GEMS", STATUS_LOGGEDIN, &WorldSession::HandleSocketOpcode },
- /*0x348*/ { "CMSG_ARENA_TEAM_CREATE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x349*/ { "SMSG_ARENA_TEAM_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x34A*/ { "UMSG_UPDATE_ARENA_TEAM_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x34B*/ { "CMSG_ARENA_TEAM_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamQueryOpcode },
- /*0x34C*/ { "SMSG_ARENA_TEAM_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x34D*/ { "CMSG_ARENA_TEAM_ROSTER", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamRosterOpcode },
- /*0x34E*/ { "SMSG_ARENA_TEAM_ROSTER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x34F*/ { "CMSG_ARENA_TEAM_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamAddMemberOpcode },
- /*0x350*/ { "SMSG_ARENA_TEAM_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x351*/ { "CMSG_ARENA_TEAM_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamInviteAcceptOpcode},
- /*0x352*/ { "CMSG_ARENA_TEAM_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamInviteDeclineOpcode},
- /*0x353*/ { "CMSG_ARENA_TEAM_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamLeaveOpcode },
- /*0x354*/ { "CMSG_ARENA_TEAM_REMOVE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamRemoveFromTeamOpcode},
- /*0x355*/ { "CMSG_ARENA_TEAM_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamDisbandOpcode },
- /*0x356*/ { "CMSG_ARENA_TEAM_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamPromoteToCaptainOpcode},
- /*0x357*/ { "SMSG_ARENA_TEAM_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x358*/ { "CMSG_BATTLEMASTER_JOIN_ARENA", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundArenaJoin },
- /*0x359*/ { "MSG_MOVE_START_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x35A*/ { "MSG_MOVE_STOP_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x35B*/ { "SMSG_ARENA_TEAM_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x35C*/ { "CMSG_LFG_SET_AUTOJOIN", STATUS_AUTHED, &WorldSession::HandleLfgAutoJoinOpcode },
- /*0x35D*/ { "CMSG_LFG_CLEAR_AUTOJOIN", STATUS_LOGGEDIN, &WorldSession::HandleLfgCancelAutoJoinOpcode },
- /*0x35E*/ { "CMSG_LFM_SET_AUTOFILL", STATUS_AUTHED, &WorldSession::HandleLfmAutoAddMembersOpcode },
- /*0x35F*/ { "CMSG_LFM_CLEAR_AUTOFILL", STATUS_LOGGEDIN, &WorldSession::HandleLfmCancelAutoAddmembersOpcode},
- /*0x360*/ { "CMSG_ACCEPT_LFG_MATCH", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x361*/ { "CMSG_DECLINE_LFG_MATCH", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x362*/ { "CMSG_CANCEL_PENDING_LFG", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x363*/ { "CMSG_CLEAR_LOOKING_FOR_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleLfgClearOpcode },
- /*0x364*/ { "CMSG_CLEAR_LOOKING_FOR_MORE", STATUS_LOGGEDIN, &WorldSession::HandleLfmSetNoneOpcode },
- /*0x365*/ { "CMSG_SET_LOOKING_FOR_MORE", STATUS_LOGGEDIN, &WorldSession::HandleLfmSetOpcode },
- /*0x366*/ { "CMSG_SET_LFG_COMMENT", STATUS_LOGGEDIN, &WorldSession::HandleLfgSetCommentOpcode },
- /*0x367*/ { "SMSG_LFG_TIMEDOUT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x368*/ { "SMSG_LFG_OTHER_TIMEDOUT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x369*/ { "SMSG_LFG_AUTOJOIN_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x36A*/ { "SMSG_LFG_AUTOJOIN_FAILED_NO_PLAYER",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x36B*/ { "SMSG_LFG_LEADER_IS_LFM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x36C*/ { "SMSG_LFG_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x36D*/ { "SMSG_LFG_UPDATE_LFM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x36E*/ { "SMSG_LFG_UPDATE_LFG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x36F*/ { "SMSG_LFG_UPDATE_QUEUED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x370*/ { "SMSG_LFG_PENDING_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x371*/ { "SMSG_LFG_PENDING_MATCH", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x372*/ { "SMSG_LFG_PENDING_MATCH_DONE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x373*/ { "SMSG_TITLE_EARNED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x374*/ { "CMSG_SET_TITLE", STATUS_LOGGEDIN, &WorldSession::HandleChooseTitleOpcode },
- /*0x375*/ { "CMSG_CANCEL_MOUNT_AURA", STATUS_LOGGEDIN, &WorldSession::HandleDismountOpcode },
- /*0x376*/ { "SMSG_ARENA_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x377*/ { "MSG_INSPECT_ARENA_TEAMS", STATUS_LOGGEDIN, &WorldSession::HandleInspectArenaStatsOpcode },
- /*0x378*/ { "SMSG_DEATH_RELEASE_LOC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x379*/ { "CMSG_CANCEL_TEMP_ENCHANTMENT", STATUS_LOGGEDIN, &WorldSession::HandleCancelTempItemEnchantmentOpcode},
- /*0x37A*/ { "SMSG_FORCED_DEATH_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x37B*/ { "CMSG_CHEAT_SET_HONOR_CURRENCY", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x37C*/ { "CMSG_CHEAT_SET_ARENA_CURRENCY", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x37D*/ { "MSG_MOVE_SET_FLIGHT_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x37E*/ { "MSG_MOVE_SET_FLIGHT_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x37F*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT",STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x380*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x381*/ { "SMSG_FORCE_FLIGHT_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x382*/ { "CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK",STATUS_LOGGEDIN,&WorldSession::HandleForceSpeedChangeAck },
- /*0x383*/ { "SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x384*/ { "CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK",STATUS_LOGGEDIN,&WorldSession::HandleForceSpeedChangeAck },
- /*0x385*/ { "SMSG_SPLINE_SET_FLIGHT_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x386*/ { "SMSG_SPLINE_SET_FLIGHT_BACK_SPEED",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x387*/ { "CMSG_MAELSTROM_INVALIDATE_CACHE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x388*/ { "SMSG_FLIGHT_SPLINE_SYNC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x389*/ { "CMSG_SET_TAXI_BENCHMARK_MODE", STATUS_AUTHED, &WorldSession::HandleSetTaxiBenchmarkOpcode },
- /*0x38A*/ { "SMSG_JOINED_BATTLEGROUND_QUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x38B*/ { "SMSG_REALM_SPLIT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x38C*/ { "CMSG_REALM_SPLIT", STATUS_AUTHED, &WorldSession::HandleRealmStateRequestOpcode },
- /*0x38D*/ { "CMSG_MOVE_CHNG_TRANSPORT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x38E*/ { "MSG_PARTY_ASSIGNMENT", STATUS_LOGGEDIN, &WorldSession::HandleGroupPromoteOpcode },
- /*0x38F*/ { "SMSG_OFFER_PETITION_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x390*/ { "SMSG_TIME_SYNC_REQ", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x391*/ { "CMSG_TIME_SYNC_RESP", STATUS_LOGGEDIN, &WorldSession::HandleAllowMoveAckOpcode },
- /*0x392*/ { "CMSG_SEND_LOCAL_EVENT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x393*/ { "CMSG_SEND_GENERAL_TRIGGER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x394*/ { "CMSG_SEND_COMBAT_TRIGGER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x395*/ { "CMSG_MAELSTROM_GM_SENT_MAIL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x396*/ { "SMSG_RESET_FAILED_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x397*/ { "SMSG_REAL_GROUP_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x398*/ { "SMSG_LFG_DISABLED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x399*/ { "CMSG_ACTIVE_PVP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x39A*/ { "CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x39B*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE",STATUS_NEVER,&WorldSession::Handle_ServerSide },
- /*0x39C*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE",STATUS_NEVER,&WorldSession::Handle_ServerSide},
- /*0x39D*/ { "SMSG_UPDATE_COMBO_POINTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x39E*/ { "SMSG_VOICE_SESSION_ROSTER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x39F*/ { "SMSG_VOICE_SESSION_LEAVE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3A0*/ { "SMSG_VOICE_SESSION_ADJUST_PRIORITY",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3A1*/ { "CMSG_VOICE_SET_TALKER_MUTED_REQUEST",STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3A2*/ { "SMSG_VOICE_SET_TALKER_MUTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3A3*/ { "SMSG_INIT_EXTRA_AURA_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3A4*/ { "SMSG_SET_EXTRA_AURA_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3A5*/ { "SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3A6*/ { "SMSG_CLEAR_EXTRA_AURA_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3A7*/ { "MSG_MOVE_START_DESCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
- /*0x3A8*/ { "CMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3A9*/ { "SMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3AA*/ { "SMSG_SPELL_CHANCE_PROC_LOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3AB*/ { "CMSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3AC*/ { "SMSG_DISMOUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3AD*/ { "MSG_MOVE_UPDATE_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3AE*/ { "MSG_RAID_READY_CHECK_CONFIRM", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3AF*/ { "CMSG_VOICE_SESSION_ENABLE", STATUS_AUTHED, &WorldSession::HandleVoiceSettingsOpcode },
- /*0x3B0*/ { "SMSG_VOICE_PARENTAL_CONTROLS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3B1*/ { "CMSG_GM_WHISPER", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3B2*/ { "SMSG_GM_MESSAGECHAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3B3*/ { "MSG_GM_GEARRATING", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3B4*/ { "CMSG_COMMENTATOR_ENABLE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3B5*/ { "SMSG_COMMENTATOR_STATE_CHANGED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3B6*/ { "CMSG_COMMENTATOR_GET_MAP_INFO", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3B7*/ { "SMSG_COMMENTATOR_MAP_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3B8*/ { "CMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3B9*/ { "SMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3BA*/ { "SMSG_COMMENTATOR_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3BB*/ { "CMSG_COMMENTATOR_ENTER_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3BC*/ { "CMSG_COMMENTATOR_EXIT_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3BD*/ { "CMSG_COMMENTATOR_INSTANCE_COMMAND",STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3BE*/ { "SMSG_CLEAR_TARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3BF*/ { "CMSG_BOT_DETECTED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3C0*/ { "SMSG_CROSSED_INEBRIATION_THRESHOLD",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3C1*/ { "CMSG_CHEAT_PLAYER_LOGIN", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3C2*/ { "CMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3C3*/ { "SMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3C4*/ { "SMSG_KICK_REASON", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3C5*/ { "MSG_RAID_READY_CHECK_FINISHED", STATUS_LOGGEDIN, &WorldSession::HandleRaidReadyCheckFinishOpcode},
- /*0x3C6*/ { "CMSG_COMPLAIN", STATUS_LOGGEDIN, &WorldSession::HandleReportSpamOpcode },
- /*0x3C7*/ { "SMSG_COMPLAIN_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3C8*/ { "SMSG_FEATURE_SYSTEM_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3C9*/ { "CMSG_GM_SHOW_COMPLAINTS", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3CA*/ { "CMSG_GM_UNSQUELCH", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3CB*/ { "CMSG_CHANNEL_SILENCE_VOICE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3CC*/ { "CMSG_CHANNEL_SILENCE_ALL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3CD*/ { "CMSG_CHANNEL_UNSILENCE_VOICE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3CE*/ { "CMSG_CHANNEL_UNSILENCE_ALL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3CF*/ { "CMSG_TARGET_CAST", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3D0*/ { "CMSG_TARGET_SCRIPT_CAST", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3D1*/ { "CMSG_CHANNEL_DISPLAY_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelRosterQuery },
- /*0x3D2*/ { "CMSG_SET_ACTIVE_VOICE_CHANNEL", STATUS_AUTHED, &WorldSession::HandleChannelVoiceChatQuery },
- /*0x3D3*/ { "CMSG_GET_CHANNEL_MEMBER_COUNT", STATUS_LOGGEDIN, &WorldSession::HandleChannelInfoQuery },
- /*0x3D4*/ { "SMSG_CHANNEL_MEMBER_COUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3D5*/ { "CMSG_CHANNEL_VOICE_ON", STATUS_LOGGEDIN, &WorldSession::HandleChannelEnableVoiceOpcode },
- /*0x3D6*/ { "CMSG_CHANNEL_VOICE_OFF", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3D7*/ { "CMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3D8*/ { "SMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3D9*/ { "SMSG_AVAILABLE_VOICE_CHANNEL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3DA*/ { "CMSG_ADD_VOICE_IGNORE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3DB*/ { "CMSG_DEL_VOICE_IGNORE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3DC*/ { "CMSG_PARTY_SILENCE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3DD*/ { "CMSG_PARTY_UNSILENCE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3DE*/ { "MSG_NOTIFY_PARTY_SQUELCH", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3DF*/ { "SMSG_COMSAT_RECONNECT_TRY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3E0*/ { "SMSG_COMSAT_DISCONNECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3E1*/ { "SMSG_COMSAT_CONNECT_FAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3E2*/ { "SMSG_VOICE_CHAT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3E3*/ { "CMSG_REPORT_PVP_AFK", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundReportAFK },
- /*0x3E4*/ { "CMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3E5*/ { "CMSG_GUILD_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankQuery },
- /*0x3E6*/ { "CMSG_GUILD_BANK_QUERY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankTabColon },
- /*0x3E7*/ { "SMSG_GUILD_BANK_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3E8*/ { "CMSG_GUILD_BANK_SWAP_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankDepositItem },
- /*0x3E9*/ { "CMSG_GUILD_BANK_BUY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankBuyTab },
- /*0x3EA*/ { "CMSG_GUILD_BANK_UPDATE_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankModifyTab },
- /*0x3EB*/ { "CMSG_GUILD_BANK_DEPOSIT_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankDeposit },
- /*0x3EC*/ { "CMSG_GUILD_BANK_WITHDRAW_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankWithdraw },
- /*0x3ED*/ { "MSG_GUILD_BANK_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankLog },
- /*0x3EE*/ { "CMSG_SET_CHANNEL_WATCH", STATUS_LOGGEDIN, &WorldSession::HandleChannelJoinNotify },
- /*0x3EF*/ { "SMSG_USERLIST_ADD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3F0*/ { "SMSG_USERLIST_REMOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3F1*/ { "SMSG_USERLIST_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3F2*/ { "CMSG_CLEAR_CHANNEL_WATCH", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3F3*/ { "SMSG_INSPECT_TALENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3F4*/ { "SMSG_GOGOGO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3F5*/ { "SMSG_ECHO_PARTY_SQUELCH", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3F6*/ { "CMSG_SET_TITLE_SUFFIX", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3F7*/ { "CMSG_SPELLCLICK", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3F8*/ { "SMSG_LOOT_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3F9*/ { "CMSG_GM_CHARACTER_RESTORE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3FA*/ { "CMSG_GM_CHARACTER_SAVE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x3FB*/ { "SMSG_VOICESESSION_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x3FC*/ { "MSG_GUILD_PERMISSIONS", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankGetRights },
- /*0x3FD*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankGetMoneyAmount },
- /*0x3FE*/ { "MSG_GUILD_EVENT_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildEventLogOpcode },
- /*0x3FF*/ { "CMSG_MAELSTROM_RENAME_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x400*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x401*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x402*/ { "SMSG_FORCE_DISPLAY_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x403*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK",STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x404*/ { "CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT",STATUS_NEVER,&WorldSession::Handle_NULL },
- /*0x405*/ { "SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT",STATUS_NEVER,&WorldSession::Handle_ServerSide },
- /*0x406*/ { "CMSG_KEEP_ALIVE", STATUS_NEVER, &WorldSession::Handle_EarlyProccess },
- /*0x407*/ { "SMSG_RAID_READY_CHECK_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x408*/ { "CMSG_OPT_OUT_OF_LOOT", STATUS_AUTHED, &WorldSession::HandleGroupPassOnLootOpcode },
- /*0x409*/ { "MSG_QUERY_GUILD_BANK_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankTabText },
- /*0x40A*/ { "CMSG_SET_GUILD_BANK_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankSetTabText },
- /*0x40B*/ { "CMSG_SET_GRANTABLE_LEVELS", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x40C*/ { "CMSG_GRANT_LEVEL", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x40D*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x40E*/ { "MSG_GM_CHANGE_ARENA_RATING", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x40F*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelDeclineInvite },
- /*0x410*/ { "CMSG_GROUPACTION_THROTTLED", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x411*/ { "SMSG_OVERRIDE_LIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x412*/ { "SMSG_TOTEM_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x413*/ { "CMSG_TOTEM_DESTROYED", STATUS_LOGGEDIN, &WorldSession::HandleTotemDestroy },
- /*0x414*/ { "CMSG_EXPIRE_RAID_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x415*/ { "CMSG_NO_SPELL_VARIANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x416*/ { "CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY",STATUS_LOGGEDIN,&WorldSession::HandleQuestgiverStatusQueryMultipleOpcode},
- /*0x417*/ { "SMSG_QUESTGIVER_STATUS_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x418*/ { "CMSG_SET_PLAYER_DECLINED_NAMES", STATUS_AUTHED, &WorldSession::HandleDeclinedPlayerNameOpcode },
- /*0x419*/ { "SMSG_SET_PLAYER_DECLINED_NAMES_RESULT",STATUS_NEVER,&WorldSession::Handle_ServerSide },
- /*0x41A*/ { "CMSG_QUERY_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x41B*/ { "CMSG_CLEAR_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x41C*/ { "SMSG_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x41D*/ { "SMSG_SEND_UNLEARN_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x41E*/ { "SMSG_PROPOSE_LEVEL_GRANT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x41F*/ { "CMSG_ACCEPT_LEVEL_GRANT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x420*/ { "SMSG_REFER_A_FRIEND_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x421*/ { "SMSG_SPLINE_MOVE_SET_FLYING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x422*/ { "SMSG_SPLINE_MOVE_UNSET_FLYING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x423*/ { "SMSG_SUMMON_CANCEL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x000*/ { "MSG_NULL_ACTION", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x001*/ { "CMSG_BOOTME", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x002*/ { "CMSG_DBLOOKUP", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x003*/ { "SMSG_DBLOOKUP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x004*/ { "CMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x005*/ { "SMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x006*/ { "CMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x007*/ { "SMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x008*/ { "CMSG_WORLD_TELEPORT", STATUS_LOGGEDIN, &WorldSession::HandleWorldTeleportOpcode },
+ /*0x009*/ { "CMSG_TELEPORT_TO_UNIT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL },
+ /*0x00A*/ { "CMSG_ZONE_MAP", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x00B*/ { "SMSG_ZONE_MAP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x00C*/ { "CMSG_DEBUG_CHANGECELLZONE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x00D*/ { "CMSG_MOVE_CHARACTER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x00E*/ { "SMSG_MOVE_CHARACTER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x00F*/ { "CMSG_RECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x010*/ { "CMSG_LEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x011*/ { "CMSG_CREATEMONSTER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x012*/ { "CMSG_DESTROYMONSTER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x013*/ { "CMSG_CREATEITEM", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x014*/ { "CMSG_CREATEGAMEOBJECT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x015*/ { "SMSG_CHECK_FOR_BOTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x016*/ { "CMSG_MAKEMONSTERATTACKGUID", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x017*/ { "CMSG_BOT_DETECTED2", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x018*/ { "CMSG_FORCEACTION", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x019*/ { "CMSG_FORCEACTIONONOTHER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x01A*/ { "CMSG_FORCEACTIONSHOW", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x01B*/ { "SMSG_FORCEACTIONSHOW", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x01C*/ { "CMSG_PETGODMODE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x01D*/ { "SMSG_PETGODMODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x01E*/ { "SMSG_REFER_A_FRIEND_EXPIRED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x01F*/ { "CMSG_WEATHER_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x020*/ { "CMSG_UNDRESSPLAYER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x021*/ { "CMSG_BEASTMASTER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x022*/ { "CMSG_GODMODE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x023*/ { "SMSG_GODMODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x024*/ { "CMSG_CHEAT_SETMONEY", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x025*/ { "CMSG_LEVEL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x026*/ { "CMSG_PET_LEVEL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x027*/ { "CMSG_SET_WORLDSTATE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x028*/ { "CMSG_COOLDOWN_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x029*/ { "CMSG_USE_SKILL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x02A*/ { "CMSG_FLAG_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x02B*/ { "CMSG_FLAG_QUEST_FINISH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x02C*/ { "CMSG_CLEAR_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x02D*/ { "CMSG_SEND_EVENT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x02E*/ { "CMSG_DEBUG_AISTATE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x02F*/ { "SMSG_DEBUG_AISTATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x030*/ { "CMSG_DISABLE_PVP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x031*/ { "CMSG_ADVANCE_SPAWN_TIME", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x032*/ { "SMSG_DESTRUCTIBLE_BUILDING_DAMAGE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x033*/ { "CMSG_AUTH_SRP6_BEGIN", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x034*/ { "CMSG_AUTH_SRP6_PROOF", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x035*/ { "CMSG_AUTH_SRP6_RECODE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x036*/ { "CMSG_CHAR_CREATE", STATUS_AUTHED, &WorldSession::HandleCharCreateOpcode },
+ /*0x037*/ { "CMSG_CHAR_ENUM", STATUS_AUTHED, &WorldSession::HandleCharEnumOpcode },
+ /*0x038*/ { "CMSG_CHAR_DELETE", STATUS_AUTHED, &WorldSession::HandleCharDeleteOpcode },
+ /*0x039*/ { "SMSG_AUTH_SRP6_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x03A*/ { "SMSG_CHAR_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x03B*/ { "SMSG_CHAR_ENUM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x03C*/ { "SMSG_CHAR_DELETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x03D*/ { "CMSG_PLAYER_LOGIN", STATUS_AUTHED, &WorldSession::HandlePlayerLoginOpcode },
+ /*0x03E*/ { "SMSG_NEW_WORLD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x03F*/ { "SMSG_TRANSFER_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x040*/ { "SMSG_TRANSFER_ABORTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x041*/ { "SMSG_CHARACTER_LOGIN_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x042*/ { "SMSG_LOGIN_SETTIMESPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x043*/ { "SMSG_GAMETIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x044*/ { "CMSG_GAMETIME_SET", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x045*/ { "SMSG_GAMETIME_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x046*/ { "CMSG_GAMESPEED_SET", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x047*/ { "SMSG_GAMESPEED_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x048*/ { "CMSG_SERVERTIME", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x049*/ { "SMSG_SERVERTIME", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x04A*/ { "CMSG_PLAYER_LOGOUT", STATUS_LOGGEDIN, &WorldSession::HandlePlayerLogoutOpcode },
+ /*0x04B*/ { "CMSG_LOGOUT_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLogoutRequestOpcode },
+ /*0x04C*/ { "SMSG_LOGOUT_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x04D*/ { "SMSG_LOGOUT_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x04E*/ { "CMSG_LOGOUT_CANCEL", STATUS_LOGGEDIN, &WorldSession::HandleLogoutCancelOpcode },
+ /*0x04F*/ { "SMSG_LOGOUT_CANCEL_ACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x050*/ { "CMSG_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleNameQueryOpcode },
+ /*0x051*/ { "SMSG_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x052*/ { "CMSG_PET_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePetNameQuery },
+ /*0x053*/ { "SMSG_PET_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x054*/ { "CMSG_GUILD_QUERY", STATUS_AUTHED, &WorldSession::HandleGuildQueryOpcode },
+ /*0x055*/ { "SMSG_GUILD_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x056*/ { "CMSG_ITEM_QUERY_SINGLE", STATUS_LOGGEDIN, &WorldSession::HandleItemQuerySingleOpcode },
+ /*0x057*/ { "CMSG_ITEM_QUERY_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x058*/ { "SMSG_ITEM_QUERY_SINGLE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x059*/ { "SMSG_ITEM_QUERY_MULTIPLE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x05A*/ { "CMSG_PAGE_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePageQueryOpcode },
+ /*0x05B*/ { "SMSG_PAGE_TEXT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x05C*/ { "CMSG_QUEST_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestQueryOpcode },
+ /*0x05D*/ { "SMSG_QUEST_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x05E*/ { "CMSG_GAMEOBJECT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGameObjectQueryOpcode },
+ /*0x05F*/ { "SMSG_GAMEOBJECT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x060*/ { "CMSG_CREATURE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCreatureQueryOpcode },
+ /*0x061*/ { "SMSG_CREATURE_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x062*/ { "CMSG_WHO", STATUS_LOGGEDIN, &WorldSession::HandleWhoOpcode },
+ /*0x063*/ { "SMSG_WHO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x064*/ { "CMSG_WHOIS", STATUS_LOGGEDIN, &WorldSession::HandleWhoisOpcode },
+ /*0x065*/ { "SMSG_WHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x066*/ { "CMSG_CONTACT_LIST", STATUS_LOGGEDIN, &WorldSession::HandleFriendListOpcode },
+ /*0x067*/ { "SMSG_CONTACT_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x068*/ { "SMSG_FRIEND_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x069*/ { "CMSG_ADD_FRIEND", STATUS_LOGGEDIN, &WorldSession::HandleAddFriendOpcode },
+ /*0x06A*/ { "CMSG_DEL_FRIEND", STATUS_LOGGEDIN, &WorldSession::HandleDelFriendOpcode },
+ /*0x06B*/ { "CMSG_SET_CONTACT_NOTES", STATUS_LOGGEDIN, &WorldSession::HandleSetFriendNoteOpcode },
+ /*0x06C*/ { "CMSG_ADD_IGNORE", STATUS_LOGGEDIN, &WorldSession::HandleAddIgnoreOpcode },
+ /*0x06D*/ { "CMSG_DEL_IGNORE", STATUS_LOGGEDIN, &WorldSession::HandleDelIgnoreOpcode },
+ /*0x06E*/ { "CMSG_GROUP_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleGroupInviteOpcode },
+ /*0x06F*/ { "SMSG_GROUP_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x070*/ { "CMSG_GROUP_CANCEL", STATUS_LOGGEDIN, &WorldSession::Handle_Deprecated },
+ /*0x071*/ { "SMSG_GROUP_CANCEL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x072*/ { "CMSG_GROUP_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleGroupAcceptOpcode },
+ /*0x073*/ { "CMSG_GROUP_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleGroupDeclineOpcode },
+ /*0x074*/ { "SMSG_GROUP_DECLINE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x075*/ { "CMSG_GROUP_UNINVITE", STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteNameOpcode },
+ /*0x076*/ { "CMSG_GROUP_UNINVITE_GUID", STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteGuidOpcode },
+ /*0x077*/ { "SMSG_GROUP_UNINVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x078*/ { "CMSG_GROUP_SET_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupSetLeaderOpcode },
+ /*0x079*/ { "SMSG_GROUP_SET_LEADER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x07A*/ { "CMSG_LOOT_METHOD", STATUS_LOGGEDIN, &WorldSession::HandleLootMethodOpcode },
+ /*0x07B*/ { "CMSG_GROUP_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleGroupLeaveOpcode },
+ /*0x07C*/ { "SMSG_GROUP_DESTROYED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x07D*/ { "SMSG_GROUP_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x07E*/ { "SMSG_PARTY_MEMBER_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x07F*/ { "SMSG_PARTY_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x080*/ { "UMSG_UPDATE_GROUP_MEMBERS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x081*/ { "CMSG_GUILD_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildCreateOpcode },
+ /*0x082*/ { "CMSG_GUILD_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleGuildInviteOpcode },
+ /*0x083*/ { "SMSG_GUILD_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x084*/ { "CMSG_GUILD_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleGuildAcceptOpcode },
+ /*0x085*/ { "CMSG_GUILD_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleGuildDeclineOpcode },
+ /*0x086*/ { "SMSG_GUILD_DECLINE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x087*/ { "CMSG_GUILD_INFO", STATUS_LOGGEDIN, &WorldSession::HandleGuildInfoOpcode },
+ /*0x088*/ { "SMSG_GUILD_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x089*/ { "CMSG_GUILD_ROSTER", STATUS_LOGGEDIN, &WorldSession::HandleGuildRosterOpcode },
+ /*0x08A*/ { "SMSG_GUILD_ROSTER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x08B*/ { "CMSG_GUILD_PROMOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildPromoteOpcode },
+ /*0x08C*/ { "CMSG_GUILD_DEMOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildDemoteOpcode },
+ /*0x08D*/ { "CMSG_GUILD_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleGuildLeaveOpcode },
+ /*0x08E*/ { "CMSG_GUILD_REMOVE", STATUS_LOGGEDIN, &WorldSession::HandleGuildRemoveOpcode },
+ /*0x08F*/ { "CMSG_GUILD_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleGuildDisbandOpcode },
+ /*0x090*/ { "CMSG_GUILD_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGuildLeaderOpcode },
+ /*0x091*/ { "CMSG_GUILD_MOTD", STATUS_LOGGEDIN, &WorldSession::HandleGuildMOTDOpcode },
+ /*0x092*/ { "SMSG_GUILD_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x093*/ { "SMSG_GUILD_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x094*/ { "UMSG_UPDATE_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x095*/ { "CMSG_MESSAGECHAT", STATUS_LOGGEDIN, &WorldSession::HandleMessagechatOpcode },
+ /*0x096*/ { "SMSG_MESSAGECHAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x097*/ { "CMSG_JOIN_CHANNEL", STATUS_LOGGEDIN, &WorldSession::HandleChannelJoin },
+ /*0x098*/ { "CMSG_LEAVE_CHANNEL", STATUS_LOGGEDIN, &WorldSession::HandleChannelLeave },
+ /*0x099*/ { "SMSG_CHANNEL_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x09A*/ { "CMSG_CHANNEL_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelList },
+ /*0x09B*/ { "SMSG_CHANNEL_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x09C*/ { "CMSG_CHANNEL_PASSWORD", STATUS_LOGGEDIN, &WorldSession::HandleChannelPassword },
+ /*0x09D*/ { "CMSG_CHANNEL_SET_OWNER", STATUS_LOGGEDIN, &WorldSession::HandleChannelSetOwner },
+ /*0x09E*/ { "CMSG_CHANNEL_OWNER", STATUS_LOGGEDIN, &WorldSession::HandleChannelOwner },
+ /*0x09F*/ { "CMSG_CHANNEL_MODERATOR", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerator },
+ /*0x0A0*/ { "CMSG_CHANNEL_UNMODERATOR", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnmoderator },
+ /*0x0A1*/ { "CMSG_CHANNEL_MUTE", STATUS_LOGGEDIN, &WorldSession::HandleChannelMute },
+ /*0x0A2*/ { "CMSG_CHANNEL_UNMUTE", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnmute },
+ /*0x0A3*/ { "CMSG_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelInvite },
+ /*0x0A4*/ { "CMSG_CHANNEL_KICK", STATUS_LOGGEDIN, &WorldSession::HandleChannelKick },
+ /*0x0A5*/ { "CMSG_CHANNEL_BAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelBan },
+ /*0x0A6*/ { "CMSG_CHANNEL_UNBAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnban },
+ /*0x0A7*/ { "CMSG_CHANNEL_ANNOUNCEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleChannelAnnounce },
+ /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerate },
+ /*0x0A9*/ { "SMSG_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0AA*/ { "SMSG_DESTROY_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0AB*/ { "CMSG_USE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleUseItemOpcode },
+ /*0x0AC*/ { "CMSG_OPEN_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleOpenItemOpcode },
+ /*0x0AD*/ { "CMSG_READ_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleReadItem },
+ /*0x0AE*/ { "SMSG_READ_ITEM_OK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0AF*/ { "SMSG_READ_ITEM_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0B0*/ { "SMSG_ITEM_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0B1*/ { "CMSG_GAMEOBJ_USE", STATUS_LOGGEDIN, &WorldSession::HandleGameObjectUseOpcode },
+ /*0x0B2*/ { "CMSG_DESTROY_ITEMS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0B3*/ { "SMSG_GAMEOBJECT_CUSTOM_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0B4*/ { "CMSG_AREATRIGGER", STATUS_LOGGEDIN, &WorldSession::HandleAreaTriggerOpcode },
+ /*0x0B5*/ { "MSG_MOVE_START_FORWARD", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0B6*/ { "MSG_MOVE_START_BACKWARD", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0B7*/ { "MSG_MOVE_STOP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0B8*/ { "MSG_MOVE_START_STRAFE_LEFT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0B9*/ { "MSG_MOVE_START_STRAFE_RIGHT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0BA*/ { "MSG_MOVE_STOP_STRAFE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0BB*/ { "MSG_MOVE_JUMP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0BC*/ { "MSG_MOVE_START_TURN_LEFT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0BD*/ { "MSG_MOVE_START_TURN_RIGHT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0BE*/ { "MSG_MOVE_STOP_TURN", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0BF*/ { "MSG_MOVE_START_PITCH_UP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0C0*/ { "MSG_MOVE_START_PITCH_DOWN", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0C1*/ { "MSG_MOVE_STOP_PITCH", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0C2*/ { "MSG_MOVE_SET_RUN_MODE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0C3*/ { "MSG_MOVE_SET_WALK_MODE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0C4*/ { "MSG_MOVE_TOGGLE_LOGGING", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0C5*/ { "MSG_MOVE_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0C6*/ { "MSG_MOVE_TELEPORT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0C7*/ { "MSG_MOVE_TELEPORT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveTeleportAck },
+ /*0x0C8*/ { "MSG_MOVE_TOGGLE_FALL_LOGGING", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0C9*/ { "MSG_MOVE_FALL_LAND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0CA*/ { "MSG_MOVE_START_SWIM", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0CB*/ { "MSG_MOVE_STOP_SWIM", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0CC*/ { "MSG_MOVE_SET_RUN_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0CD*/ { "MSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0CE*/ { "MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0CF*/ { "MSG_MOVE_SET_RUN_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D0*/ { "MSG_MOVE_SET_WALK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D1*/ { "MSG_MOVE_SET_WALK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D2*/ { "MSG_MOVE_SET_SWIM_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D3*/ { "MSG_MOVE_SET_SWIM_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D4*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D5*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D6*/ { "MSG_MOVE_SET_ALL_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D7*/ { "MSG_MOVE_SET_TURN_RATE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D8*/ { "MSG_MOVE_SET_TURN_RATE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0D9*/ { "MSG_MOVE_TOGGLE_COLLISION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0DA*/ { "MSG_MOVE_SET_FACING", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0DB*/ { "MSG_MOVE_SET_PITCH", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0DC*/ { "MSG_MOVE_WORLDPORT_ACK", STATUS_TRANSFER_PENDING,&WorldSession::HandleMoveWorldportAckOpcode},
+ /*0x0DD*/ { "SMSG_MONSTER_MOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0DE*/ { "SMSG_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0DF*/ { "SMSG_MOVE_LAND_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0E0*/ { "MSG_MOVE_SET_RAW_POSITION_ACK", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0E1*/ { "CMSG_MOVE_SET_RAW_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0E2*/ { "SMSG_FORCE_RUN_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0E3*/ { "CMSG_FORCE_RUN_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
+ /*0x0E4*/ { "SMSG_FORCE_RUN_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0E5*/ { "CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
+ /*0x0E6*/ { "SMSG_FORCE_SWIM_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0E7*/ { "CMSG_FORCE_SWIM_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
+ /*0x0E8*/ { "SMSG_FORCE_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0E9*/ { "CMSG_FORCE_MOVE_ROOT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveRootAck },
+ /*0x0EA*/ { "SMSG_FORCE_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0EB*/ { "CMSG_FORCE_MOVE_UNROOT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveUnRootAck },
+ /*0x0EC*/ { "MSG_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0ED*/ { "MSG_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0EE*/ { "MSG_MOVE_HEARTBEAT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x0EF*/ { "SMSG_MOVE_KNOCK_BACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0F0*/ { "CMSG_MOVE_KNOCK_BACK_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveKnockBackAck },
+ /*0x0F1*/ { "MSG_MOVE_KNOCK_BACK", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0F2*/ { "SMSG_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0F3*/ { "SMSG_MOVE_NORMAL_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0F4*/ { "SMSG_MOVE_SET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0F5*/ { "SMSG_MOVE_UNSET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0F6*/ { "CMSG_MOVE_HOVER_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveHoverAck },
+ /*0x0F7*/ { "MSG_MOVE_HOVER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0F8*/ { "CMSG_TRIGGER_CINEMATIC_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0F9*/ { "CMSG_OPENING_CINEMATIC", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0FA*/ { "SMSG_TRIGGER_CINEMATIC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0FB*/ { "CMSG_NEXT_CINEMATIC_CAMERA", STATUS_LOGGEDIN, &WorldSession::HandleNextCinematicCamera },
+ /*0x0FC*/ { "CMSG_COMPLETE_CINEMATIC", STATUS_LOGGEDIN, &WorldSession::HandleCompleteCinema },
+ /*0x0FD*/ { "SMSG_TUTORIAL_FLAGS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0FE*/ { "CMSG_TUTORIAL_FLAG", STATUS_LOGGEDIN, &WorldSession::HandleTutorialFlag },
+ /*0x0FF*/ { "CMSG_TUTORIAL_CLEAR", STATUS_LOGGEDIN, &WorldSession::HandleTutorialClear },
+ /*0x100*/ { "CMSG_TUTORIAL_RESET", STATUS_LOGGEDIN, &WorldSession::HandleTutorialReset },
+ /*0x101*/ { "CMSG_STANDSTATECHANGE", STATUS_LOGGEDIN, &WorldSession::HandleStandStateChangeOpcode },
+ /*0x102*/ { "CMSG_EMOTE", STATUS_LOGGEDIN, &WorldSession::HandleEmoteOpcode },
+ /*0x103*/ { "SMSG_EMOTE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x104*/ { "CMSG_TEXT_EMOTE", STATUS_LOGGEDIN, &WorldSession::HandleTextEmoteOpcode },
+ /*0x105*/ { "SMSG_TEXT_EMOTE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x106*/ { "CMSG_AUTOEQUIP_GROUND_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x107*/ { "CMSG_AUTOSTORE_GROUND_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x108*/ { "CMSG_AUTOSTORE_LOOT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutostoreLootItemOpcode },
+ /*0x109*/ { "CMSG_STORE_LOOT_IN_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x10A*/ { "CMSG_AUTOEQUIP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoEquipItemOpcode },
+ /*0x10B*/ { "CMSG_AUTOSTORE_BAG_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBagItemOpcode },
+ /*0x10C*/ { "CMSG_SWAP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSwapItem },
+ /*0x10D*/ { "CMSG_SWAP_INV_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSwapInvItemOpcode },
+ /*0x10E*/ { "CMSG_SPLIT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSplitItemOpcode },
+ /*0x10F*/ { "CMSG_AUTOEQUIP_ITEM_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleAutoEquipItemSlotOpcode },
+ /*0x110*/ { "OBSOLETE_DROP_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x111*/ { "CMSG_DESTROYITEM", STATUS_LOGGEDIN, &WorldSession::HandleDestroyItemOpcode },
+ /*0x112*/ { "SMSG_INVENTORY_CHANGE_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x113*/ { "SMSG_OPEN_CONTAINER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x114*/ { "CMSG_INSPECT", STATUS_LOGGEDIN, &WorldSession::HandleInspectOpcode },
+ /*0x115*/ { "SMSG_INSPECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x116*/ { "CMSG_INITIATE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleInitiateTradeOpcode },
+ /*0x117*/ { "CMSG_BEGIN_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleBeginTradeOpcode },
+ /*0x118*/ { "CMSG_BUSY_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleBusyTradeOpcode },
+ /*0x119*/ { "CMSG_IGNORE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleIgnoreTradeOpcode },
+ /*0x11A*/ { "CMSG_ACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleAcceptTradeOpcode },
+ /*0x11B*/ { "CMSG_UNACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleUnacceptTradeOpcode },
+ /*0x11C*/ { "CMSG_CANCEL_TRADE", STATUS_AUTHED, &WorldSession::HandleCancelTradeOpcode },
+ /*0x11D*/ { "CMSG_SET_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeItemOpcode },
+ /*0x11E*/ { "CMSG_CLEAR_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleClearTradeItemOpcode },
+ /*0x11F*/ { "CMSG_SET_TRADE_GOLD", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeGoldOpcode },
+ /*0x120*/ { "SMSG_TRADE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x121*/ { "SMSG_TRADE_STATUS_EXTENDED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x122*/ { "SMSG_INITIALIZE_FACTIONS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x123*/ { "SMSG_SET_FACTION_VISIBLE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x124*/ { "SMSG_SET_FACTION_STANDING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x125*/ { "CMSG_SET_FACTION_ATWAR", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionAtWar },
+ /*0x126*/ { "CMSG_SET_FACTION_CHEAT", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionCheat },
+ /*0x127*/ { "SMSG_SET_PROFICIENCY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x128*/ { "CMSG_SET_ACTION_BUTTON", STATUS_LOGGEDIN, &WorldSession::HandleSetActionButtonOpcode },
+ /*0x129*/ { "SMSG_ACTION_BUTTONS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x12A*/ { "SMSG_INITIAL_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x12B*/ { "SMSG_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x12C*/ { "SMSG_SUPERCEDED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x12D*/ { "CMSG_NEW_SPELL_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x12E*/ { "CMSG_CAST_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleCastSpellOpcode },
+ /*0x12F*/ { "CMSG_CANCEL_CAST", STATUS_LOGGEDIN, &WorldSession::HandleCancelCastOpcode },
+ /*0x130*/ { "SMSG_CAST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x131*/ { "SMSG_SPELL_START", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x132*/ { "SMSG_SPELL_GO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x133*/ { "SMSG_SPELL_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x134*/ { "SMSG_SPELL_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x135*/ { "SMSG_COOLDOWN_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x136*/ { "CMSG_CANCEL_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelAuraOpcode },
+ /*0x137*/ { "SMSG_UPDATE_AURA_DURATION_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x138*/ { "SMSG_PET_CAST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x139*/ { "MSG_CHANNEL_START", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x13A*/ { "MSG_CHANNEL_UPDATE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x13B*/ { "CMSG_CANCEL_CHANNELLING", STATUS_LOGGEDIN, &WorldSession::HandleCancelChanneling },
+ /*0x13C*/ { "SMSG_AI_REACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x13D*/ { "CMSG_SET_SELECTION", STATUS_LOGGEDIN, &WorldSession::HandleSetSelectionOpcode },
+ /*0x13E*/ { "CMSG_SET_TARGET_OBSOLETE", STATUS_LOGGEDIN, &WorldSession::HandleSetTargetOpcode },
+ /*0x13F*/ { "CMSG_UNUSED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x140*/ { "CMSG_UNUSED2", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x141*/ { "CMSG_ATTACKSWING", STATUS_LOGGEDIN, &WorldSession::HandleAttackSwingOpcode },
+ /*0x142*/ { "CMSG_ATTACKSTOP", STATUS_LOGGEDIN, &WorldSession::HandleAttackStopOpcode },
+ /*0x143*/ { "SMSG_ATTACKSTART", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x144*/ { "SMSG_ATTACKSTOP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x145*/ { "SMSG_ATTACKSWING_NOTINRANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x146*/ { "SMSG_ATTACKSWING_BADFACING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x147*/ { "SMSG_ATTACKSWING_NOTSTANDING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x148*/ { "SMSG_ATTACKSWING_DEADTARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x149*/ { "SMSG_ATTACKSWING_CANT_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x14A*/ { "SMSG_ATTACKERSTATEUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x14B*/ { "SMSG_VICTIMSTATEUPDATE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x14C*/ { "SMSG_DAMAGE_DONE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x14D*/ { "SMSG_DAMAGE_TAKEN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x14E*/ { "SMSG_CANCEL_COMBAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x14F*/ { "SMSG_SPELLBREAKLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x150*/ { "SMSG_SPELLHEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x151*/ { "SMSG_SPELLENERGIZELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x152*/ { "SMSG_BREAK_TARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x153*/ { "CMSG_SAVE_PLAYER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x154*/ { "CMSG_SETDEATHBINDPOINT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x155*/ { "SMSG_BINDPOINTUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x156*/ { "CMSG_GETDEATHBINDZONE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x157*/ { "SMSG_BINDZONEREPLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x158*/ { "SMSG_PLAYERBOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x159*/ { "SMSG_CLIENT_CONTROL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x15A*/ { "CMSG_REPOP_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleRepopRequestOpcode },
+ /*0x15B*/ { "SMSG_RESURRECT_REQUEST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x15C*/ { "CMSG_RESURRECT_RESPONSE", STATUS_LOGGEDIN, &WorldSession::HandleResurrectResponseOpcode },
+ /*0x15D*/ { "CMSG_LOOT", STATUS_LOGGEDIN, &WorldSession::HandleLootOpcode },
+ /*0x15E*/ { "CMSG_LOOT_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleLootMoneyOpcode },
+ /*0x15F*/ { "CMSG_LOOT_RELEASE", STATUS_LOGGEDIN, &WorldSession::HandleLootReleaseOpcode },
+ /*0x160*/ { "SMSG_LOOT_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x161*/ { "SMSG_LOOT_RELEASE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x162*/ { "SMSG_LOOT_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x163*/ { "SMSG_LOOT_MONEY_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x164*/ { "SMSG_LOOT_ITEM_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x165*/ { "SMSG_LOOT_CLEAR_MONEY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x166*/ { "SMSG_ITEM_PUSH_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x167*/ { "SMSG_DUEL_REQUESTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x168*/ { "SMSG_DUEL_OUTOFBOUNDS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x169*/ { "SMSG_DUEL_INBOUNDS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x16A*/ { "SMSG_DUEL_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x16B*/ { "SMSG_DUEL_WINNER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x16C*/ { "CMSG_DUEL_ACCEPTED", STATUS_LOGGEDIN, &WorldSession::HandleDuelAcceptedOpcode },
+ /*0x16D*/ { "CMSG_DUEL_CANCELLED", STATUS_LOGGEDIN, &WorldSession::HandleDuelCancelledOpcode },
+ /*0x16E*/ { "SMSG_MOUNTRESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x16F*/ { "SMSG_DISMOUNTRESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x170*/ { "SMSG_PUREMOUNT_CANCELLED_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x171*/ { "CMSG_MOUNTSPECIAL_ANIM", STATUS_LOGGEDIN, &WorldSession::HandleMountSpecialAnimOpcode },
+ /*0x172*/ { "SMSG_MOUNTSPECIAL_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x173*/ { "SMSG_PET_TAME_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x174*/ { "CMSG_PET_SET_ACTION", STATUS_LOGGEDIN, &WorldSession::HandlePetSetAction },
+ /*0x175*/ { "CMSG_PET_ACTION", STATUS_LOGGEDIN, &WorldSession::HandlePetAction },
+ /*0x176*/ { "CMSG_PET_ABANDON", STATUS_LOGGEDIN, &WorldSession::HandlePetAbandon },
+ /*0x177*/ { "CMSG_PET_RENAME", STATUS_LOGGEDIN, &WorldSession::HandlePetRename },
+ /*0x178*/ { "SMSG_PET_NAME_INVALID", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x179*/ { "SMSG_PET_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x17A*/ { "SMSG_PET_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x17B*/ { "CMSG_GOSSIP_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleGossipHelloOpcode },
+ /*0x17C*/ { "CMSG_GOSSIP_SELECT_OPTION", STATUS_LOGGEDIN, &WorldSession::HandleGossipSelectOptionOpcode },
+ /*0x17D*/ { "SMSG_GOSSIP_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x17E*/ { "SMSG_GOSSIP_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x17F*/ { "CMSG_NPC_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleNpcTextQueryOpcode },
+ /*0x180*/ { "SMSG_NPC_TEXT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x181*/ { "SMSG_NPC_WONT_TALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x182*/ { "CMSG_QUESTGIVER_STATUS_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverStatusQueryOpcode},
+ /*0x183*/ { "SMSG_QUESTGIVER_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x184*/ { "CMSG_QUESTGIVER_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverHelloOpcode },
+ /*0x185*/ { "SMSG_QUESTGIVER_QUEST_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x186*/ { "CMSG_QUESTGIVER_QUERY_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverQuestQueryOpcode},
+ /*0x187*/ { "CMSG_QUESTGIVER_QUEST_AUTOLAUNCH", STATUS_LOGGEDIN, &WorldSession::HandleQuestAutoLaunch },
+ /*0x188*/ { "SMSG_QUESTGIVER_QUEST_DETAILS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x189*/ { "CMSG_QUESTGIVER_ACCEPT_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverAcceptQuestOpcode},
+ /*0x18A*/ { "CMSG_QUESTGIVER_COMPLETE_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestComplete },
+ /*0x18B*/ { "SMSG_QUESTGIVER_REQUEST_ITEMS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x18C*/ { "CMSG_QUESTGIVER_REQUEST_REWARD", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverRequestRewardOpcode},
+ /*0x18D*/ { "SMSG_QUESTGIVER_OFFER_REWARD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x18E*/ { "CMSG_QUESTGIVER_CHOOSE_REWARD", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverChooseRewardOpcode},
+ /*0x18F*/ { "SMSG_QUESTGIVER_QUEST_INVALID", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x190*/ { "CMSG_QUESTGIVER_CANCEL", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverCancel },
+ /*0x191*/ { "SMSG_QUESTGIVER_QUEST_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x192*/ { "SMSG_QUESTGIVER_QUEST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x193*/ { "CMSG_QUESTLOG_SWAP_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestLogSwapQuest },
+ /*0x194*/ { "CMSG_QUESTLOG_REMOVE_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestLogRemoveQuest },
+ /*0x195*/ { "SMSG_QUESTLOG_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x196*/ { "SMSG_QUESTUPDATE_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x197*/ { "SMSG_QUESTUPDATE_FAILEDTIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x198*/ { "SMSG_QUESTUPDATE_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x199*/ { "SMSG_QUESTUPDATE_ADD_KILL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x19A*/ { "SMSG_QUESTUPDATE_ADD_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x19B*/ { "CMSG_QUEST_CONFIRM_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleQuestConfirmAccept },
+ /*0x19C*/ { "SMSG_QUEST_CONFIRM_ACCEPT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x19D*/ { "CMSG_PUSHQUESTTOPARTY", STATUS_LOGGEDIN, &WorldSession::HandleQuestPushToParty },
+ /*0x19E*/ { "CMSG_LIST_INVENTORY", STATUS_LOGGEDIN, &WorldSession::HandleListInventoryOpcode },
+ /*0x19F*/ { "SMSG_LIST_INVENTORY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1A0*/ { "CMSG_SELL_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSellItemOpcode },
+ /*0x1A1*/ { "SMSG_SELL_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1A2*/ { "CMSG_BUY_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuyItemOpcode },
+ /*0x1A3*/ { "CMSG_BUY_ITEM_IN_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyItemInSlotOpcode },
+ /*0x1A4*/ { "SMSG_BUY_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1A5*/ { "SMSG_BUY_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1A6*/ { "CMSG_TAXICLEARALLNODES", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1A7*/ { "CMSG_TAXIENABLEALLNODES", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1A8*/ { "CMSG_TAXISHOWNODES", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1A9*/ { "SMSG_SHOWTAXINODES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1AA*/ { "CMSG_TAXINODE_STATUS_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleTaxiNodeStatusQueryOpcode },
+ /*0x1AB*/ { "SMSG_TAXINODE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1AC*/ { "CMSG_TAXIQUERYAVAILABLENODES", STATUS_LOGGEDIN, &WorldSession::HandleTaxiQueryAvailableNodes },
+ /*0x1AD*/ { "CMSG_ACTIVATETAXI", STATUS_LOGGEDIN, &WorldSession::HandleActivateTaxiOpcode },
+ /*0x1AE*/ { "SMSG_ACTIVATETAXIREPLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1AF*/ { "SMSG_NEW_TAXI_PATH", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1B0*/ { "CMSG_TRAINER_LIST", STATUS_LOGGEDIN, &WorldSession::HandleTrainerListOpcode },
+ /*0x1B1*/ { "SMSG_TRAINER_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1B2*/ { "CMSG_TRAINER_BUY_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleTrainerBuySpellOpcode },
+ /*0x1B3*/ { "SMSG_TRAINER_BUY_SUCCEEDED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1B4*/ { "SMSG_TRAINER_BUY_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1B5*/ { "CMSG_BINDER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleBinderActivateOpcode },
+ /*0x1B6*/ { "SMSG_PLAYERBINDERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1B7*/ { "CMSG_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleBankerActivateOpcode },
+ /*0x1B8*/ { "SMSG_SHOW_BANK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1B9*/ { "CMSG_BUY_BANK_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyBankSlotOpcode },
+ /*0x1BA*/ { "SMSG_BUY_BANK_SLOT_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1BB*/ { "CMSG_PETITION_SHOWLIST", STATUS_LOGGEDIN, &WorldSession::HandlePetitionShowListOpcode },
+ /*0x1BC*/ { "SMSG_PETITION_SHOWLIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1BD*/ { "CMSG_PETITION_BUY", STATUS_LOGGEDIN, &WorldSession::HandlePetitionBuyOpcode },
+ /*0x1BE*/ { "CMSG_PETITION_SHOW_SIGNATURES", STATUS_LOGGEDIN, &WorldSession::HandlePetitionShowSignOpcode },
+ /*0x1BF*/ { "SMSG_PETITION_SHOW_SIGNATURES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1C0*/ { "CMSG_PETITION_SIGN", STATUS_LOGGEDIN, &WorldSession::HandlePetitionSignOpcode },
+ /*0x1C1*/ { "SMSG_PETITION_SIGN_RESULTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1C2*/ { "MSG_PETITION_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandlePetitionDeclineOpcode },
+ /*0x1C3*/ { "CMSG_OFFER_PETITION", STATUS_LOGGEDIN, &WorldSession::HandleOfferPetitionOpcode },
+ /*0x1C4*/ { "CMSG_TURN_IN_PETITION", STATUS_LOGGEDIN, &WorldSession::HandleTurnInPetitionOpcode },
+ /*0x1C5*/ { "SMSG_TURN_IN_PETITION_RESULTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1C6*/ { "CMSG_PETITION_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePetitionQueryOpcode },
+ /*0x1C7*/ { "SMSG_PETITION_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1C8*/ { "SMSG_FISH_NOT_HOOKED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1C9*/ { "SMSG_FISH_ESCAPED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1CA*/ { "CMSG_BUG", STATUS_LOGGEDIN, &WorldSession::HandleBugOpcode },
+ /*0x1CB*/ { "SMSG_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1CC*/ { "CMSG_PLAYED_TIME", STATUS_LOGGEDIN, &WorldSession::HandlePlayedTime },
+ /*0x1CD*/ { "SMSG_PLAYED_TIME", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1CE*/ { "CMSG_QUERY_TIME", STATUS_LOGGEDIN, &WorldSession::HandleQueryTimeOpcode },
+ /*0x1CF*/ { "SMSG_QUERY_TIME_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1D0*/ { "SMSG_LOG_XPGAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1D1*/ { "SMSG_AURACASTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1D2*/ { "CMSG_RECLAIM_CORPSE", STATUS_LOGGEDIN, &WorldSession::HandleCorpseReclaimOpcode },
+ /*0x1D3*/ { "CMSG_WRAP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleWrapItemOpcode },
+ /*0x1D4*/ { "SMSG_LEVELUP_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1D5*/ { "MSG_MINIMAP_PING", STATUS_LOGGEDIN, &WorldSession::HandleMinimapPingOpcode },
+ /*0x1D6*/ { "SMSG_RESISTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1D7*/ { "SMSG_ENCHANTMENTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1D8*/ { "CMSG_SET_SKILL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1D9*/ { "SMSG_START_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1DA*/ { "SMSG_PAUSE_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1DB*/ { "SMSG_STOP_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1DC*/ { "CMSG_PING", STATUS_NEVER, &WorldSession::Handle_EarlyProccess },
+ /*0x1DD*/ { "SMSG_PONG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1DE*/ { "SMSG_CLEAR_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1DF*/ { "SMSG_GAMEOBJECT_PAGETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1E0*/ { "CMSG_SETSHEATHED", STATUS_LOGGEDIN, &WorldSession::HandleSetSheathedOpcode },
+ /*0x1E1*/ { "SMSG_COOLDOWN_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1E2*/ { "SMSG_SPELL_DELAYED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1E3*/ { "CMSG_PLAYER_MACRO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1E4*/ { "SMSG_PLAYER_MACRO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1E5*/ { "CMSG_GHOST", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1E6*/ { "CMSG_GM_INVIS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1E7*/ { "SMSG_INVALID_PROMOTION_CODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1E8*/ { "MSG_GM_BIND_OTHER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1E9*/ { "MSG_GM_SUMMON", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1EA*/ { "SMSG_ITEM_TIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1EB*/ { "SMSG_ITEM_ENCHANT_TIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1EC*/ { "SMSG_AUTH_CHALLENGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1ED*/ { "CMSG_AUTH_SESSION", STATUS_NEVER, &WorldSession::Handle_EarlyProccess },
+ /*0x1EE*/ { "SMSG_AUTH_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1EF*/ { "MSG_GM_SHOWLABEL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1F0*/ { "CMSG_PET_CAST_SPELL", STATUS_LOGGEDIN, &WorldSession::HandlePetCastSpellOpcode },
+ /*0x1F1*/ { "MSG_SAVE_GUILD_EMBLEM", STATUS_LOGGEDIN, &WorldSession::HandleGuildSaveEmblemOpcode },
+ /*0x1F2*/ { "MSG_TABARDVENDOR_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleTabardVendorActivateOpcode},
+ /*0x1F3*/ { "SMSG_PLAY_SPELL_VISUAL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1F4*/ { "CMSG_ZONEUPDATE", STATUS_LOGGEDIN, &WorldSession::HandleZoneUpdateOpcode },
+ /*0x1F5*/ { "SMSG_PARTYKILLLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1F6*/ { "SMSG_COMPRESSED_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1F7*/ { "SMSG_PLAY_SPELL_IMPACT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1F8*/ { "SMSG_EXPLORATION_EXPERIENCE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1F9*/ { "CMSG_GM_SET_SECURITY_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1FA*/ { "CMSG_GM_NUKE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1FB*/ { "MSG_RANDOM_ROLL", STATUS_LOGGEDIN, &WorldSession::HandleRandomRollOpcode },
+ /*0x1FC*/ { "SMSG_ENVIRONMENTALDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1FD*/ { "CMSG_RWHOIS_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x1FE*/ { "SMSG_RWHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x1FF*/ { "MSG_LOOKING_FOR_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleLookingForGroup },
+ /*0x200*/ { "CMSG_SET_LOOKING_FOR_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleSetLfgOpcode },
+ /*0x201*/ { "CMSG_UNLEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x202*/ { "CMSG_UNLEARN_SKILL", STATUS_LOGGEDIN, &WorldSession::HandleUnlearnSkillOpcode },
+ /*0x203*/ { "SMSG_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x204*/ { "CMSG_DECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x205*/ { "CMSG_GMTICKET_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketCreateOpcode },
+ /*0x206*/ { "SMSG_GMTICKET_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x207*/ { "CMSG_GMTICKET_UPDATETEXT", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketUpdateOpcode },
+ /*0x208*/ { "SMSG_GMTICKET_UPDATETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x209*/ { "SMSG_ACCOUNT_DATA_TIMES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x20A*/ { "CMSG_REQUEST_ACCOUNT_DATA", STATUS_LOGGEDIN, &WorldSession::HandleRequestAccountData },
+ /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_AUTHED, &WorldSession::HandleUpdateAccountData },
+ /*0x20C*/ { "SMSG_UPDATE_ACCOUNT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x20D*/ { "SMSG_CLEAR_FAR_SIGHT_IMMEDIATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x20E*/ { "SMSG_POWERGAINLOG_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x20F*/ { "CMSG_GM_TEACH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x210*/ { "CMSG_GM_CREATE_ITEM_TARGET", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x211*/ { "CMSG_GMTICKET_GETTICKET", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketGetTicketOpcode },
+ /*0x212*/ { "SMSG_GMTICKET_GETTICKET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x213*/ { "CMSG_UNLEARN_TALENTS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x214*/ { "SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x215*/ { "SMSG_GAMEOBJECT_DESPAWN_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x216*/ { "MSG_CORPSE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCorpseQueryOpcode },
+ /*0x217*/ { "CMSG_GMTICKET_DELETETICKET", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketDeleteOpcode },
+ /*0x218*/ { "SMSG_GMTICKET_DELETETICKET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x219*/ { "SMSG_CHAT_WRONG_FACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x21A*/ { "CMSG_GMTICKET_SYSTEMSTATUS", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketSystemStatusOpcode},
+ /*0x21B*/ { "SMSG_GMTICKET_SYSTEMSTATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x21C*/ { "CMSG_SPIRIT_HEALER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleSpiritHealerActivateOpcode},
+ /*0x21D*/ { "CMSG_SET_STAT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x21E*/ { "SMSG_SET_REST_START_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x21F*/ { "CMSG_SKILL_BUY_STEP", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x220*/ { "CMSG_SKILL_BUY_RANK", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x221*/ { "CMSG_XP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x222*/ { "SMSG_SPIRIT_HEALER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x223*/ { "CMSG_CHARACTER_POINT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x224*/ { "SMSG_GOSSIP_POI", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x225*/ { "CMSG_CHAT_IGNORED", STATUS_LOGGEDIN, &WorldSession::HandleChatIgnoredOpcode },
+ /*0x226*/ { "CMSG_GM_VISION", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x227*/ { "CMSG_SERVER_COMMAND", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x228*/ { "CMSG_GM_SILENCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x229*/ { "CMSG_GM_REVEALTO", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x22A*/ { "CMSG_GM_RESURRECT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x22B*/ { "CMSG_GM_SUMMONMOB", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x22C*/ { "CMSG_GM_MOVECORPSE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x22D*/ { "CMSG_GM_FREEZE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x22E*/ { "CMSG_GM_UBERINVIS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x22F*/ { "CMSG_GM_REQUEST_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x230*/ { "SMSG_GM_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x231*/ { "CMSG_GUILD_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildRankOpcode },
+ /*0x232*/ { "CMSG_GUILD_ADD_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildAddRankOpcode },
+ /*0x233*/ { "CMSG_GUILD_DEL_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildDelRankOpcode },
+ /*0x234*/ { "CMSG_GUILD_SET_PUBLIC_NOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildSetPublicNoteOpcode },
+ /*0x235*/ { "CMSG_GUILD_SET_OFFICER_NOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildSetOfficerNoteOpcode },
+ /*0x236*/ { "SMSG_LOGIN_VERIFY_WORLD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x237*/ { "CMSG_CLEAR_EXPLORATION", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x238*/ { "CMSG_SEND_MAIL", STATUS_LOGGEDIN, &WorldSession::HandleSendMail },
+ /*0x239*/ { "SMSG_SEND_MAIL_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x23A*/ { "CMSG_GET_MAIL_LIST", STATUS_LOGGEDIN, &WorldSession::HandleGetMail },
+ /*0x23B*/ { "SMSG_MAIL_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x23C*/ { "CMSG_BATTLEFIELD_LIST", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundListOpcode },
+ /*0x23D*/ { "SMSG_BATTLEFIELD_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x23E*/ { "CMSG_BATTLEFIELD_JOIN", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x23F*/ { "SMSG_BATTLEFIELD_WIN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x240*/ { "SMSG_BATTLEFIELD_LOSE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x241*/ { "CMSG_TAXICLEARNODE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x242*/ { "CMSG_TAXIENABLENODE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x243*/ { "CMSG_ITEM_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleItemTextQuery },
+ /*0x244*/ { "SMSG_ITEM_TEXT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x245*/ { "CMSG_MAIL_TAKE_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleTakeMoney },
+ /*0x246*/ { "CMSG_MAIL_TAKE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleTakeItem },
+ /*0x247*/ { "CMSG_MAIL_MARK_AS_READ", STATUS_LOGGEDIN, &WorldSession::HandleMarkAsRead },
+ /*0x248*/ { "CMSG_MAIL_RETURN_TO_SENDER", STATUS_LOGGEDIN, &WorldSession::HandleReturnToSender },
+ /*0x249*/ { "CMSG_MAIL_DELETE", STATUS_LOGGEDIN, &WorldSession::HandleMailDelete },
+ /*0x24A*/ { "CMSG_MAIL_CREATE_TEXT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleMailCreateTextItem },
+ /*0x24B*/ { "SMSG_SPELLLOGMISS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x24C*/ { "SMSG_SPELLLOGEXECUTE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x24D*/ { "SMSG_DEBUGAURAPROC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x24E*/ { "SMSG_PERIODICAURALOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x24F*/ { "SMSG_SPELLDAMAGESHIELD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x250*/ { "SMSG_SPELLNONMELEEDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x251*/ { "CMSG_LEARN_TALENT", STATUS_LOGGEDIN, &WorldSession::HandleLearnTalentOpcode },
+ /*0x252*/ { "SMSG_RESURRECT_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x253*/ { "CMSG_TOGGLE_PVP", STATUS_LOGGEDIN, &WorldSession::HandleTogglePvP },
+ /*0x254*/ { "SMSG_ZONE_UNDER_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x255*/ { "MSG_AUCTION_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleAuctionHelloOpcode },
+ /*0x256*/ { "CMSG_AUCTION_SELL_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAuctionSellItem },
+ /*0x257*/ { "CMSG_AUCTION_REMOVE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAuctionRemoveItem },
+ /*0x258*/ { "CMSG_AUCTION_LIST_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListItems },
+ /*0x259*/ { "CMSG_AUCTION_LIST_OWNER_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListOwnerItems },
+ /*0x25A*/ { "CMSG_AUCTION_PLACE_BID", STATUS_LOGGEDIN, &WorldSession::HandleAuctionPlaceBid },
+ /*0x25B*/ { "SMSG_AUCTION_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x25C*/ { "SMSG_AUCTION_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x25D*/ { "SMSG_AUCTION_OWNER_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x25E*/ { "SMSG_AUCTION_BIDDER_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x25F*/ { "SMSG_AUCTION_OWNER_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x260*/ { "SMSG_PROCRESIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x261*/ { "SMSG_STANDSTATE_CHANGE_FAILURE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x262*/ { "SMSG_DISPEL_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x263*/ { "SMSG_SPELLORDAMAGE_IMMUNE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x264*/ { "CMSG_AUCTION_LIST_BIDDER_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListBidderItems },
+ /*0x265*/ { "SMSG_AUCTION_BIDDER_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x266*/ { "SMSG_SET_FLAT_SPELL_MODIFIER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x267*/ { "SMSG_SET_PCT_SPELL_MODIFIER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x268*/ { "CMSG_SET_AMMO", STATUS_LOGGEDIN, &WorldSession::HandleSetAmmoOpcode },
+ /*0x269*/ { "SMSG_CORPSE_RECLAIM_DELAY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x26A*/ { "CMSG_SET_ACTIVE_MOVER", STATUS_LOGGEDIN, &WorldSession::HandleSetActiveMoverOpcode },
+ /*0x26B*/ { "CMSG_PET_CANCEL_AURA", STATUS_LOGGEDIN, &WorldSession::HandlePetCancelAuraOpcode },
+ /*0x26C*/ { "CMSG_PLAYER_AI_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x26D*/ { "CMSG_CANCEL_AUTO_REPEAT_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleCancelAutoRepeatSpellOpcode},
+ /*0x26E*/ { "MSG_GM_ACCOUNT_ONLINE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x26F*/ { "MSG_LIST_STABLED_PETS", STATUS_LOGGEDIN, &WorldSession::HandleListStabledPetsOpcode },
+ /*0x270*/ { "CMSG_STABLE_PET", STATUS_LOGGEDIN, &WorldSession::HandleStablePet },
+ /*0x271*/ { "CMSG_UNSTABLE_PET", STATUS_LOGGEDIN, &WorldSession::HandleUnstablePet },
+ /*0x272*/ { "CMSG_BUY_STABLE_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyStableSlot },
+ /*0x273*/ { "SMSG_STABLE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x274*/ { "CMSG_STABLE_REVIVE_PET", STATUS_LOGGEDIN, &WorldSession::HandleStableRevivePet },
+ /*0x275*/ { "CMSG_STABLE_SWAP_PET", STATUS_LOGGEDIN, &WorldSession::HandleStableSwapPet },
+ /*0x276*/ { "MSG_QUEST_PUSH_RESULT", STATUS_LOGGEDIN, &WorldSession::HandleQuestPushResult },
+ /*0x277*/ { "SMSG_PLAY_MUSIC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x278*/ { "SMSG_PLAY_OBJECT_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x279*/ { "CMSG_REQUEST_PET_INFO", STATUS_LOGGEDIN, &WorldSession::HandleRequestPetInfoOpcode },
+ /*0x27A*/ { "CMSG_FAR_SIGHT", STATUS_LOGGEDIN, &WorldSession::HandleFarSightOpcode },
+ /*0x27B*/ { "SMSG_SPELLDISPELLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x27C*/ { "SMSG_DAMAGE_CALC_LOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x27D*/ { "CMSG_ENABLE_DAMAGE_LOG", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x27E*/ { "CMSG_GROUP_CHANGE_SUB_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleGroupChangeSubGroupOpcode },
+ /*0x27F*/ { "CMSG_REQUEST_PARTY_MEMBER_STATS", STATUS_LOGGEDIN, &WorldSession::HandleRequestPartyMemberStatsOpcode},
+ /*0x280*/ { "CMSG_GROUP_SWAP_SUB_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x281*/ { "CMSG_RESET_FACTION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x282*/ { "CMSG_AUTOSTORE_BANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBankItemOpcode },
+ /*0x283*/ { "CMSG_AUTOBANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoBankItemOpcode },
+ /*0x284*/ { "MSG_QUERY_NEXT_MAIL_TIME", STATUS_LOGGEDIN, &WorldSession::HandleMsgQueryNextMailtime },
+ /*0x285*/ { "SMSG_RECEIVED_MAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x286*/ { "SMSG_RAID_GROUP_ONLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x287*/ { "CMSG_SET_DURABILITY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x288*/ { "CMSG_SET_PVP_RANK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x289*/ { "CMSG_ADD_PVP_MEDAL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x28A*/ { "CMSG_DEL_PVP_MEDAL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x28B*/ { "CMSG_SET_PVP_TITLE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x28C*/ { "SMSG_PVP_CREDIT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x28D*/ { "SMSG_AUCTION_REMOVED_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x28E*/ { "CMSG_GROUP_RAID_CONVERT", STATUS_LOGGEDIN, &WorldSession::HandleRaidConvertOpcode },
+ /*0x28F*/ { "CMSG_GROUP_ASSISTANT_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupAssistantOpcode },
+ /*0x290*/ { "CMSG_BUYBACK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuybackItem },
+ /*0x291*/ { "SMSG_SERVER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x292*/ { "CMSG_MEETINGSTONE_JOIN", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x293*/ { "CMSG_MEETINGSTONE_LEAVE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x294*/ { "CMSG_MEETINGSTONE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x295*/ { "SMSG_MEETINGSTONE_SETQUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x296*/ { "CMSG_MEETINGSTONE_INFO", STATUS_LOGGEDIN, &WorldSession::HandleMeetingStoneInfo },
+ /*0x297*/ { "SMSG_MEETINGSTONE_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x298*/ { "SMSG_MEETINGSTONE_IN_PROGRESS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x299*/ { "SMSG_MEETINGSTONE_MEMBER_ADDED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x29A*/ { "CMSG_GMTICKETSYSTEM_TOGGLE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x29B*/ { "CMSG_CANCEL_GROWTH_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelGrowthAuraOpcode },
+ /*0x29C*/ { "SMSG_CANCEL_AUTO_REPEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x29D*/ { "SMSG_STANDSTATE_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x29E*/ { "SMSG_LOOT_ALL_PASSED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x29F*/ { "SMSG_LOOT_ROLL_WON", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2A0*/ { "CMSG_LOOT_ROLL", STATUS_LOGGEDIN, &WorldSession::HandleLootRoll },
+ /*0x2A1*/ { "SMSG_LOOT_START_ROLL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2A2*/ { "SMSG_LOOT_ROLL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2A3*/ { "CMSG_LOOT_MASTER_GIVE", STATUS_LOGGEDIN, &WorldSession::HandleLootMasterGiveOpcode },
+ /*0x2A4*/ { "SMSG_LOOT_MASTER_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2A5*/ { "SMSG_SET_FORCED_REACTIONS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2A6*/ { "SMSG_SPELL_FAILED_OTHER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2A7*/ { "SMSG_GAMEOBJECT_RESET_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2A8*/ { "CMSG_REPAIR_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleRepairItemOpcode },
+ /*0x2A9*/ { "SMSG_CHAT_PLAYER_NOT_FOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2AA*/ { "MSG_TALENT_WIPE_CONFIRM", STATUS_LOGGEDIN, &WorldSession::HandleTalentWipeOpcode },
+ /*0x2AB*/ { "SMSG_SUMMON_REQUEST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2AC*/ { "CMSG_SUMMON_RESPONSE", STATUS_LOGGEDIN, &WorldSession::HandleSummonResponseOpcode },
+ /*0x2AD*/ { "MSG_MOVE_TOGGLE_GRAVITY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2AE*/ { "SMSG_MONSTER_MOVE_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2AF*/ { "SMSG_PET_BROKEN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2B0*/ { "MSG_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2B1*/ { "MSG_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2B2*/ { "CMSG_SERVER_BROADCAST", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2B3*/ { "CMSG_SELF_RES", STATUS_LOGGEDIN, &WorldSession::HandleSelfResOpcode },
+ /*0x2B4*/ { "SMSG_FEIGN_DEATH_RESISTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2B5*/ { "CMSG_RUN_SCRIPT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2B6*/ { "SMSG_SCRIPT_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2B7*/ { "SMSG_DUEL_COUNTDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2B8*/ { "SMSG_AREA_TRIGGER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2B9*/ { "CMSG_SHOWING_HELM", STATUS_LOGGEDIN, &WorldSession::HandleToggleHelmOpcode },
+ /*0x2BA*/ { "CMSG_SHOWING_CLOAK", STATUS_LOGGEDIN, &WorldSession::HandleToggleCloakOpcode },
+ /*0x2BB*/ { "SMSG_MEETINGSTONE_JOINFAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2BC*/ { "SMSG_PLAYER_SKINNED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2BD*/ { "SMSG_DURABILITY_DAMAGE_DEATH", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2BE*/ { "CMSG_SET_EXPLORATION", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2BF*/ { "CMSG_SET_ACTIONBAR_TOGGLES", STATUS_AUTHED, &WorldSession::HandleSetActionBar },
+ /*0x2C0*/ { "UMSG_DELETE_GUILD_CHARTER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2C1*/ { "MSG_PETITION_RENAME", STATUS_LOGGEDIN, &WorldSession::HandlePetitionRenameOpcode },
+ /*0x2C2*/ { "SMSG_INIT_WORLD_STATES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2C3*/ { "SMSG_UPDATE_WORLD_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2C4*/ { "CMSG_ITEM_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleItemNameQueryOpcode },
+ /*0x2C5*/ { "SMSG_ITEM_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2C6*/ { "SMSG_PET_ACTION_FEEDBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2C7*/ { "CMSG_CHAR_RENAME", STATUS_AUTHED, &WorldSession::HandleChangePlayerNameOpcode },
+ /*0x2C8*/ { "SMSG_CHAR_RENAME", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2C9*/ { "CMSG_MOVE_SPLINE_DONE", STATUS_LOGGEDIN, &WorldSession::HandleTaxiNextDestinationOpcode },
+ /*0x2CA*/ { "CMSG_MOVE_FALL_RESET", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x2CB*/ { "SMSG_INSTANCE_SAVE_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2CC*/ { "SMSG_RAID_INSTANCE_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2CD*/ { "CMSG_REQUEST_RAID_INFO", STATUS_LOGGEDIN, &WorldSession::HandleRequestRaidInfoOpcode },
+ /*0x2CE*/ { "CMSG_MOVE_TIME_SKIPPED", STATUS_LOGGEDIN, &WorldSession::HandleMoveTimeSkippedOpcode },
+ /*0x2CF*/ { "CMSG_MOVE_FEATHER_FALL_ACK", STATUS_LOGGEDIN, &WorldSession::HandleFeatherFallAck },
+ /*0x2D0*/ { "CMSG_MOVE_WATER_WALK_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveWaterWalkAck },
+ /*0x2D1*/ { "CMSG_MOVE_NOT_ACTIVE_MOVER", STATUS_LOGGEDIN, &WorldSession::HandleMoveNotActiveMover },
+ /*0x2D2*/ { "SMSG_PLAY_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2D3*/ { "CMSG_BATTLEFIELD_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleBattlefieldStatusOpcode },
+ /*0x2D4*/ { "SMSG_BATTLEFIELD_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2D5*/ { "CMSG_BATTLEFIELD_PORT", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPlayerPortOpcode},
+ /*0x2D6*/ { "MSG_INSPECT_HONOR_STATS", STATUS_LOGGEDIN, &WorldSession::HandleInspectHonorStatsOpcode },
+ /*0x2D7*/ { "CMSG_BATTLEMASTER_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundHelloOpcode },
+ /*0x2D8*/ { "CMSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2D9*/ { "CMSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2DA*/ { "SMSG_FORCE_WALK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2DB*/ { "CMSG_FORCE_WALK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
+ /*0x2DC*/ { "SMSG_FORCE_SWIM_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2DD*/ { "CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
+ /*0x2DE*/ { "SMSG_FORCE_TURN_RATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2DF*/ { "CMSG_FORCE_TURN_RATE_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
+ /*0x2E0*/ { "MSG_PVP_LOG_DATA", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPVPlogdataOpcode},
+ /*0x2E1*/ { "CMSG_LEAVE_BATTLEFIELD", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundLeaveOpcode },
+ /*0x2E2*/ { "CMSG_AREA_SPIRIT_HEALER_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleAreaSpiritHealerQueryOpcode},
+ /*0x2E3*/ { "CMSG_AREA_SPIRIT_HEALER_QUEUE", STATUS_LOGGEDIN, &WorldSession::HandleAreaSpiritHealerQueueOpcode},
+ /*0x2E4*/ { "SMSG_AREA_SPIRIT_HEALER_TIME", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2E5*/ { "CMSG_GM_UNTEACH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2E6*/ { "SMSG_WARDEN_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2E7*/ { "CMSG_WARDEN_DATA", STATUS_LOGGEDIN, &WorldSession::HandleWardenDataOpcode },
+ /*0x2E8*/ { "SMSG_GROUP_JOINED_BATTLEGROUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2E9*/ { "MSG_BATTLEGROUND_PLAYER_POSITIONS", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPlayerPositionsOpcode},
+ /*0x2EA*/ { "CMSG_PET_STOP_ATTACK", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2EB*/ { "SMSG_BINDER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2EC*/ { "SMSG_BATTLEGROUND_PLAYER_JOINED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2ED*/ { "SMSG_BATTLEGROUND_PLAYER_LEFT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2EE*/ { "CMSG_BATTLEMASTER_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundJoinOpcode },
+ /*0x2EF*/ { "SMSG_ADDON_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2F0*/ { "CMSG_PET_UNLEARN", STATUS_LOGGEDIN, &WorldSession::HandlePetUnlearnOpcode },
+ /*0x2F1*/ { "SMSG_PET_UNLEARN_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2F2*/ { "SMSG_PARTY_MEMBER_STATS_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2F3*/ { "CMSG_PET_SPELL_AUTOCAST", STATUS_LOGGEDIN, &WorldSession::HandlePetSpellAutocastOpcode },
+ /*0x2F4*/ { "SMSG_WEATHER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2F5*/ { "SMSG_PLAY_TIME_WARNING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2F6*/ { "SMSG_MINIGAME_SETUP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2F7*/ { "SMSG_MINIGAME_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2F8*/ { "CMSG_MINIGAME_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x2F9*/ { "SMSG_MINIGAME_MOVE_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2FA*/ { "SMSG_RAID_INSTANCE_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2FB*/ { "SMSG_COMPRESSED_MOVES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2FC*/ { "CMSG_GUILD_INFO_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleGuildChangeInfoOpcode },
+ /*0x2FD*/ { "SMSG_CHAT_RESTRICTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2FE*/ { "SMSG_SPLINE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x2FF*/ { "SMSG_SPLINE_SET_RUN_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x300*/ { "SMSG_SPLINE_SET_SWIM_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x301*/ { "SMSG_SPLINE_SET_WALK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x302*/ { "SMSG_SPLINE_SET_SWIM_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x303*/ { "SMSG_SPLINE_SET_TURN_RATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x304*/ { "SMSG_SPLINE_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x305*/ { "SMSG_SPLINE_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x306*/ { "SMSG_SPLINE_MOVE_NORMAL_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x307*/ { "SMSG_SPLINE_MOVE_SET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x308*/ { "SMSG_SPLINE_MOVE_UNSET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x309*/ { "SMSG_SPLINE_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x30A*/ { "SMSG_SPLINE_MOVE_LAND_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x30B*/ { "SMSG_SPLINE_MOVE_START_SWIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x30C*/ { "SMSG_SPLINE_MOVE_STOP_SWIM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x30D*/ { "SMSG_SPLINE_MOVE_SET_RUN_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x30E*/ { "SMSG_SPLINE_MOVE_SET_WALK_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x30F*/ { "CMSG_GM_NUKE_ACCOUNT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x310*/ { "MSG_GM_DESTROY_CORPSE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x311*/ { "CMSG_GM_DESTROY_ONLINE_CORPSE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x312*/ { "CMSG_ACTIVATETAXIEXPRESS", STATUS_LOGGEDIN, &WorldSession::HandleActivateTaxiFarOpcode },
+ /*0x313*/ { "SMSG_SET_FACTION_ATWAR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x314*/ { "SMSG_GAMETIMEBIAS_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x315*/ { "CMSG_DEBUG_ACTIONS_START", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x316*/ { "CMSG_DEBUG_ACTIONS_STOP", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x317*/ { "CMSG_SET_FACTION_INACTIVE", STATUS_LOGGEDIN, &WorldSession::HandleSetWatchedFactionInactiveOpcode},
+ /*0x318*/ { "CMSG_SET_WATCHED_FACTION", STATUS_LOGGEDIN, &WorldSession::HandleSetWatchedFactionIndexOpcode},
+ /*0x319*/ { "MSG_MOVE_TIME_SKIPPED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x31A*/ { "SMSG_SPLINE_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x31B*/ { "CMSG_SET_EXPLORATION_ALL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x31C*/ { "SMSG_INVALIDATE_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x31D*/ { "CMSG_RESET_INSTANCES", STATUS_LOGGEDIN, &WorldSession::HandleResetInstancesOpcode },
+ /*0x31E*/ { "SMSG_INSTANCE_RESET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x31F*/ { "SMSG_INSTANCE_RESET_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x320*/ { "SMSG_UPDATE_LAST_INSTANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x321*/ { "MSG_RAID_TARGET_UPDATE", STATUS_LOGGEDIN, &WorldSession::HandleRaidIconTargetOpcode },
+ /*0x322*/ { "MSG_RAID_READY_CHECK", STATUS_LOGGEDIN, &WorldSession::HandleRaidReadyCheckOpcode },
+ /*0x323*/ { "CMSG_LUA_USAGE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x324*/ { "SMSG_PET_ACTION_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x325*/ { "SMSG_PET_DISMISS_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x326*/ { "SMSG_GHOSTEE_GONE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x327*/ { "CMSG_GM_UPDATE_TICKET_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x328*/ { "SMSG_GM_TICKET_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x329*/ { "MSG_SET_DUNGEON_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleDungeonDifficultyOpcode },
+ /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_NEVER, &WorldSession::Handle_NULL },//LOGGEDIN, &WorldSession::HandleGMSurveySubmit },
+ /*0x32B*/ { "SMSG_UPDATE_INSTANCE_OWNERSHIP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x32C*/ { "CMSG_IGNORE_KNOCKBACK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x32D*/ { "SMSG_CHAT_PLAYER_AMBIGUOUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x32E*/ { "MSG_DELAY_GHOST_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x32F*/ { "SMSG_SPELLINSTAKILLLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x330*/ { "SMSG_SPELL_UPDATE_CHAIN_TARGETS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x331*/ { "CMSG_CHAT_FILTERED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x332*/ { "SMSG_EXPECTED_SPAM_RECORDS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x333*/ { "SMSG_SPELLSTEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x334*/ { "CMSG_LOTTERY_QUERY_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x335*/ { "SMSG_LOTTERY_QUERY_RESULT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x336*/ { "CMSG_BUY_LOTTERY_TICKET_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x337*/ { "SMSG_LOTTERY_RESULT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x338*/ { "SMSG_CHARACTER_PROFILE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x339*/ { "SMSG_CHARACTER_PROFILE_REALM_CONNECTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x33A*/ { "SMSG_DEFENSE_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x33B*/ { "SMSG_INSTANCE_DIFFICULTY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x33C*/ { "MSG_GM_RESETINSTANCELIMIT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x33D*/ { "SMSG_MOTD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x33E*/ { "SMSG_MOVE_SET_FLIGHT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x33F*/ { "SMSG_MOVE_UNSET_FLIGHT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x340*/ { "CMSG_MOVE_FLIGHT_ACK_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x341*/ { "MSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x342*/ { "MSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x343*/ { "SMSG_MOVE_SET_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x344*/ { "SMSG_MOVE_UNSET_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x345*/ { "CMSG_MOVE_SET_CAN_FLY_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveFlyModeChangeAckOpcode},
+ /*0x346*/ { "CMSG_MOVE_SET_FLY", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x347*/ { "CMSG_SOCKET_GEMS", STATUS_LOGGEDIN, &WorldSession::HandleSocketOpcode },
+ /*0x348*/ { "CMSG_ARENA_TEAM_CREATE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x349*/ { "SMSG_ARENA_TEAM_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x34A*/ { "UMSG_UPDATE_ARENA_TEAM_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x34B*/ { "CMSG_ARENA_TEAM_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamQueryOpcode },
+ /*0x34C*/ { "SMSG_ARENA_TEAM_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x34D*/ { "CMSG_ARENA_TEAM_ROSTER", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamRosterOpcode },
+ /*0x34E*/ { "SMSG_ARENA_TEAM_ROSTER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x34F*/ { "CMSG_ARENA_TEAM_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamAddMemberOpcode },
+ /*0x350*/ { "SMSG_ARENA_TEAM_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x351*/ { "CMSG_ARENA_TEAM_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamInviteAcceptOpcode},
+ /*0x352*/ { "CMSG_ARENA_TEAM_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamInviteDeclineOpcode},
+ /*0x353*/ { "CMSG_ARENA_TEAM_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamLeaveOpcode },
+ /*0x354*/ { "CMSG_ARENA_TEAM_REMOVE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamRemoveFromTeamOpcode},
+ /*0x355*/ { "CMSG_ARENA_TEAM_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamDisbandOpcode },
+ /*0x356*/ { "CMSG_ARENA_TEAM_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamPromoteToCaptainOpcode},
+ /*0x357*/ { "SMSG_ARENA_TEAM_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x358*/ { "CMSG_BATTLEMASTER_JOIN_ARENA", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundArenaJoin },
+ /*0x359*/ { "MSG_MOVE_START_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x35A*/ { "MSG_MOVE_STOP_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x35B*/ { "SMSG_ARENA_TEAM_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x35C*/ { "CMSG_LFG_SET_AUTOJOIN", STATUS_AUTHED, &WorldSession::HandleLfgAutoJoinOpcode },
+ /*0x35D*/ { "CMSG_LFG_CLEAR_AUTOJOIN", STATUS_LOGGEDIN, &WorldSession::HandleLfgCancelAutoJoinOpcode },
+ /*0x35E*/ { "CMSG_LFM_SET_AUTOFILL", STATUS_AUTHED, &WorldSession::HandleLfmAutoAddMembersOpcode },
+ /*0x35F*/ { "CMSG_LFM_CLEAR_AUTOFILL", STATUS_LOGGEDIN, &WorldSession::HandleLfmCancelAutoAddmembersOpcode},
+ /*0x360*/ { "CMSG_ACCEPT_LFG_MATCH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x361*/ { "CMSG_DECLINE_LFG_MATCH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x362*/ { "CMSG_CANCEL_PENDING_LFG", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x363*/ { "CMSG_CLEAR_LOOKING_FOR_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleLfgClearOpcode },
+ /*0x364*/ { "CMSG_CLEAR_LOOKING_FOR_MORE", STATUS_LOGGEDIN, &WorldSession::HandleLfmSetNoneOpcode },
+ /*0x365*/ { "CMSG_SET_LOOKING_FOR_MORE", STATUS_LOGGEDIN, &WorldSession::HandleLfmSetOpcode },
+ /*0x366*/ { "CMSG_SET_LFG_COMMENT", STATUS_LOGGEDIN, &WorldSession::HandleLfgSetCommentOpcode },
+ /*0x367*/ { "SMSG_LFG_TIMEDOUT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x368*/ { "SMSG_LFG_OTHER_TIMEDOUT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x369*/ { "SMSG_LFG_AUTOJOIN_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x36A*/ { "SMSG_LFG_AUTOJOIN_FAILED_NO_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x36B*/ { "SMSG_LFG_LEADER_IS_LFM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x36C*/ { "SMSG_LFG_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x36D*/ { "SMSG_LFG_UPDATE_LFM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x36E*/ { "SMSG_LFG_UPDATE_LFG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x36F*/ { "SMSG_LFG_UPDATE_QUEUED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x370*/ { "SMSG_LFG_PENDING_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x371*/ { "SMSG_LFG_PENDING_MATCH", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x372*/ { "SMSG_LFG_PENDING_MATCH_DONE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x373*/ { "SMSG_TITLE_EARNED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x374*/ { "CMSG_SET_TITLE", STATUS_LOGGEDIN, &WorldSession::HandleChooseTitleOpcode },
+ /*0x375*/ { "CMSG_CANCEL_MOUNT_AURA", STATUS_LOGGEDIN, &WorldSession::HandleDismountOpcode },
+ /*0x376*/ { "SMSG_ARENA_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x377*/ { "MSG_INSPECT_ARENA_TEAMS", STATUS_LOGGEDIN, &WorldSession::HandleInspectArenaStatsOpcode },
+ /*0x378*/ { "SMSG_DEATH_RELEASE_LOC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x379*/ { "CMSG_CANCEL_TEMP_ENCHANTMENT", STATUS_LOGGEDIN, &WorldSession::HandleCancelTempItemEnchantmentOpcode},
+ /*0x37A*/ { "SMSG_FORCED_DEATH_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x37B*/ { "CMSG_CHEAT_SET_HONOR_CURRENCY", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x37C*/ { "CMSG_CHEAT_SET_ARENA_CURRENCY", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x37D*/ { "MSG_MOVE_SET_FLIGHT_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x37E*/ { "MSG_MOVE_SET_FLIGHT_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x37F*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x380*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x381*/ { "SMSG_FORCE_FLIGHT_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x382*/ { "CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
+ /*0x383*/ { "SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x384*/ { "CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck },
+ /*0x385*/ { "SMSG_SPLINE_SET_FLIGHT_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x386*/ { "SMSG_SPLINE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x387*/ { "CMSG_MAELSTROM_INVALIDATE_CACHE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x388*/ { "SMSG_FLIGHT_SPLINE_SYNC", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x389*/ { "CMSG_SET_TAXI_BENCHMARK_MODE", STATUS_AUTHED, &WorldSession::HandleSetTaxiBenchmarkOpcode },
+ /*0x38A*/ { "SMSG_JOINED_BATTLEGROUND_QUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x38B*/ { "SMSG_REALM_SPLIT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x38C*/ { "CMSG_REALM_SPLIT", STATUS_AUTHED, &WorldSession::HandleRealmStateRequestOpcode },
+ /*0x38D*/ { "CMSG_MOVE_CHNG_TRANSPORT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x38E*/ { "MSG_PARTY_ASSIGNMENT", STATUS_LOGGEDIN, &WorldSession::HandleGroupPromoteOpcode },
+ /*0x38F*/ { "SMSG_OFFER_PETITION_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x390*/ { "SMSG_TIME_SYNC_REQ", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x391*/ { "CMSG_TIME_SYNC_RESP", STATUS_LOGGEDIN, &WorldSession::HandleTimeSyncResp },
+ /*0x392*/ { "CMSG_SEND_LOCAL_EVENT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x393*/ { "CMSG_SEND_GENERAL_TRIGGER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x394*/ { "CMSG_SEND_COMBAT_TRIGGER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x395*/ { "CMSG_MAELSTROM_GM_SENT_MAIL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x396*/ { "SMSG_RESET_FAILED_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x397*/ { "SMSG_REAL_GROUP_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x398*/ { "SMSG_LFG_DISABLED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x399*/ { "CMSG_ACTIVE_PVP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x39A*/ { "CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x39B*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x39C*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE",STATUS_NEVER,&WorldSession::Handle_ServerSide },
+ /*0x39D*/ { "SMSG_UPDATE_COMBO_POINTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x39E*/ { "SMSG_VOICE_SESSION_ROSTER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x39F*/ { "SMSG_VOICE_SESSION_LEAVE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3A0*/ { "SMSG_VOICE_SESSION_ADJUST_PRIORITY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3A1*/ { "CMSG_VOICE_SET_TALKER_MUTED_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3A2*/ { "SMSG_VOICE_SET_TALKER_MUTED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3A3*/ { "SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3A4*/ { "SMSG_SET_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3A5*/ { "SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE",STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3A6*/ { "SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3A7*/ { "MSG_MOVE_START_DESCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes },
+ /*0x3A8*/ { "CMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3A9*/ { "SMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3AA*/ { "SMSG_SPELL_CHANCE_PROC_LOG", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3AB*/ { "CMSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3AC*/ { "SMSG_DISMOUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3AD*/ { "MSG_MOVE_UPDATE_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3AE*/ { "MSG_RAID_READY_CHECK_CONFIRM", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3AF*/ { "CMSG_VOICE_SESSION_ENABLE", STATUS_AUTHED, &WorldSession::HandleVoiceSettingsOpcode },
+ /*0x3B0*/ { "SMSG_VOICE_SESSION_ENABLE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3B1*/ { "SMSG_VOICE_PARENTAL_CONTROLS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3B2*/ { "CMSG_GM_WHISPER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3B3*/ { "SMSG_GM_MESSAGECHAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3B4*/ { "MSG_GM_GEARRATING", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3B5*/ { "CMSG_COMMENTATOR_ENABLE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3B6*/ { "SMSG_COMMENTATOR_STATE_CHANGED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3B7*/ { "CMSG_COMMENTATOR_GET_MAP_INFO", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3B8*/ { "SMSG_COMMENTATOR_MAP_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3B9*/ { "CMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3BA*/ { "SMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3BB*/ { "SMSG_COMMENTATOR_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3BC*/ { "CMSG_COMMENTATOR_ENTER_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3BD*/ { "CMSG_COMMENTATOR_EXIT_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3BE*/ { "CMSG_COMMENTATOR_INSTANCE_COMMAND", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3BF*/ { "SMSG_CLEAR_TARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3C0*/ { "CMSG_BOT_DETECTED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3C1*/ { "SMSG_CROSSED_INEBRIATION_THRESHOLD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3C2*/ { "CMSG_CHEAT_PLAYER_LOGIN", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3C3*/ { "CMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3C4*/ { "SMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3C5*/ { "SMSG_KICK_REASON", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3C6*/ { "MSG_RAID_READY_CHECK_FINISHED", STATUS_LOGGEDIN, &WorldSession::HandleRaidReadyCheckFinishOpcode},
+ /*0x3C7*/ { "CMSG_COMPLAIN", STATUS_LOGGEDIN, &WorldSession::HandleReportSpamOpcode },
+ /*0x3C8*/ { "SMSG_COMPLAIN_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3C9*/ { "SMSG_FEATURE_SYSTEM_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3CA*/ { "CMSG_GM_SHOW_COMPLAINTS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3CB*/ { "CMSG_GM_UNSQUELCH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3CC*/ { "CMSG_CHANNEL_SILENCE_VOICE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3CD*/ { "CMSG_CHANNEL_SILENCE_ALL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3CE*/ { "CMSG_CHANNEL_UNSILENCE_VOICE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3CF*/ { "CMSG_CHANNEL_UNSILENCE_ALL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3D0*/ { "CMSG_TARGET_CAST", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3D1*/ { "CMSG_TARGET_SCRIPT_CAST", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3D2*/ { "CMSG_CHANNEL_DISPLAY_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelRosterQuery },
+ /*0x3D3*/ { "CMSG_SET_ACTIVE_VOICE_CHANNEL", STATUS_AUTHED, &WorldSession::HandleChannelVoiceChatQuery },
+ /*0x3D4*/ { "CMSG_GET_CHANNEL_MEMBER_COUNT", STATUS_LOGGEDIN, &WorldSession::HandleChannelInfoQuery },
+ /*0x3D5*/ { "SMSG_CHANNEL_MEMBER_COUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3D6*/ { "CMSG_CHANNEL_VOICE_ON", STATUS_LOGGEDIN, &WorldSession::HandleChannelEnableVoiceOpcode },
+ /*0x3D7*/ { "CMSG_CHANNEL_VOICE_OFF", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3D8*/ { "CMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3D9*/ { "SMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3DA*/ { "SMSG_AVAILABLE_VOICE_CHANNEL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3DB*/ { "CMSG_ADD_VOICE_IGNORE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3DC*/ { "CMSG_DEL_VOICE_IGNORE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3DD*/ { "CMSG_PARTY_SILENCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3DE*/ { "CMSG_PARTY_UNSILENCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3DF*/ { "MSG_NOTIFY_PARTY_SQUELCH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3E0*/ { "SMSG_COMSAT_RECONNECT_TRY", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3E1*/ { "SMSG_COMSAT_DISCONNECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3E2*/ { "SMSG_COMSAT_CONNECT_FAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3E3*/ { "SMSG_VOICE_CHAT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3E4*/ { "CMSG_REPORT_PVP_AFK", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundReportAFK },
+ /*0x3E5*/ { "CMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3E6*/ { "CMSG_GUILD_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankQuery },
+ /*0x3E7*/ { "CMSG_GUILD_BANK_QUERY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankTabColon },
+ /*0x3E8*/ { "SMSG_GUILD_BANK_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3E9*/ { "CMSG_GUILD_BANK_SWAP_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankDepositItem },
+ /*0x3EA*/ { "CMSG_GUILD_BANK_BUY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankBuyTab },
+ /*0x3EB*/ { "CMSG_GUILD_BANK_UPDATE_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankModifyTab },
+ /*0x3EC*/ { "CMSG_GUILD_BANK_DEPOSIT_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankDeposit },
+ /*0x3ED*/ { "CMSG_GUILD_BANK_WITHDRAW_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankWithdraw },
+ /*0x3EE*/ { "MSG_GUILD_BANK_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankLog },
+ /*0x3EF*/ { "CMSG_SET_CHANNEL_WATCH", STATUS_LOGGEDIN, &WorldSession::HandleChannelJoinNotify },
+ /*0x3F0*/ { "SMSG_USERLIST_ADD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3F1*/ { "SMSG_USERLIST_REMOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3F2*/ { "SMSG_USERLIST_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3F3*/ { "CMSG_CLEAR_CHANNEL_WATCH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3F4*/ { "SMSG_INSPECT_TALENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3F5*/ { "SMSG_GOGOGO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3F6*/ { "SMSG_ECHO_PARTY_SQUELCH", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3F7*/ { "CMSG_SET_TITLE_SUFFIX", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3F8*/ { "CMSG_SPELLCLICK", STATUS_LOGGEDIN, &WorldSession::HandleSpellClick },
+ /*0x3F9*/ { "SMSG_LOOT_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3FA*/ { "CMSG_GM_CHARACTER_RESTORE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3FB*/ { "CMSG_GM_CHARACTER_SAVE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3FC*/ { "SMSG_VOICESESSION_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x3FD*/ { "MSG_GUILD_PERMISSIONS", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankGetRights },
+ /*0x3FE*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankGetMoneyAmount },
+ /*0x3FF*/ { "MSG_GUILD_EVENT_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildEventLogOpcode },
+ /*0x400*/ { "CMSG_MAELSTROM_RENAME_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x402*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x403*/ { "SMSG_FORCE_DISPLAY_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x404*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x405*/ { "CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x406*/ { "SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x407*/ { "CMSG_KEEP_ALIVE", STATUS_NEVER, &WorldSession::Handle_EarlyProccess },
+ /*0x408*/ { "SMSG_RAID_READY_CHECK_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x409*/ { "CMSG_OPT_OUT_OF_LOOT", STATUS_AUTHED, &WorldSession::HandleGroupPassOnLootOpcode },
+ /*0x40A*/ { "MSG_QUERY_GUILD_BANK_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankTabText },
+ /*0x40B*/ { "CMSG_SET_GUILD_BANK_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankSetTabText },
+ /*0x40C*/ { "CMSG_SET_GRANTABLE_LEVELS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x40D*/ { "CMSG_GRANT_LEVEL", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x40E*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x40F*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelDeclineInvite },
+ /*0x410*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x411*/ { "CMSG_GROUPACTION_THROTTLED", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x412*/ { "SMSG_OVERRIDE_LIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x413*/ { "SMSG_TOTEM_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x414*/ { "CMSG_TOTEM_DESTROYED", STATUS_LOGGEDIN, &WorldSession::HandleTotemDestroy },
+ /*0x415*/ { "CMSG_EXPIRE_RAID_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x416*/ { "CMSG_NO_SPELL_VARIANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x417*/ { "CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverStatusQueryMultipleOpcode},
+ /*0x418*/ { "SMSG_QUESTGIVER_STATUS_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x419*/ { "CMSG_SET_PLAYER_DECLINED_NAMES", STATUS_AUTHED, &WorldSession::HandleDeclinedPlayerNameOpcode },
+ /*0x41A*/ { "SMSG_SET_PLAYER_DECLINED_NAMES_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x41B*/ { "CMSG_QUERY_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x41C*/ { "CMSG_CLEAR_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x41D*/ { "SMSG_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x41E*/ { "SMSG_SEND_UNLEARN_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x41F*/ { "SMSG_PROPOSE_LEVEL_GRANT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x420*/ { "CMSG_ACCEPT_LEVEL_GRANT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x421*/ { "SMSG_REFER_A_FRIEND_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x422*/ { "SMSG_SPLINE_MOVE_SET_FLYING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x423*/ { "SMSG_SPLINE_MOVE_UNSET_FLYING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x424*/ { "SMSG_SUMMON_CANCEL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x425*/ { "CMSG_CHANGE_PERSONAL_ARENA_RATING", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x426*/ { "CMSG_ALTER_APPEARANCE", STATUS_LOGGEDIN, &WorldSession::HandleAlterAppearance },
+ /*0x427*/ { "SMSG_ENABLE_BARBER_SHOP", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x428*/ { "SMSG_BARBER_SHOP_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x429*/ { "CMSG_CALENDAR_GET_CALENDAR", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetCalendar },
+ /*0x42A*/ { "CMSG_CALENDAR_GET_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetEvent },
+ /*0x42B*/ { "CMSG_CALENDAR_GUILD_FILTER", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGuildFilter },
+ /*0x42C*/ { "CMSG_CALENDAR_ARENA_TEAM", STATUS_LOGGEDIN, &WorldSession::HandleCalendarArenaTeam },
+ /*0x42D*/ { "CMSG_CALENDAR_ADD_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarAddEvent },
+ /*0x42E*/ { "CMSG_CALENDAR_UPDATE_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarUpdateEvent },
+ /*0x42F*/ { "CMSG_CALENDAR_REMOVE_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarRemoveEvent },
+ /*0x430*/ { "CMSG_CALENDAR_COPY_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarCopyEvent },
+ /*0x431*/ { "CMSG_CALENDAR_EVENT_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventInvite },
+ /*0x432*/ { "CMSG_CALENDAR_EVENT_RSVP", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventRsvp },
+ /*0x433*/ { "CMSG_CALENDAR_EVENT_REMOVE_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventRemoveInvite },
+ /*0x434*/ { "CMSG_CALENDAR_EVENT_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventStatus },
+ /*0x435*/ { "CMSG_CALENDAR_EVENT_MODERATOR_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventModeratorStatus},
+ /*0x436*/ { "SMSG_CALENDAR_SEND_CALENDAR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x437*/ { "SMSG_CALENDAR_SEND_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x438*/ { "SMSG_CALENDAR_FILTER_GUILD", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x439*/ { "SMSG_CALENDAR_ARENA_TEAM", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x43A*/ { "SMSG_CALENDAR_EVENT_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x43B*/ { "SMSG_CALENDAR_EVENT_INVITE_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x43C*/ { "SMSG_CALENDAR_EVENT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x43D*/ { "SMSG_CALENDAR_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x43E*/ { "SMSG_CALENDAR_RAID_LOCKOUT_ADDED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x43F*/ { "SMSG_CALENDAR_RAID_LOCKOUT_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x440*/ { "SMSG_CALENDAR_EVENT_INVITE_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x441*/ { "SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x442*/ { "SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x443*/ { "SMSG_CALENDAR_EVENT_REMOVED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x444*/ { "SMSG_CALENDAR_EVENT_UPDATED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x445*/ { "SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x446*/ { "CMSG_CALENDAR_COMPLAIN", STATUS_LOGGEDIN, &WorldSession::HandleCalendarComplain },
+ /*0x447*/ { "CMSG_CALENDAR_GET_NUM_PENDING", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetNumPending },
+ /*0x448*/ { "SMSG_CALENDAR_SEND_NUM_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x449*/ { "CMSG_SAVE_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x44A*/ { "SMSG_NOTIFY_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x44B*/ { "CMSG_PLAY_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x44C*/ { "SMSG_PLAY_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x44D*/ { "CMSG_LOAD_DANCES", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x44E*/ { "CMSG_STOP_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x44F*/ { "SMSG_STOP_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x450*/ { "CMSG_SYNC_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x451*/ { "CMSG_DANCE_QUERY", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x452*/ { "SMSG_DANCE_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x453*/ { "SMSG_INVALIDATE_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x454*/ { "CMSG_DELETE_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x455*/ { "SMSG_LEARNED_DANCE_MOVES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x456*/ { "CMSG_LEARN_DANCE_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x457*/ { "CMSG_UNLEARN_DANCE_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x458*/ { "CMSG_SET_RUNE_COUNT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x459*/ { "CMSG_SET_RUNE_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x45A*/ { "MSG_MOVE_SET_PITCH_RATE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x45B*/ { "MSG_MOVE_SET_PITCH_RATE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x45C*/ { "SMSG_FORCE_PITCH_RATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x45D*/ { "CMSG_FORCE_PITCH_RATE_CHANGE_ACK", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x45E*/ { "SMSG_SPLINE_SET_PITCH_RATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x45F*/ { "SMSG_MOVE_ABANDON_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x460*/ { "MSG_MOVE_ABANDON_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x461*/ { "CMSG_MOVE_ABANDON_TRANSPORT_ACK", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x462*/ { "CMSG_UPDATE_MISSILE_TRAJECTORY", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x463*/ { "SMSG_UPDATE_ACCOUNT_DATA_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x464*/ { "SMSG_TRIGGER_MOVIE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x465*/ { "CMSG_COMPLETE_MOVIE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x466*/ { "CMSG_SET_GLYPH_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x467*/ { "CMSG_SET_GLYPH", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x468*/ { "SMSG_ACHIEVEMENT_EARNED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x469*/ { "SMSG_DYNAMIC_DROP_ROLL_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x46A*/ { "SMSG_CRITERIA_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x46B*/ { "CMSG_QUERY_INSPECT_ACHIEVEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleInspectAchievements },
+ /*0x46C*/ { "SMSG_RESPOND_INSPECT_ACHIEVEMENTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x46D*/ { "CMSG_DISMISS_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, &WorldSession::HandleDismissControlledVehicle },
+ /*0x46E*/ { "CMSG_COMPLETE_ACHIEVEMENT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x46F*/ { "SMSG_QUESTUPDATE_ADD_PVP_KILL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x470*/ { "CMSG_SET_CRITERIA_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x471*/ { "SMSG_GROUP_SWAP_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x472*/ { "CMSG_UNITANIMTIER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x473*/ { "CMSG_CHAR_CUSTOMIZE", STATUS_AUTHED, &WorldSession::HandleCharCustomize },
+ /*0x474*/ { "SMSG_CHAR_CUSTOMIZE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x475*/ { "SMSG_PET_RENAMEABLE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x476*/ { "CMSG_REQUEST_VEHICLE_EXIT", STATUS_LOGGEDIN, &WorldSession::HandleRequestVehicleExit },
+ /*0x477*/ { "CMSG_REQUEST_VEHICLE_PREV_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle},
+ /*0x478*/ { "CMSG_REQUEST_VEHICLE_NEXT_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle},
+ /*0x479*/ { "CMSG_REQUEST_VEHICLE_SWITCH_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle},
+ /*0x47A*/ { "CMSG_PET_LEARN_TALENT", STATUS_LOGGEDIN, &WorldSession::HandlePetLearnTalent },
+ /*0x47B*/ { "CMSG_PET_UNLEARN_TALENTS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x47C*/ { "SMSG_SET_PHASE_SHIFT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x47D*/ { "SMSG_ALL_ACHIEVEMENT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x47E*/ { "CMSG_FORCE_SAY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x47F*/ { "SMSG_HEALTH_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x480*/ { "SMSG_POWER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x481*/ { "CMSG_GAMEOBJ_REPORT_USE", STATUS_LOGGEDIN, &WorldSession::HandleGameobjectReportUse },
+ /*0x482*/ { "SMSG_HIGHEST_THREAT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x483*/ { "SMSG_THREAT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x484*/ { "SMSG_THREAT_REMOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x485*/ { "SMSG_THREAT_CLEAR", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x486*/ { "SMSG_CONVERT_RUNE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x487*/ { "SMSG_RESYNC_RUNES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x488*/ { "SMSG_ADD_RUNE_POWER", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x489*/ { "CMSG_START_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x48A*/ { "CMSG_REMOVE_GLYPH", STATUS_LOGGEDIN, &WorldSession::HandleRemoveGlyph },
+ /*0x48B*/ { "CMSG_DUMP_OBJECTS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x48C*/ { "SMSG_DUMP_OBJECTS_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x48D*/ { "CMSG_DISMISS_CRITTER", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x48E*/ { "SMSG_NOTIFY_DEST_LOC_SPELL_CAST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x48F*/ { "CMSG_AUCTION_LIST_PENDING_SALES", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListPendingSales },
+ /*0x490*/ { "SMSG_AUCTION_LIST_PENDING_SALES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x491*/ { "SMSG_MODIFY_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x492*/ { "SMSG_PET_UPDATE_COMBO_POINTS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x493*/ { "CMSG_ENABLETAXI", STATUS_LOGGEDIN, &WorldSession::HandleTaxiQueryAvailableNodes },
+ /*0x494*/ { "SMSG_PRE_RESURRECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x495*/ { "SMSG_AURA_UPDATE_ALL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x496*/ { "SMSG_AURA_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x497*/ { "CMSG_FLOOD_GRACE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x498*/ { "SMSG_SERVER_FIRST_ACHIEVEMENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x499*/ { "SMSG_PET_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x49A*/ { "SMSG_PET_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x49B*/ { "CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle},
+ /*0x49C*/ { "CMSG_HEARTH_AND_RESURRECT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x49D*/ { "SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x49E*/ { "SMSG_CRITERIA_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x49F*/ { "SMSG_ACHIEVEMENT_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x4A0*/ { "CMSG_SERVER_INFO_QUERY", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x4A1*/ { "SMSG_SERVER_INFO_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x4A2*/ { "CMSG_CHECK_LOGIN_CRITERIA", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x4A3*/ { "SMSG_SERVER_BUCK_DATA_START", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x4A4*/ { "CMSG_QUERY_VEHICLE_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x4A5*/ { "SMSG_PET_GUIDS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x4A6*/ { "SMSG_CLIENTCACHE_VERSION", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x4A7*/ { "UMSG_UNKNOWN_1191", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x4A8*/ { "UMSG_UNKNOWN_1192", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x4A9*/ { "UMSG_UNKNOWN_1193", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x4AA*/ { "UMSG_UNKNOWN_1194", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x4AB*/ { "UMSG_UNKNOWN_1195", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x4AC*/ { "UMSG_UNKNOWN_1196", STATUS_NEVER, &WorldSession::Handle_NULL },
};
diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h
index 12f9c9459fa..d57cfd62852 100644
--- a/src/game/Opcodes.h
+++ b/src/game/Opcodes.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,8 +49,8 @@ enum Opcodes
CMSG_ZONE_MAP = 0x00A,
SMSG_ZONE_MAP = 0x00B,
CMSG_DEBUG_CHANGECELLZONE = 0x00C,
- CMSG_EMBLAZON_TABARD_OBSOLETE = 0x00D,
- CMSG_UNEMBLAZON_TABARD_OBSOLETE = 0x00E,
+ CMSG_MOVE_CHARACTER_CHEAT = 0x00D,
+ SMSG_MOVE_CHARACTER_CHEAT = 0x00E,
CMSG_RECHARGE = 0x00F,
CMSG_LEARN_SPELL = 0x010,
CMSG_CREATEMONSTER = 0x011,
@@ -66,7 +66,7 @@ enum Opcodes
SMSG_FORCEACTIONSHOW = 0x01B,
CMSG_PETGODMODE = 0x01C,
SMSG_PETGODMODE = 0x01D,
- SMSG_DEBUGINFOSPELLMISS_OBSOLETE = 0x01E,
+ SMSG_REFER_A_FRIEND_EXPIRED = 0x01E,
CMSG_WEATHER_SPEED_CHEAT = 0x01F,
CMSG_UNDRESSPLAYER = 0x020,
CMSG_BEASTMASTER = 0x021,
@@ -86,7 +86,7 @@ enum Opcodes
SMSG_DEBUG_AISTATE = 0x02F,
CMSG_DISABLE_PVP_CHEAT = 0x030,
CMSG_ADVANCE_SPAWN_TIME = 0x031,
- CMSG_PVP_PORT_OBSOLETE = 0x032,
+ SMSG_DESTRUCTIBLE_BUILDING_DAMAGE = 0x032,
CMSG_AUTH_SRP6_BEGIN = 0x033,
CMSG_AUTH_SRP6_PROOF = 0x034,
CMSG_AUTH_SRP6_RECODE = 0x035,
@@ -214,7 +214,7 @@ enum Opcodes
SMSG_READ_ITEM_FAILED = 0x0AF,
SMSG_ITEM_COOLDOWN = 0x0B0,
CMSG_GAMEOBJ_USE = 0x0B1,
- CMSG_GAMEOBJ_CHAIR_USE_OBSOLETE = 0x0B2,
+ CMSG_DESTROY_ITEMS = 0x0B2,
SMSG_GAMEOBJECT_CUSTOM_ANIM = 0x0B3,
CMSG_AREATRIGGER = 0x0B4,
MSG_MOVE_START_FORWARD = 0x0B5,
@@ -347,7 +347,7 @@ enum Opcodes
SMSG_SPELL_COOLDOWN = 0x134,
SMSG_COOLDOWN_EVENT = 0x135,
CMSG_CANCEL_AURA = 0x136,
- SMSG_UPDATE_AURA_DURATION = 0x137,
+ SMSG_UPDATE_AURA_DURATION_OBSOLETE = 0x137,
SMSG_PET_CAST_FAILED = 0x138,
MSG_CHANNEL_START = 0x139,
MSG_CHANNEL_UPDATE = 0x13A,
@@ -371,10 +371,10 @@ enum Opcodes
SMSG_DAMAGE_DONE_OBSOLETE = 0x14C,
SMSG_DAMAGE_TAKEN_OBSOLETE = 0x14D,
SMSG_CANCEL_COMBAT = 0x14E,
- SMSG_PLAYER_COMBAT_XP_GAIN_OBSOLETE = 0x14F,
+ SMSG_SPELLBREAKLOG = 0x14F,
SMSG_SPELLHEALLOG = 0x150,
SMSG_SPELLENERGIZELOG = 0x151,
- CMSG_SHEATHE_OBSOLETE = 0x152,
+ SMSG_BREAK_TARGET = 0x152,
CMSG_SAVE_PLAYER = 0x153,
CMSG_SETDEATHBINDPOINT = 0x154,
SMSG_BINDPOINTUPDATE = 0x155,
@@ -578,7 +578,7 @@ enum Opcodes
SMSG_GMTICKET_SYSTEMSTATUS = 0x21B,
CMSG_SPIRIT_HEALER_ACTIVATE = 0x21C,
CMSG_SET_STAT_CHEAT = 0x21D,
- SMSG_SET_REST_START = 0x21E,
+ SMSG_SET_REST_START_OBSOLETE = 0x21E,
CMSG_SKILL_BUY_STEP = 0x21F,
CMSG_SKILL_BUY_RANK = 0x220,
CMSG_XP_CHEAT = 0x221,
@@ -733,8 +733,8 @@ enum Opcodes
SMSG_SCRIPT_MESSAGE = 0x2B6,
SMSG_DUEL_COUNTDOWN = 0x2B7,
SMSG_AREA_TRIGGER_MESSAGE = 0x2B8,
- CMSG_TOGGLE_HELM = 0x2B9,
- CMSG_TOGGLE_CLOAK = 0x2BA,
+ CMSG_SHOWING_HELM = 0x2B9,
+ CMSG_SHOWING_CLOAK = 0x2BA,
SMSG_MEETINGSTONE_JOINFAILED = 0x2BB,
SMSG_PLAYER_SKINNED = 0x2BC,
SMSG_DURABILITY_DAMAGE_DEATH = 0x2BD,
@@ -967,10 +967,10 @@ enum Opcodes
SMSG_VOICE_SESSION_ADJUST_PRIORITY = 0x3A0,
CMSG_VOICE_SET_TALKER_MUTED_REQUEST = 0x3A1,
SMSG_VOICE_SET_TALKER_MUTED = 0x3A2,
- SMSG_INIT_EXTRA_AURA_INFO = 0x3A3,
- SMSG_SET_EXTRA_AURA_INFO = 0x3A4,
- SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE = 0x3A5,
- SMSG_CLEAR_EXTRA_AURA_INFO = 0x3A6,
+ SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE = 0x3A3,
+ SMSG_SET_EXTRA_AURA_INFO_OBSOLETE = 0x3A4,
+ SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE = 0x3A5,
+ SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE = 0x3A6,
MSG_MOVE_START_DESCEND = 0x3A7,
CMSG_IGNORE_REQUIREMENTS_CHEAT = 0x3A8,
SMSG_IGNORE_REQUIREMENTS_CHEAT = 0x3A9,
@@ -980,127 +980,262 @@ enum Opcodes
MSG_MOVE_UPDATE_CAN_FLY = 0x3AD,
MSG_RAID_READY_CHECK_CONFIRM = 0x3AE,
CMSG_VOICE_SESSION_ENABLE = 0x3AF,
- SMSG_VOICE_PARENTAL_CONTROLS = 0x3B0,
- CMSG_GM_WHISPER = 0x3B1,
- SMSG_GM_MESSAGECHAT = 0x3B2,
- MSG_GM_GEARRATING = 0x3B3,
- CMSG_COMMENTATOR_ENABLE = 0x3B4,
- SMSG_COMMENTATOR_STATE_CHANGED = 0x3B5,
- CMSG_COMMENTATOR_GET_MAP_INFO = 0x3B6,
- SMSG_COMMENTATOR_MAP_INFO = 0x3B7,
- CMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3B8,
- SMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3B9,
- SMSG_COMMENTATOR_PLAYER_INFO = 0x3BA,
- CMSG_COMMENTATOR_ENTER_INSTANCE = 0x3BB,
- CMSG_COMMENTATOR_EXIT_INSTANCE = 0x3BC,
- CMSG_COMMENTATOR_INSTANCE_COMMAND = 0x3BD,
- SMSG_CLEAR_TARGET = 0x3BE,
- CMSG_BOT_DETECTED = 0x3BF,
- SMSG_CROSSED_INEBRIATION_THRESHOLD = 0x3C0,
- CMSG_CHEAT_PLAYER_LOGIN = 0x3C1,
- CMSG_CHEAT_PLAYER_LOOKUP = 0x3C2,
- SMSG_CHEAT_PLAYER_LOOKUP = 0x3C3,
- SMSG_KICK_REASON = 0x3C4,
- MSG_RAID_READY_CHECK_FINISHED = 0x3C5,
- CMSG_COMPLAIN = 0x3C6,
- SMSG_COMPLAIN_RESULT = 0x3C7,
- SMSG_FEATURE_SYSTEM_STATUS = 0x3C8,
- CMSG_GM_SHOW_COMPLAINTS = 0x3C9,
- CMSG_GM_UNSQUELCH = 0x3CA,
- CMSG_CHANNEL_SILENCE_VOICE = 0x3CB,
- CMSG_CHANNEL_SILENCE_ALL = 0x3CC,
- CMSG_CHANNEL_UNSILENCE_VOICE = 0x3CD,
- CMSG_CHANNEL_UNSILENCE_ALL = 0x3CE,
- CMSG_TARGET_CAST = 0x3CF,
- CMSG_TARGET_SCRIPT_CAST = 0x3D0,
- CMSG_CHANNEL_DISPLAY_LIST = 0x3D1,
- CMSG_SET_ACTIVE_VOICE_CHANNEL = 0x3D2,
- CMSG_GET_CHANNEL_MEMBER_COUNT = 0x3D3,
- SMSG_CHANNEL_MEMBER_COUNT = 0x3D4,
- CMSG_CHANNEL_VOICE_ON = 0x3D5,
- CMSG_CHANNEL_VOICE_OFF = 0x3D6,
- CMSG_DEBUG_LIST_TARGETS = 0x3D7,
- SMSG_DEBUG_LIST_TARGETS = 0x3D8,
- SMSG_AVAILABLE_VOICE_CHANNEL = 0x3D9,
- CMSG_ADD_VOICE_IGNORE = 0x3DA,
- CMSG_DEL_VOICE_IGNORE = 0x3DB,
- CMSG_PARTY_SILENCE = 0x3DC,
- CMSG_PARTY_UNSILENCE = 0x3DD,
- MSG_NOTIFY_PARTY_SQUELCH = 0x3DE,
- SMSG_COMSAT_RECONNECT_TRY = 0x3DF,
- SMSG_COMSAT_DISCONNECT = 0x3E0,
- SMSG_COMSAT_CONNECT_FAIL = 0x3E1,
- SMSG_VOICE_CHAT_STATUS = 0x3E2,
- CMSG_REPORT_PVP_AFK = 0x3E3,
- CMSG_REPORT_PVP_AFK_RESULT = 0x3E4,
- CMSG_GUILD_BANKER_ACTIVATE = 0x3E5,
- CMSG_GUILD_BANK_QUERY_TAB = 0x3E6,
- SMSG_GUILD_BANK_LIST = 0x3E7,
- CMSG_GUILD_BANK_SWAP_ITEMS = 0x3E8,
- CMSG_GUILD_BANK_BUY_TAB = 0x3E9,
- CMSG_GUILD_BANK_UPDATE_TAB = 0x3EA,
- CMSG_GUILD_BANK_DEPOSIT_MONEY = 0x3EB,
- CMSG_GUILD_BANK_WITHDRAW_MONEY = 0x3EC,
- MSG_GUILD_BANK_LOG_QUERY = 0x3ED,
- CMSG_SET_CHANNEL_WATCH = 0x3EE,
- SMSG_USERLIST_ADD = 0x3EF,
- SMSG_USERLIST_REMOVE = 0x3F0,
- SMSG_USERLIST_UPDATE = 0x3F1,
- CMSG_CLEAR_CHANNEL_WATCH = 0x3F2,
- SMSG_INSPECT_TALENT = 0x3F3,
- SMSG_GOGOGO_OBSOLETE = 0x3F4,
- SMSG_ECHO_PARTY_SQUELCH = 0x3F5,
- CMSG_SET_TITLE_SUFFIX = 0x3F6,
- CMSG_SPELLCLICK = 0x3F7,
- SMSG_LOOT_LIST = 0x3F8,
- CMSG_GM_CHARACTER_RESTORE = 0x3F9,
- CMSG_GM_CHARACTER_SAVE = 0x3FA,
- SMSG_VOICESESSION_FULL = 0x3FB,
- MSG_GUILD_PERMISSIONS = 0x3FC,
- MSG_GUILD_BANK_MONEY_WITHDRAWN = 0x3FD,
- MSG_GUILD_EVENT_LOG_QUERY = 0x3FE,
- CMSG_MAELSTROM_RENAME_GUILD = 0x3FF,
- CMSG_GET_MIRRORIMAGE_DATA = 0x400,
- SMSG_MIRRORIMAGE_DATA = 0x401,
- SMSG_FORCE_DISPLAY_UPDATE = 0x402,
- SMSG_SPELL_CHANCE_RESIST_PUSHBACK = 0x403,
- CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x404,
- SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x405,
- CMSG_KEEP_ALIVE = 0x406,
- SMSG_RAID_READY_CHECK_ERROR = 0x407,
- CMSG_OPT_OUT_OF_LOOT = 0x408,
- MSG_QUERY_GUILD_BANK_TEXT = 0x409,
- CMSG_SET_GUILD_BANK_TEXT = 0x40A,
- CMSG_SET_GRANTABLE_LEVELS = 0x40B,
- CMSG_GRANT_LEVEL = 0x40C,
- CMSG_REFER_A_FRIEND = 0x40D,
- MSG_GM_CHANGE_ARENA_RATING = 0x40E,
- CMSG_DECLINE_CHANNEL_INVITE = 0x40F,
- CMSG_GROUPACTION_THROTTLED = 0x410,
- SMSG_OVERRIDE_LIGHT = 0x411,
- SMSG_TOTEM_CREATED = 0x412,
- CMSG_TOTEM_DESTROYED = 0x413,
- CMSG_EXPIRE_RAID_INSTANCE = 0x414,
- CMSG_NO_SPELL_VARIANCE = 0x415,
- CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x416,
- SMSG_QUESTGIVER_STATUS_MULTIPLE = 0x417,
- CMSG_SET_PLAYER_DECLINED_NAMES = 0x418,
- SMSG_SET_PLAYER_DECLINED_NAMES_RESULT = 0x419,
- CMSG_QUERY_SERVER_BUCK_DATA = 0x41A,
- CMSG_CLEAR_SERVER_BUCK_DATA = 0x41B,
- SMSG_SERVER_BUCK_DATA = 0x41C,
- SMSG_SEND_UNLEARN_SPELLS = 0x41D,
- SMSG_PROPOSE_LEVEL_GRANT = 0x41E,
- CMSG_ACCEPT_LEVEL_GRANT = 0x41F,
- SMSG_REFER_A_FRIEND_FAILURE = 0x420,
- SMSG_SPLINE_MOVE_SET_FLYING = 0x421,
- SMSG_SPLINE_MOVE_UNSET_FLYING = 0x422,
- SMSG_SUMMON_CANCEL = 0x423
+ SMSG_VOICE_SESSION_ENABLE = 0x3B0,
+ SMSG_VOICE_PARENTAL_CONTROLS = 0x3B1,
+ CMSG_GM_WHISPER = 0x3B2,
+ SMSG_GM_MESSAGECHAT = 0x3B3,
+ MSG_GM_GEARRATING = 0x3B4,
+ CMSG_COMMENTATOR_ENABLE = 0x3B5,
+ SMSG_COMMENTATOR_STATE_CHANGED = 0x3B6,
+ CMSG_COMMENTATOR_GET_MAP_INFO = 0x3B7,
+ SMSG_COMMENTATOR_MAP_INFO = 0x3B8,
+ CMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3B9,
+ SMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3BA,
+ SMSG_COMMENTATOR_PLAYER_INFO = 0x3BB,
+ CMSG_COMMENTATOR_ENTER_INSTANCE = 0x3BC,
+ CMSG_COMMENTATOR_EXIT_INSTANCE = 0x3BD,
+ CMSG_COMMENTATOR_INSTANCE_COMMAND = 0x3BE,
+ SMSG_CLEAR_TARGET = 0x3BF,
+ CMSG_BOT_DETECTED = 0x3C0,
+ SMSG_CROSSED_INEBRIATION_THRESHOLD = 0x3C1,
+ CMSG_CHEAT_PLAYER_LOGIN = 0x3C2,
+ CMSG_CHEAT_PLAYER_LOOKUP = 0x3C3,
+ SMSG_CHEAT_PLAYER_LOOKUP = 0x3C4,
+ SMSG_KICK_REASON = 0x3C5,
+ MSG_RAID_READY_CHECK_FINISHED = 0x3C6,
+ CMSG_COMPLAIN = 0x3C7,
+ SMSG_COMPLAIN_RESULT = 0x3C8,
+ SMSG_FEATURE_SYSTEM_STATUS = 0x3C9,
+ CMSG_GM_SHOW_COMPLAINTS = 0x3CA,
+ CMSG_GM_UNSQUELCH = 0x3CB,
+ CMSG_CHANNEL_SILENCE_VOICE = 0x3CC,
+ CMSG_CHANNEL_SILENCE_ALL = 0x3CD,
+ CMSG_CHANNEL_UNSILENCE_VOICE = 0x3CE,
+ CMSG_CHANNEL_UNSILENCE_ALL = 0x3CF,
+ CMSG_TARGET_CAST = 0x3D0,
+ CMSG_TARGET_SCRIPT_CAST = 0x3D1,
+ CMSG_CHANNEL_DISPLAY_LIST = 0x3D2,
+ CMSG_SET_ACTIVE_VOICE_CHANNEL = 0x3D3,
+ CMSG_GET_CHANNEL_MEMBER_COUNT = 0x3D4,
+ SMSG_CHANNEL_MEMBER_COUNT = 0x3D5,
+ CMSG_CHANNEL_VOICE_ON = 0x3D6,
+ CMSG_CHANNEL_VOICE_OFF = 0x3D7,
+ CMSG_DEBUG_LIST_TARGETS = 0x3D8,
+ SMSG_DEBUG_LIST_TARGETS = 0x3D9,
+ SMSG_AVAILABLE_VOICE_CHANNEL = 0x3DA,
+ CMSG_ADD_VOICE_IGNORE = 0x3DB,
+ CMSG_DEL_VOICE_IGNORE = 0x3DC,
+ CMSG_PARTY_SILENCE = 0x3DD,
+ CMSG_PARTY_UNSILENCE = 0x3DE,
+ MSG_NOTIFY_PARTY_SQUELCH = 0x3DF,
+ SMSG_COMSAT_RECONNECT_TRY = 0x3E0,
+ SMSG_COMSAT_DISCONNECT = 0x3E1,
+ SMSG_COMSAT_CONNECT_FAIL = 0x3E2,
+ SMSG_VOICE_CHAT_STATUS = 0x3E3,
+ CMSG_REPORT_PVP_AFK = 0x3E4,
+ CMSG_REPORT_PVP_AFK_RESULT = 0x3E5,
+ CMSG_GUILD_BANKER_ACTIVATE = 0x3E6,
+ CMSG_GUILD_BANK_QUERY_TAB = 0x3E7,
+ SMSG_GUILD_BANK_LIST = 0x3E8,
+ CMSG_GUILD_BANK_SWAP_ITEMS = 0x3E9,
+ CMSG_GUILD_BANK_BUY_TAB = 0x3EA,
+ CMSG_GUILD_BANK_UPDATE_TAB = 0x3EB,
+ CMSG_GUILD_BANK_DEPOSIT_MONEY = 0x3EC,
+ CMSG_GUILD_BANK_WITHDRAW_MONEY = 0x3ED,
+ MSG_GUILD_BANK_LOG_QUERY = 0x3EE,
+ CMSG_SET_CHANNEL_WATCH = 0x3EF,
+ SMSG_USERLIST_ADD = 0x3F0,
+ SMSG_USERLIST_REMOVE = 0x3F1,
+ SMSG_USERLIST_UPDATE = 0x3F2,
+ CMSG_CLEAR_CHANNEL_WATCH = 0x3F3,
+ SMSG_INSPECT_TALENT = 0x3F4,
+ SMSG_GOGOGO_OBSOLETE = 0x3F5,
+ SMSG_ECHO_PARTY_SQUELCH = 0x3F6,
+ CMSG_SET_TITLE_SUFFIX = 0x3F7,
+ CMSG_SPELLCLICK = 0x3F8,
+ SMSG_LOOT_LIST = 0x3F9,
+ CMSG_GM_CHARACTER_RESTORE = 0x3FA,
+ CMSG_GM_CHARACTER_SAVE = 0x3FB,
+ SMSG_VOICESESSION_FULL = 0x3FC,
+ MSG_GUILD_PERMISSIONS = 0x3FD,
+ MSG_GUILD_BANK_MONEY_WITHDRAWN = 0x3FE,
+ MSG_GUILD_EVENT_LOG_QUERY = 0x3FF,
+ CMSG_MAELSTROM_RENAME_GUILD = 0x400,
+ CMSG_GET_MIRRORIMAGE_DATA = 0x401,
+ SMSG_MIRRORIMAGE_DATA = 0x402,
+ SMSG_FORCE_DISPLAY_UPDATE = 0x403,
+ SMSG_SPELL_CHANCE_RESIST_PUSHBACK = 0x404,
+ CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x405,
+ SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x406,
+ CMSG_KEEP_ALIVE = 0x407,
+ SMSG_RAID_READY_CHECK_ERROR = 0x408,
+ CMSG_OPT_OUT_OF_LOOT = 0x409,
+ MSG_QUERY_GUILD_BANK_TEXT = 0x40A,
+ CMSG_SET_GUILD_BANK_TEXT = 0x40B,
+ CMSG_SET_GRANTABLE_LEVELS = 0x40C,
+ CMSG_GRANT_LEVEL = 0x40D,
+ CMSG_REFER_A_FRIEND = 0x40E,
+ MSG_GM_CHANGE_ARENA_RATING = 0x40F,
+ CMSG_DECLINE_CHANNEL_INVITE = 0x410,
+ CMSG_GROUPACTION_THROTTLED = 0x411,
+ SMSG_OVERRIDE_LIGHT = 0x412,
+ SMSG_TOTEM_CREATED = 0x413,
+ CMSG_TOTEM_DESTROYED = 0x414,
+ CMSG_EXPIRE_RAID_INSTANCE = 0x415,
+ CMSG_NO_SPELL_VARIANCE = 0x416,
+ CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x417,
+ SMSG_QUESTGIVER_STATUS_MULTIPLE = 0x418,
+ CMSG_SET_PLAYER_DECLINED_NAMES = 0x419,
+ SMSG_SET_PLAYER_DECLINED_NAMES_RESULT = 0x41A,
+ CMSG_QUERY_SERVER_BUCK_DATA = 0x41B,
+ CMSG_CLEAR_SERVER_BUCK_DATA = 0x41C,
+ SMSG_SERVER_BUCK_DATA = 0x41D,
+ SMSG_SEND_UNLEARN_SPELLS = 0x41E,
+ SMSG_PROPOSE_LEVEL_GRANT = 0x41F,
+ CMSG_ACCEPT_LEVEL_GRANT = 0x420,
+ SMSG_REFER_A_FRIEND_FAILURE = 0x421,
+ SMSG_SPLINE_MOVE_SET_FLYING = 0x422,
+ SMSG_SPLINE_MOVE_UNSET_FLYING = 0x423,
+ SMSG_SUMMON_CANCEL = 0x424,
+ CMSG_CHANGE_PERSONAL_ARENA_RATING = 0x425,
+ CMSG_ALTER_APPEARANCE = 0x426,
+ SMSG_ENABLE_BARBER_SHOP = 0x427,
+ SMSG_BARBER_SHOP_RESULT = 0x428,
+ CMSG_CALENDAR_GET_CALENDAR = 0x429,
+ CMSG_CALENDAR_GET_EVENT = 0x42A,
+ CMSG_CALENDAR_GUILD_FILTER = 0x42B,
+ CMSG_CALENDAR_ARENA_TEAM = 0x42C,
+ CMSG_CALENDAR_ADD_EVENT = 0x42D,
+ CMSG_CALENDAR_UPDATE_EVENT = 0x42E,
+ CMSG_CALENDAR_REMOVE_EVENT = 0x42F,
+ CMSG_CALENDAR_COPY_EVENT = 0x430,
+ CMSG_CALENDAR_EVENT_INVITE = 0x431,
+ CMSG_CALENDAR_EVENT_RSVP = 0x432,
+ CMSG_CALENDAR_EVENT_REMOVE_INVITE = 0x433,
+ CMSG_CALENDAR_EVENT_STATUS = 0x434,
+ CMSG_CALENDAR_EVENT_MODERATOR_STATUS = 0x435,
+ SMSG_CALENDAR_SEND_CALENDAR = 0x436,
+ SMSG_CALENDAR_SEND_EVENT = 0x437,
+ SMSG_CALENDAR_FILTER_GUILD = 0x438,
+ SMSG_CALENDAR_ARENA_TEAM = 0x439,
+ SMSG_CALENDAR_EVENT_INVITE = 0x43A,
+ SMSG_CALENDAR_EVENT_INVITE_REMOVED = 0x43B,
+ SMSG_CALENDAR_EVENT_STATUS = 0x43C,
+ SMSG_CALENDAR_COMMAND_RESULT = 0x43D,
+ SMSG_CALENDAR_RAID_LOCKOUT_ADDED = 0x43E,
+ SMSG_CALENDAR_RAID_LOCKOUT_REMOVED = 0x43F,
+ SMSG_CALENDAR_EVENT_INVITE_ALERT = 0x440,
+ SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT = 0x441,
+ SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT = 0x442,
+ SMSG_CALENDAR_EVENT_REMOVED_ALERT = 0x443,
+ SMSG_CALENDAR_EVENT_UPDATED_ALERT = 0x444,
+ SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT = 0x445,
+ CMSG_CALENDAR_COMPLAIN = 0x446,
+ CMSG_CALENDAR_GET_NUM_PENDING = 0x447,
+ SMSG_CALENDAR_SEND_NUM_PENDING = 0x448,
+ CMSG_SAVE_DANCE = 0x449,
+ SMSG_NOTIFY_DANCE = 0x44A,
+ CMSG_PLAY_DANCE = 0x44B,
+ SMSG_PLAY_DANCE = 0x44C,
+ CMSG_LOAD_DANCES = 0x44D,
+ CMSG_STOP_DANCE = 0x44E,
+ SMSG_STOP_DANCE = 0x44F,
+ CMSG_SYNC_DANCE = 0x450,
+ CMSG_DANCE_QUERY = 0x451,
+ SMSG_DANCE_QUERY_RESPONSE = 0x452,
+ SMSG_INVALIDATE_DANCE = 0x453,
+ CMSG_DELETE_DANCE = 0x454,
+ SMSG_LEARNED_DANCE_MOVES = 0x455,
+ CMSG_LEARN_DANCE_MOVE = 0x456,
+ CMSG_UNLEARN_DANCE_MOVE = 0x457,
+ CMSG_SET_RUNE_COUNT = 0x458,
+ CMSG_SET_RUNE_COOLDOWN = 0x459,
+ MSG_MOVE_SET_PITCH_RATE_CHEAT = 0x45A,
+ MSG_MOVE_SET_PITCH_RATE = 0x45B,
+ SMSG_FORCE_PITCH_RATE_CHANGE = 0x45C,
+ CMSG_FORCE_PITCH_RATE_CHANGE_ACK = 0x45D,
+ SMSG_SPLINE_SET_PITCH_RATE = 0x45E,
+ SMSG_MOVE_ABANDON_TRANSPORT = 0x45F,
+ MSG_MOVE_ABANDON_TRANSPORT = 0x460,
+ CMSG_MOVE_ABANDON_TRANSPORT_ACK = 0x461,
+ CMSG_UPDATE_MISSILE_TRAJECTORY = 0x462,
+ SMSG_UPDATE_ACCOUNT_DATA_COMPLETE = 0x463,
+ SMSG_TRIGGER_MOVIE = 0x464,
+ CMSG_COMPLETE_MOVIE = 0x465,
+ CMSG_SET_GLYPH_SLOT = 0x466,
+ CMSG_SET_GLYPH = 0x467,
+ SMSG_ACHIEVEMENT_EARNED = 0x468,
+ SMSG_DYNAMIC_DROP_ROLL_RESULT = 0x469,
+ SMSG_CRITERIA_UPDATE = 0x46A,
+ CMSG_QUERY_INSPECT_ACHIEVEMENTS = 0x46B,
+ SMSG_RESPOND_INSPECT_ACHIEVEMENTS = 0x46C,
+ CMSG_DISMISS_CONTROLLED_VEHICLE = 0x46D,
+ CMSG_COMPLETE_ACHIEVEMENT_CHEAT = 0x46E,
+ SMSG_QUESTUPDATE_ADD_PVP_KILL = 0x46F,
+ CMSG_SET_CRITERIA_CHEAT = 0x470,
+ SMSG_GROUP_SWAP_FAILED = 0x471,
+ CMSG_UNITANIMTIER_CHEAT = 0x472,
+ CMSG_CHAR_CUSTOMIZE = 0x473,
+ SMSG_CHAR_CUSTOMIZE = 0x474,
+ SMSG_PET_RENAMEABLE = 0x475,
+ CMSG_REQUEST_VEHICLE_EXIT = 0x476,
+ CMSG_REQUEST_VEHICLE_PREV_SEAT = 0x477,
+ CMSG_REQUEST_VEHICLE_NEXT_SEAT = 0x478,
+ CMSG_REQUEST_VEHICLE_SWITCH_SEAT = 0x479,
+ CMSG_PET_LEARN_TALENT = 0x47A,
+ CMSG_PET_UNLEARN_TALENTS = 0x47B,
+ SMSG_SET_PHASE_SHIFT = 0x47C,
+ SMSG_ALL_ACHIEVEMENT_DATA = 0x47D,
+ CMSG_FORCE_SAY_CHEAT = 0x47E,
+ SMSG_HEALTH_UPDATE = 0x47F,
+ SMSG_POWER_UPDATE = 0x480,
+ CMSG_GAMEOBJ_REPORT_USE = 0x481,
+ SMSG_HIGHEST_THREAT_UPDATE = 0x482,
+ SMSG_THREAT_UPDATE = 0x483,
+ SMSG_THREAT_REMOVE = 0x484,
+ SMSG_THREAT_CLEAR = 0x485,
+ SMSG_CONVERT_RUNE = 0x486,
+ SMSG_RESYNC_RUNES = 0x487,
+ SMSG_ADD_RUNE_POWER = 0x488,
+ CMSG_START_QUEST = 0x489,
+ CMSG_REMOVE_GLYPH = 0x48A,
+ CMSG_DUMP_OBJECTS = 0x48B,
+ SMSG_DUMP_OBJECTS_DATA = 0x48C,
+ CMSG_DISMISS_CRITTER = 0x48D,
+ SMSG_NOTIFY_DEST_LOC_SPELL_CAST = 0x48E,
+ CMSG_AUCTION_LIST_PENDING_SALES = 0x48F,
+ SMSG_AUCTION_LIST_PENDING_SALES = 0x490,
+ SMSG_MODIFY_COOLDOWN = 0x491,
+ SMSG_PET_UPDATE_COMBO_POINTS = 0x492,
+ CMSG_ENABLETAXI = 0x493,
+ SMSG_PRE_RESURRECT = 0x494,
+ SMSG_AURA_UPDATE_ALL = 0x495,
+ SMSG_AURA_UPDATE = 0x496,
+ CMSG_FLOOD_GRACE_CHEAT = 0x497,
+ SMSG_SERVER_FIRST_ACHIEVEMENT = 0x498,
+ SMSG_PET_LEARNED_SPELL = 0x499,
+ SMSG_PET_REMOVED_SPELL = 0x49A,
+ CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE = 0x49B,
+ CMSG_HEARTH_AND_RESURRECT = 0x49C,
+ SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA = 0x49D,
+ SMSG_CRITERIA_DELETED = 0x49E,
+ SMSG_ACHIEVEMENT_DELETED = 0x49F,
+ CMSG_SERVER_INFO_QUERY = 0x4A0,
+ SMSG_SERVER_INFO_RESPONSE = 0x4A1,
+ CMSG_CHECK_LOGIN_CRITERIA = 0x4A2,
+ SMSG_SERVER_BUCK_DATA_START = 0x4A3,
+ CMSG_QUERY_VEHICLE_STATUS = 0x4A4,
+ SMSG_PET_GUIDS = 0x4A5,
+ SMSG_CLIENTCACHE_VERSION = 0x4A6,
+ UMSG_UNKNOWN_1191 = 0x4A7,
+ UMSG_UNKNOWN_1192 = 0x4A8,
+ UMSG_UNKNOWN_1193 = 0x4A9,
+ UMSG_UNKNOWN_1194 = 0x4AA,
+ UMSG_UNKNOWN_1195 = 0x4AB,
+ UMSG_UNKNOWN_1196 = 0x4AC,
+ NUM_MSG_TYPES = 0x4AD
};
-// Don't forget to change this value and add opcode name to Opcodes.cpp when you add new opcode!
-#define NUM_MSG_TYPES 0x424
-
/// Player state
enum SessionStatus
{
diff --git a/src/game/OutdoorPvP.cpp b/src/game/OutdoorPvP.cpp
index 17f08131197..bda04bf3799 100644
--- a/src/game/OutdoorPvP.cpp
+++ b/src/game/OutdoorPvP.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
*/
#include "OutdoorPvP.h"
+#include "OutdoorPvPImpl.h"
#include "OutdoorPvPMgr.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
@@ -83,7 +84,7 @@ bool OutdoorPvPObjective::AddObject(uint32 type, uint32 entry, uint32 map, float
data.spawntimesecs = 0;
data.animprogress = 100;
data.spawnMask = 1;
- data.go_state = 1;
+ data.go_state = GO_STATE_READY;
objmgr.AddGameobjectToGrid(guid, &data);
@@ -95,7 +96,7 @@ bool OutdoorPvPObjective::AddObject(uint32 type, uint32 entry, uint32 map, float
if(!pMap)
return true;
GameObject * go = new GameObject;
- if(!go->Create(guid,entry, pMap,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
+ if(!go->Create(guid,entry, pMap,PHASEMASK_NORMAL,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,GO_STATE_READY))
{
sLog.outError("Gameobject template %u not found in database.", entry);
delete go;
@@ -156,15 +157,13 @@ bool OutdoorPvPObjective::AddCreature(uint32 type, uint32 entry, uint32 teamval,
if(!pMap)
return true;
Creature* pCreature = new Creature;
- if (!pCreature->Create(guid, pMap, entry, teamval))
+ if (!pCreature->Create(guid, pMap, PHASEMASK_NORMAL, entry, teamval))
{
sLog.outError("Can't create creature entry: %u",entry);
delete pCreature;
- return true;
+ return false;
}
- pCreature->AIM_Initialize();
-
pCreature->Relocate(x, y, z, o);
if(!pCreature->IsPositionValid())
@@ -240,7 +239,7 @@ bool OutdoorPvPObjective::AddCapturePoint(uint32 entry, uint32 map, float x, flo
data.spawntimesecs = 1;
data.animprogress = 100;
data.spawnMask = 1;
- data.go_state = 1;
+ data.go_state = GO_STATE_READY;
objmgr.AddGameobjectToGrid(guid, &data);
@@ -257,7 +256,7 @@ bool OutdoorPvPObjective::AddCapturePoint(uint32 entry, uint32 map, float x, flo
return true;
// add GO...
GameObject * go = new GameObject;
- if(!go->Create(guid,entry, pMap,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
+ if(!go->Create(guid,entry, pMap,PHASEMASK_NORMAL,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,GO_STATE_READY))
{
sLog.outError("Gameobject template %u not found in database.", entry);
delete go;
@@ -270,15 +269,14 @@ bool OutdoorPvPObjective::AddCapturePoint(uint32 entry, uint32 map, float x, flo
}
// add creature...
Creature* pCreature = new Creature;
- if (!pCreature->Create(creature_guid, pMap, OPVP_TRIGGER_CREATURE_ENTRY, 0))
+ if (!pCreature->Create(creature_guid, pMap, PHASEMASK_NORMAL, OPVP_TRIGGER_CREATURE_ENTRY, 0))
{
sLog.outError("Can't create creature entry: %u",entry);
delete pCreature;
+ return false;
}
else
{
- pCreature->AIM_Initialize();
-
pCreature->Relocate(x, y, z, o);
if(!pCreature->IsPositionValid())
@@ -317,8 +315,8 @@ bool OutdoorPvPObjective::DelCreature(uint32 type)
// explicit removal from map
// beats me why this is needed, but with the recent removal "cleanup" some creatures stay in the map if "properly" deleted
// so this is a big fat workaround, if AddObjectToRemoveList and DoDelayedMovesAndRemoves worked correctly, this wouldn't be needed
- if(Map * map = MapManager::Instance().FindMap(cr->GetMapId()))
- map->Remove(cr,false);
+ //if(Map * map = MapManager::Instance().FindMap(cr->GetMapId()))
+ // map->Remove(cr,false);
// delete respawn time for this creature
WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u'", guid);
cr->AddObjectToRemoveList();
@@ -375,8 +373,8 @@ bool OutdoorPvPObjective::DelCapturePoint()
// explicit removal from map
// beats me why this is needed, but with the recent removal "cleanup" some creatures stay in the map if "properly" deleted
// so this is a big fat workaround, if AddObjectToRemoveList and DoDelayedMovesAndRemoves worked correctly, this wouldn't be needed
- if(Map * map = MapManager::Instance().FindMap(cr->GetMapId()))
- map->Remove(cr,false);
+ //if(Map * map = MapManager::Instance().FindMap(cr->GetMapId()))
+ // map->Remove(cr,false);
// delete respawn time for this creature
WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u'", guid);
cr->AddObjectToRemoveList();
@@ -413,10 +411,7 @@ OutdoorPvP::~OutdoorPvP()
void OutdoorPvP::HandlePlayerEnterZone(Player * plr, uint32 zone)
{
- if(plr->GetTeam()==ALLIANCE)
- m_PlayerGuids[0].insert(plr->GetGUID());
- else
- m_PlayerGuids[1].insert(plr->GetGUID());
+ m_players[TEAM_ID(plr->GetTeam())].insert(plr);
}
void OutdoorPvP::HandlePlayerLeaveZone(Player * plr, uint32 zone)
@@ -425,13 +420,10 @@ void OutdoorPvP::HandlePlayerLeaveZone(Player * plr, uint32 zone)
for(OutdoorPvPObjectiveSet::iterator itr = m_OutdoorPvPObjectives.begin(); itr != m_OutdoorPvPObjectives.end(); ++itr)
(*itr)->HandlePlayerLeave(plr);
// remove the world state information from the player (we can't keep everyone up to date, so leave out those who are not in the concerning zones)
- if(zone != plr->GetZoneId())
+ if(!plr->GetSession()->PlayerLogout())
SendRemoveWorldStates(plr);
- if(plr->GetTeam()==ALLIANCE)
- m_PlayerGuids[0].erase(plr->GetGUID());
- else
- m_PlayerGuids[1].erase(plr->GetGUID());
- sLog.outDebug("player left an outdoorpvp zone");
+ m_players[TEAM_ID(plr->GetTeam())].erase(plr);
+ sLog.outDebug("Player %s left an outdoorpvp zone");
}
bool OutdoorPvP::Update(uint32 diff)
@@ -572,14 +564,8 @@ void OutdoorPvP::SendUpdateWorldState(uint32 field, uint32 value)
for(int i = 0; i < 2; ++i)
{
// send to all players present in the area
- for(std::set<uint64>::iterator itr = m_PlayerGuids[i].begin(); itr != m_PlayerGuids[i].end(); ++itr)
- {
- Player * plr = objmgr.GetPlayer(*itr);
- if(plr)
- {
- plr->SendUpdateWorldState(field,value);
- }
- }
+ for(PlayerSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr)
+ (*itr)->SendUpdateWorldState(field,value);
}
}
@@ -779,3 +765,28 @@ bool OutdoorPvP::HandleAreaTrigger(Player *plr, uint32 trigger)
return false;
}
+void OutdoorPvP::RegisterZone(uint32 zoneId)
+{
+ sOutdoorPvPMgr.AddZone(zoneId, this);
+}
+
+bool OutdoorPvP::HasPlayer(Player *plr) const
+{
+ return m_players[TEAM_ID(plr->GetTeam())].find(plr) != m_players[TEAM_ID(plr->GetTeam())].end();
+}
+
+void OutdoorPvP::TeamCastSpell(TeamId team, int32 spellId)
+{
+ if(spellId > 0)
+ for(PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
+ (*itr)->CastSpell(*itr, (uint32)spellId, true);
+ else
+ for(PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
+ (*itr)->RemoveAura((uint32)-spellId); // by stack?
+}
+
+void OutdoorPvP::TeamApplyBuff(TeamId team, uint32 spellId, uint32 spellId2)
+{
+ TeamCastSpell(team, spellId);
+ TeamCastSpell(OTHER_TEAM(team), spellId2 ? -(int32)spellId2 : -(int32)spellId);
+}
diff --git a/src/game/OutdoorPvP.h b/src/game/OutdoorPvP.h
index e7bd21059a7..e82873c951c 100644
--- a/src/game/OutdoorPvP.h
+++ b/src/game/OutdoorPvP.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,23 +26,22 @@
#define OPVP_TRIGGER_CREATURE_ENTRY 12999
-enum ObjectiveStates{
- OBJECTIVESTATE_NEUTRAL = 0,
- OBJECTIVESTATE_ALLIANCE = 1,
- OBJECTIVESTATE_HORDE = 2,
- OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE = 3,
- OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE = 4,
- OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE = 5,
- OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE = 6
+enum TeamId
+{
+ TEAM_ALLIANCE = 0,
+ TEAM_HORDE,
+ TEAM_NEUTRAL,
};
-enum OutdoorPvPTypes{
+enum OutdoorPvPTypes
+{
OUTDOOR_PVP_HP = 1,
- OUTDOOR_PVP_NA = 2,
- OUTDOOR_PVP_TF = 3,
- OUTDOOR_PVP_ZM = 4,
- OUTDOOR_PVP_SI = 5,
- OUTDOOR_PVP_EP = 6
+ OUTDOOR_PVP_NA,
+ OUTDOOR_PVP_TF,
+ OUTDOOR_PVP_ZM,
+ OUTDOOR_PVP_SI,
+ OUTDOOR_PVP_EP,
+ OPVP_WINTERGRASP,
};
// struct for go spawning
@@ -161,6 +160,7 @@ protected:
// base class for specific outdoor pvp handlers
class OutdoorPvP
{
+ friend class OutdoorPvPMgr;
public:
// ctor
OutdoorPvP();
@@ -171,9 +171,7 @@ public:
typedef std::vector<OutdoorPvPObjective *> OutdoorPvPObjectiveSet;
- // called from Player::UpdateZone to add / remove buffs given by outdoor pvp events
- virtual void HandlePlayerEnterZone(Player * plr, uint32 zone);
- virtual void HandlePlayerLeaveZone(Player * plr, uint32 zone);
+ virtual void FillInitialWorldStates(WorldPacket & data) {}
virtual void HandlePlayerActivityChanged(Player * plr);
// called when a player triggers an areatrigger
virtual bool HandleAreaTrigger(Player * plr, uint32 trigger);
@@ -187,10 +185,6 @@ public:
// setup stuff
virtual bool SetupOutdoorPvP() {return true;}
- // world state stuff
- virtual void SendRemoveWorldStates(Player * plr) {}
- virtual void FillInitialWorldStates(WorldPacket & data) {}
-
// send world state update to all players present
virtual void SendUpdateWorldState(uint32 field, uint32 value);
@@ -214,12 +208,25 @@ public:
virtual bool HandleGossipOption(Player *plr, uint64 guid, uint32 gossipid);
virtual bool CanTalkTo(Player * plr, Creature * c, GossipOption &gso);
+
+ void TeamApplyBuff(TeamId team, uint32 spellId, uint32 spellId2 = 0);
protected:
// the map of the objectives belonging to this outdoorpvp
OutdoorPvPObjectiveSet m_OutdoorPvPObjectives;
- // players in the zones of this outdoorpvp, 0 - alliance, 1 - horde
- std::set<uint64> m_PlayerGuids[2];
+
+ typedef std::set<Player*> PlayerSet;
+ PlayerSet m_players[2];
uint32 m_TypeId;
+
+ // world state stuff
+ virtual void SendRemoveWorldStates(Player * plr) {}
+
+ virtual void HandlePlayerEnterZone(Player * plr, uint32 zone);
+ virtual void HandlePlayerLeaveZone(Player * plr, uint32 zone);
+
+ void RegisterZone(uint32 zoneid);
+ bool HasPlayer(Player *plr) const;
+ void TeamCastSpell(TeamId team, int32 spellId);
};
#endif /*OUTDOOR_PVP_H_*/
diff --git a/src/game/OutdoorPvPEP.cpp b/src/game/OutdoorPvPEP.cpp
index 41747dba100..4d94ef07b62 100644
--- a/src/game/OutdoorPvPEP.cpp
+++ b/src/game/OutdoorPvPEP.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -768,7 +768,7 @@ bool OutdoorPvPObjectiveEP_PWT::HandleGossipOption(Player *plr, uint64 guid, uin
nodes[1] = dst;
plr->PlayerTalkClass->CloseGossip();
- plr->ActivateTaxiPathTo(nodes, 0, cr);
+ plr->ActivateTaxiPathTo(nodes, cr);
// leave the opvp, seems like moveinlineofsight isn't called when entering a taxi
HandlePlayerLeave(plr);
}
@@ -789,7 +789,7 @@ OutdoorPvPEP::OutdoorPvPEP()
bool OutdoorPvPEP::SetupOutdoorPvP()
{
for(int i = 0; i < EPBuffZonesNum; ++i)
- sOutdoorPvPMgr.AddZone(EPBuffZones[i],this);
+ RegisterZone(EPBuffZones[i]);
m_OutdoorPvPObjectives.push_back(new OutdoorPvPObjectiveEP_EWT(this));
m_OutdoorPvPObjectives.push_back(new OutdoorPvPObjectiveEP_PWT(this));
@@ -853,24 +853,24 @@ void OutdoorPvPEP::HandlePlayerLeaveZone(Player * plr, uint32 zone)
void OutdoorPvPEP::BuffTeams()
{
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
+ for(PlayerSet::iterator itr = m_players[0].begin(); itr != m_players[0].end(); ++itr)
{
- if(Player * plr = objmgr.GetPlayer(*itr))
+ Player * plr = *itr;
{
for(int i = 0; i < 4; ++i)
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(EP_AllianceBuffs[i]);
+ plr->RemoveAurasDueToSpell(EP_AllianceBuffs[i]);
if(m_AllianceTowersControlled && m_AllianceTowersControlled < 5)
- if(plr->IsInWorld()) plr->CastSpell(plr,EP_AllianceBuffs[m_AllianceTowersControlled-1],true);
+ plr->CastSpell(plr,EP_AllianceBuffs[m_AllianceTowersControlled-1],true);
}
}
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
+ for(PlayerSet::iterator itr = m_players[1].begin(); itr != m_players[1].end(); ++itr)
{
- if(Player * plr = objmgr.GetPlayer(*itr))
+ Player * plr = *itr;
{
for(int i = 0; i < 4; ++i)
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(EP_HordeBuffs[i]);
+ plr->RemoveAurasDueToSpell(EP_HordeBuffs[i]);
if(m_HordeTowersControlled && m_HordeTowersControlled < 5)
- if(plr->IsInWorld()) plr->CastSpell(plr,EP_HordeBuffs[m_HordeTowersControlled-1],true);
+ plr->CastSpell(plr,EP_HordeBuffs[m_HordeTowersControlled-1],true);
}
}
}
diff --git a/src/game/OutdoorPvPEP.h b/src/game/OutdoorPvPEP.h
index ae242a1da16..f6199ac5a3b 100644
--- a/src/game/OutdoorPvPEP.h
+++ b/src/game/OutdoorPvPEP.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,9 +19,9 @@
#ifndef OUTDOOR_PVP_EP_
#define OUTDOOR_PVP_EP_
-#include "OutdoorPvP.h"
+#include "OutdoorPvPImpl.h"
-#include "Database/DBCStructure.h"
+#include "DBCStructure.h"
const uint32 EP_AllianceBuffs[4] = {11413, 11414, 11415, 1386};
diff --git a/src/game/OutdoorPvPHP.cpp b/src/game/OutdoorPvPHP.cpp
index b31f79a6288..c3855b4f90a 100644
--- a/src/game/OutdoorPvPHP.cpp
+++ b/src/game/OutdoorPvPHP.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -70,7 +70,7 @@ bool OutdoorPvPHP::SetupOutdoorPvP()
m_HordeTowersControlled = 0;
// add the zones affected by the pvp buff
for(int i = 0; i < OutdoorPvPHPBuffZonesNum; ++i)
- sOutdoorPvPMgr.AddZone(OutdoorPvPHPBuffZones[i],this);
+ RegisterZone(OutdoorPvPHPBuffZones[i]);
m_OutdoorPvPObjectives.push_back(new OutdoorPvPObjectiveHP(this,HP_TOWER_BROKEN_HILL));
@@ -117,11 +117,14 @@ bool OutdoorPvPHP::Update(uint32 diff)
if(changed = OutdoorPvP::Update(diff))
{
if(m_AllianceTowersControlled == 3)
- BuffTeam(ALLIANCE);
+ TeamApplyBuff(TEAM_ALLIANCE, AllianceBuff, HordeBuff);
else if(m_HordeTowersControlled == 3)
- BuffTeam(HORDE);
+ TeamApplyBuff(TEAM_HORDE, HordeBuff, AllianceBuff);
else
- BuffTeam(0);
+ {
+ TeamCastSpell(TEAM_ALLIANCE, -AllianceBuff);
+ TeamCastSpell(TEAM_HORDE, -HordeBuff);
+ }
SendUpdateWorldState(HP_UI_TOWER_COUNT_A, m_AllianceTowersControlled);
SendUpdateWorldState(HP_UI_TOWER_COUNT_H, m_HordeTowersControlled);
}
@@ -328,49 +331,6 @@ void OutdoorPvPObjectiveHP::HandlePlayerLeave(Player *plr)
OutdoorPvPObjective::HandlePlayerLeave(plr);
}
-void OutdoorPvPHP::BuffTeam(uint32 team)
-{
- if(team == ALLIANCE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,AllianceBuff,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(HordeBuff);
- }
- }
- else if(team == HORDE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,HordeBuff,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(AllianceBuff);
- }
- }
- else
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(AllianceBuff);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(HordeBuff);
- }
- }
-}
-
void OutdoorPvPHP::HandleKillImpl(Player *plr, Unit * killed)
{
if(killed->GetTypeId() != TYPEID_PLAYER)
diff --git a/src/game/OutdoorPvPHP.h b/src/game/OutdoorPvPHP.h
index da41761d572..7d00b0a536d 100644
--- a/src/game/OutdoorPvPHP.h
+++ b/src/game/OutdoorPvPHP.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,15 +19,15 @@
#ifndef OUTDOOR_PVP_HP_
#define OUTDOOR_PVP_HP_
-#include "OutdoorPvP.h"
+#include "OutdoorPvPImpl.h"
#define OutdoorPvPHPBuffZonesNum 6
// HP, citadel, ramparts, blood furnace, shattered halls, mag's lair
const uint32 OutdoorPvPHPBuffZones[OutdoorPvPHPBuffZonesNum] = { 3483, 3563, 3562, 3713, 3714, 3836 };
-const uint32 AllianceBuff = 32071;
+#define AllianceBuff 32071
-const uint32 HordeBuff = 32049;
+#define HordeBuff 32049
const uint32 AlliancePlayerKillReward = 32155;
@@ -108,7 +108,6 @@ public:
void FillInitialWorldStates(WorldPacket &data);
void SendRemoveWorldStates(Player * plr);
void HandleKillImpl(Player * plr, Unit * killed);
- void BuffTeam(uint32 team);
private:
// how many towers are controlled
uint32 m_AllianceTowersControlled;
diff --git a/src/game/OutdoorPvPImpl.h b/src/game/OutdoorPvPImpl.h
new file mode 100644
index 00000000000..1bbd29435c5
--- /dev/null
+++ b/src/game/OutdoorPvPImpl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef OUTDOORPVP_IMPL_H
+#define OUTDOORPVP_IMPL_H
+
+#include "SharedDefines.h"
+#include "OutdoorPvP.h"
+#include "Player.h"
+
+#define TEAM_ID(a) (a == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE)
+#define OTHER_TEAM(a) (a == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE)
+
+enum ObjectiveStates
+{
+ OBJECTIVESTATE_NEUTRAL = 0,
+ OBJECTIVESTATE_ALLIANCE,
+ OBJECTIVESTATE_HORDE,
+ OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE,
+ OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE,
+ OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE,
+ OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE,
+};
+
+#endif
diff --git a/src/game/OutdoorPvPMgr.cpp b/src/game/OutdoorPvPMgr.cpp
index 5c53bf4eaba..ff0d1269447 100644
--- a/src/game/OutdoorPvPMgr.cpp
+++ b/src/game/OutdoorPvPMgr.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include "OutdoorPvPZM.h"
#include "OutdoorPvPSI.h"
#include "OutdoorPvPEP.h"
+#include "Wintergrasp.h"
#include "Player.h"
#include "Policies/SingletonImp.h"
@@ -125,6 +126,19 @@ void OutdoorPvPMgr::InitOutdoorPvP()
m_OutdoorPvPSet.push_back(pOP);
sLog.outDebug("OutdoorPvP : EP successfully initiated.");
}
+
+ pOP = new OPvPWintergrasp;
+ // respawn, init variables
+ if(!pOP->SetupOutdoorPvP())
+ {
+ sLog.outDebug("OutdoorPvP : Wintergrasp init failed.");
+ delete pOP;
+ }
+ else
+ {
+ m_OutdoorPvPSet.push_back(pOP);
+ sLog.outDebug("OutdoorPvP : Wintergrasp successfully initiated.");
+ }
}
void OutdoorPvPMgr::AddZone(uint32 zoneid, OutdoorPvP *handle)
@@ -137,25 +151,25 @@ void OutdoorPvPMgr::HandlePlayerEnterZone(Player *plr, uint32 zoneid)
{
OutdoorPvPMap::iterator itr = m_OutdoorPvPMap.find(zoneid);
if(itr == m_OutdoorPvPMap.end())
- {
- // no handle for this zone, return
return;
- }
- // add possibly beneficial buffs to plr for zone
+
+ if(itr->second->HasPlayer(plr))
+ return;
+
itr->second->HandlePlayerEnterZone(plr, zoneid);
- plr->SendInitWorldStates();
- sLog.outDebug("Player %u entered outdoorpvp id %u",plr->GetGUIDLow(), itr->second->GetTypeId());
+ sLog.outDebug("Player %u entered outdoorpvp id %u", plr->GetGUIDLow(), itr->second->GetTypeId());
}
void OutdoorPvPMgr::HandlePlayerLeaveZone(Player *plr, uint32 zoneid)
{
OutdoorPvPMap::iterator itr = m_OutdoorPvPMap.find(zoneid);
if(itr == m_OutdoorPvPMap.end())
- {
- // no handle for this zone, return
return;
- }
- // inform the OutdoorPvP class of the leaving, it should remove the player from all objectives
+
+ // teleport: remove once in removefromworld, once in updatezone
+ if(!itr->second->HasPlayer(plr))
+ return;
+
itr->second->HandlePlayerLeaveZone(plr, zoneid);
sLog.outDebug("Player %u left outdoorpvp id %u",plr->GetGUIDLow(), itr->second->GetTypeId());
}
diff --git a/src/game/OutdoorPvPMgr.h b/src/game/OutdoorPvPMgr.h
index 7426876b42b..28b01c586b7 100644
--- a/src/game/OutdoorPvPMgr.h
+++ b/src/game/OutdoorPvPMgr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/OutdoorPvPNA.cpp b/src/game/OutdoorPvPNA.cpp
index 9b59347dd2d..ef7e6b97e51 100644
--- a/src/game/OutdoorPvPNA.cpp
+++ b/src/game/OutdoorPvPNA.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -83,49 +83,6 @@ uint32 OutdoorPvPObjectiveNA::GetAliveGuardsCount()
return cnt;
}
-void OutdoorPvPNA::BuffTeam(uint32 team)
-{
- if(team == ALLIANCE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,NA_CAPTURE_BUFF,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(NA_CAPTURE_BUFF);
- }
- }
- else if(team == HORDE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,NA_CAPTURE_BUFF,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(NA_CAPTURE_BUFF);
- }
- }
- else
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(NA_CAPTURE_BUFF);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(NA_CAPTURE_BUFF);
- }
- }
-}
-
void OutdoorPvPObjectiveNA::SpawnNPCsForTeam(uint32 team)
{
const creature_type * creatures = NULL;
@@ -222,7 +179,7 @@ void OutdoorPvPObjectiveNA::FactionTakeOver(uint32 team)
this->UpdateWyvernRoostWorldState(NA_ROOST_N);
this->UpdateWyvernRoostWorldState(NA_ROOST_W);
this->UpdateWyvernRoostWorldState(NA_ROOST_E);
- ((OutdoorPvPNA*)m_PvP)->BuffTeam(team);
+ m_PvP->TeamApplyBuff(TEAM_ID(team), NA_CAPTURE_BUFF);
}
bool OutdoorPvPObjectiveNA::HandlePlayerEnter(Player *plr)
@@ -256,7 +213,7 @@ bool OutdoorPvPNA::SetupOutdoorPvP()
{
// m_TypeId = OUTDOOR_PVP_NA; _MUST_ be set in ctor, because of spawns cleanup
// add the zones affected by the pvp buff
- sOutdoorPvPMgr.AddZone(NA_BUFF_ZONE,this);
+ RegisterZone(NA_BUFF_ZONE);
// halaa
m_obj = new OutdoorPvPObjectiveNA(this);
diff --git a/src/game/OutdoorPvPNA.h b/src/game/OutdoorPvPNA.h
index b6be2270cda..a9500eb5e27 100644
--- a/src/game/OutdoorPvPNA.h
+++ b/src/game/OutdoorPvPNA.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
// TODO: "sometimes" set to neutral
-#include "OutdoorPvP.h"
+#include "OutdoorPvPImpl.h"
// kill credit for pks
const uint32 NA_CREDIT_MARKER = 24867;
@@ -289,7 +289,6 @@ public:
void FillInitialWorldStates(WorldPacket &data);
void SendRemoveWorldStates(Player * plr);
void HandleKillImpl(Player * plr, Unit * killed);
- void BuffTeam(uint32 team);
private:
OutdoorPvPObjectiveNA * m_obj;
};
diff --git a/src/game/OutdoorPvPObjectiveAI.cpp b/src/game/OutdoorPvPObjectiveAI.cpp
index 7c4fd5e6de8..35247d81210 100644
--- a/src/game/OutdoorPvPObjectiveAI.cpp
+++ b/src/game/OutdoorPvPObjectiveAI.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
#include "Player.h"
#include "Unit.h"
#include "OutdoorPvPMgr.h"
+#include "OutdoorPvPImpl.h"
#include "World.h"
#define MAX_OUTDOOR_PVP_DISTANCE 200 // the max value in capture point type go data0 is 100 currently, so use twice that much to handle leaving as well
diff --git a/src/game/OutdoorPvPObjectiveAI.h b/src/game/OutdoorPvPObjectiveAI.h
index d21655795e9..dffd8885243 100644
--- a/src/game/OutdoorPvPObjectiveAI.h
+++ b/src/game/OutdoorPvPObjectiveAI.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@ class Creature;
class TRINITY_DLL_DECL OutdoorPvPObjectiveAI : public NullCreatureAI
{
public:
- OutdoorPvPObjectiveAI(Creature *c);
+ explicit OutdoorPvPObjectiveAI(Creature *c);
void MoveInLineOfSight(Unit *);
diff --git a/src/game/OutdoorPvPSI.cpp b/src/game/OutdoorPvPSI.cpp
index e4686573a67..f9f04f676ff 100644
--- a/src/game/OutdoorPvPSI.cpp
+++ b/src/game/OutdoorPvPSI.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,7 +58,7 @@ void OutdoorPvPSI::UpdateWorldState()
bool OutdoorPvPSI::SetupOutdoorPvP()
{
for(int i = 0; i < OutdoorPvPSIBuffZonesNum; ++i)
- sOutdoorPvPMgr.AddZone(OutdoorPvPSIBuffZones[i],this);
+ RegisterZone(OutdoorPvPSIBuffZones[i]);
return true;
}
@@ -81,62 +81,19 @@ void OutdoorPvPSI::HandlePlayerLeaveZone(Player * plr, uint32 zone)
OutdoorPvP::HandlePlayerLeaveZone(plr, zone);
}
-void OutdoorPvPSI::BuffTeam(uint32 team)
-{
- if(team == ALLIANCE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,SI_CENARION_FAVOR,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(SI_CENARION_FAVOR);
- }
- }
- else if(team == HORDE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,SI_CENARION_FAVOR,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(SI_CENARION_FAVOR);
- }
- }
- else
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(SI_CENARION_FAVOR);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(SI_CENARION_FAVOR);
- }
- }
-}
-
bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger)
{
switch(trigger)
{
case SI_AREATRIGGER_A:
- if(plr->GetTeam() == ALLIANCE && plr->HasAura(SI_SILITHYST_FLAG,0))
+ if(plr->GetTeam() == ALLIANCE && plr->HasAura(SI_SILITHYST_FLAG))
{
// remove aura
plr->RemoveAurasDueToSpell(SI_SILITHYST_FLAG);
++ m_Gathered_A;
if(m_Gathered_A >= SI_MAX_RESOURCES)
{
- BuffTeam(ALLIANCE);
+ TeamApplyBuff(TEAM_ALLIANCE, SI_CENARION_FAVOR);
sWorld.SendZoneText(OutdoorPvPSIBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_SI_CAPTURE_A));
m_LastController = ALLIANCE;
m_Gathered_A = 0;
@@ -148,20 +105,20 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger)
// add 19 honor
plr->RewardHonor(NULL,1,19);
// add 20 cenarion circle repu
- plr->ModifyFactionReputation(609,20);
+ plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20);
// complete quest
plr->KilledMonster(SI_TURNIN_QUEST_CM_A,0);
}
return true;
case SI_AREATRIGGER_H:
- if(plr->GetTeam() == HORDE && plr->HasAura(SI_SILITHYST_FLAG,0))
+ if(plr->GetTeam() == HORDE && plr->HasAura(SI_SILITHYST_FLAG))
{
// remove aura
plr->RemoveAurasDueToSpell(SI_SILITHYST_FLAG);
++ m_Gathered_H;
if(m_Gathered_H >= SI_MAX_RESOURCES)
{
- BuffTeam(HORDE);
+ TeamApplyBuff(TEAM_HORDE, SI_CENARION_FAVOR);
sWorld.SendZoneText(OutdoorPvPSIBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_SI_CAPTURE_H));
m_LastController = HORDE;
m_Gathered_A = 0;
@@ -173,7 +130,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger)
// add 19 honor
plr->RewardHonor(NULL,1,19);
// add 20 cenarion circle repu
- plr->ModifyFactionReputation(609,20);
+ plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20);
// complete quest
plr->KilledMonster(SI_TURNIN_QUEST_CM_H,0);
}
@@ -200,14 +157,13 @@ bool OutdoorPvPSI::HandleDropFlag(Player *plr, uint32 spellId)
// he dropped it further, summon mound
GameObject * go = new GameObject;
Map * map = MapManager::Instance().GetMap(plr->GetMapId(), plr);
- if(!map){
-
- delete go;
- return true;
-
+ if(!map)
+ {
+ delete go;
+ return true;
}
- if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),SI_SILITHYST_MOUND, map,plr->GetPositionX(),plr->GetPositionY(),plr->GetPositionZ(),plr->GetOrientation(),0,0,0,0,100,1))
+ if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),SI_SILITHYST_MOUND, map, plr->GetPhaseMask(), plr->GetPositionX(),plr->GetPositionY(),plr->GetPositionZ(),plr->GetOrientation(),0,0,0,0,100,GO_STATE_READY))
{
delete go;
}
@@ -233,7 +189,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player *plr, uint32 spellId)
Map * map = MapManager::Instance().GetMap(plr->GetMapId(), plr);
if(!map)
return true;
- if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),SI_SILITHYST_MOUND, map ,plr->GetPositionX(),plr->GetPositionY(),plr->GetPositionZ(),plr->GetOrientation(),0,0,0,0,100,1))
+ if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),SI_SILITHYST_MOUND, map, plr->GetPhaseMask() ,plr->GetPositionX(),plr->GetPositionY(),plr->GetPositionZ(),plr->GetOrientation(),0,0,0,0,100,GO_STATE_READY))
{
delete go;
}
diff --git a/src/game/OutdoorPvPSI.h b/src/game/OutdoorPvPSI.h
index 4b0b5da357e..2ef5822ba8e 100644
--- a/src/game/OutdoorPvPSI.h
+++ b/src/game/OutdoorPvPSI.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
#ifndef OUTDOOR_PVP_SI_
#define OUTDOOR_PVP_SI_
-#include "OutdoorPvP.h"
+#include "OutdoorPvPImpl.h"
const uint32 SI_SILITHYST_FLAG_GO_SPELL = 29518;
@@ -64,7 +64,6 @@ public:
bool HandleAreaTrigger(Player * plr, uint32 trigger);
bool HandleDropFlag(Player * plr, uint32 spellId);
bool HandleCustomSpell(Player * plr, uint32 spellId, GameObject *go);
- void BuffTeam(uint32 team);
void UpdateWorldState();
private:
uint32 m_Gathered_A;
diff --git a/src/game/OutdoorPvPTF.cpp b/src/game/OutdoorPvPTF.cpp
index b94bc9246ee..2031dbc7521 100644
--- a/src/game/OutdoorPvPTF.cpp
+++ b/src/game/OutdoorPvPTF.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -133,49 +133,6 @@ bool OutdoorPvPObjectiveTF::HandleCapturePointEvent(Player *plr, uint32 eventId)
return false;
}
-void OutdoorPvPTF::BuffTeam(uint32 team)
-{
- if(team == ALLIANCE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,TF_CAPTURE_BUFF,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(TF_CAPTURE_BUFF);
- }
- }
- else if(team == HORDE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,TF_CAPTURE_BUFF,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(TF_CAPTURE_BUFF);
- }
- }
- else
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(TF_CAPTURE_BUFF);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(TF_CAPTURE_BUFF);
- }
- }
-}
-
bool OutdoorPvPTF::Update(uint32 diff)
{
bool changed = false;
@@ -184,7 +141,7 @@ bool OutdoorPvPTF::Update(uint32 diff)
{
if(m_AllianceTowersControlled == TF_TOWER_NUM)
{
- BuffTeam(ALLIANCE);
+ TeamApplyBuff(TEAM_ALLIANCE, TF_CAPTURE_BUFF);
m_IsLocked = true;
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0));
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(0));
@@ -193,7 +150,7 @@ bool OutdoorPvPTF::Update(uint32 diff)
}
else if(m_HordeTowersControlled == TF_TOWER_NUM)
{
- BuffTeam(HORDE);
+ TeamApplyBuff(TEAM_HORDE, TF_CAPTURE_BUFF);
m_IsLocked = true;
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0));
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(1));
@@ -201,7 +158,10 @@ bool OutdoorPvPTF::Update(uint32 diff)
SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(0));
}
else
- BuffTeam(NULL);
+ {
+ TeamCastSpell(TEAM_ALLIANCE, -TF_CAPTURE_BUFF);
+ TeamCastSpell(TEAM_HORDE, -TF_CAPTURE_BUFF);
+ }
SendUpdateWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled);
SendUpdateWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled);
}
@@ -276,7 +236,7 @@ bool OutdoorPvPTF::SetupOutdoorPvP()
// add the zones affected by the pvp buff
for(int i = 0; i < OutdoorPvPTFBuffZonesNum; ++i)
- sOutdoorPvPMgr.AddZone(OutdoorPvPTFBuffZones[i],this);
+ RegisterZone(OutdoorPvPTFBuffZones[i]);
m_OutdoorPvPObjectives.push_back(new OutdoorPvPObjectiveTF(this,TF_TOWER_NW));
m_OutdoorPvPObjectives.push_back(new OutdoorPvPObjectiveTF(this,TF_TOWER_N));
diff --git a/src/game/OutdoorPvPTF.h b/src/game/OutdoorPvPTF.h
index 255ddb1fda9..c45a31e3d22 100644
--- a/src/game/OutdoorPvPTF.h
+++ b/src/game/OutdoorPvPTF.h
@@ -1,7 +1,7 @@
#ifndef OUTDOOR_PVP_TF_
#define OUTDOOR_PVP_TF_
-#include "OutdoorPvP.h"
+#include "OutdoorPvPImpl.h"
const uint32 OutdoorPvPTFBuffZonesNum = 5;
@@ -13,7 +13,7 @@ const uint32 TF_LOCK_TIME = 3600 * 6 * 1000;
const uint32 TF_LOCK_TIME_UPDATE = 15000;
// blessing of auchindoun
-const uint32 TF_CAPTURE_BUFF = 33377;
+#define TF_CAPTURE_BUFF 33377
const uint32 TF_ALLY_QUEST = 11505;
const uint32 TF_HORDE_QUEST = 11506;
@@ -104,7 +104,6 @@ public:
bool Update(uint32 diff);
void FillInitialWorldStates(WorldPacket &data);
void SendRemoveWorldStates(Player * plr);
- void BuffTeam(uint32 team);
private:
bool m_IsLocked;
uint32 m_LockTimer;
diff --git a/src/game/OutdoorPvPZM.cpp b/src/game/OutdoorPvPZM.cpp
index b220f6a778f..340c12c3ca6 100644
--- a/src/game/OutdoorPvPZM.cpp
+++ b/src/game/OutdoorPvPZM.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -203,7 +203,7 @@ bool OutdoorPvPZM::SetupOutdoorPvP()
// add the zones affected by the pvp buff
for(int i = 0; i < OutdoorPvPZMBuffZonesNum; ++i)
- sOutdoorPvPMgr.AddZone(OutdoorPvPZMBuffZones[i],this);
+ RegisterZone(OutdoorPvPZMBuffZones[i]);
m_OutdoorPvPObjectives.push_back(new OutdoorPvPObjectiveZM_Beacon(this,ZM_BEACON_WEST));
m_OutdoorPvPObjectives.push_back(new OutdoorPvPObjectiveZM_Beacon(this,ZM_BEACON_EAST));
@@ -224,49 +224,6 @@ void OutdoorPvPZM::HandleKillImpl(Player *plr, Unit * killed)
plr->CastSpell(plr,ZM_HordePlayerKillReward,true);
}
-void OutdoorPvPZM::BuffTeam(uint32 team)
-{
- if(team == ALLIANCE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,ZM_CAPTURE_BUFF,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(ZM_CAPTURE_BUFF);
- }
- }
- else if(team == HORDE)
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->CastSpell(plr,ZM_CAPTURE_BUFF,true);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(ZM_CAPTURE_BUFF);
- }
- }
- else
- {
- for(std::set<uint64>::iterator itr = m_PlayerGuids[0].begin(); itr != m_PlayerGuids[0].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(ZM_CAPTURE_BUFF);
- }
- for(std::set<uint64>::iterator itr = m_PlayerGuids[1].begin(); itr != m_PlayerGuids[1].end(); ++itr)
- {
- if(Player * plr = objmgr.GetPlayer(*itr))
- if(plr->IsInWorld()) plr->RemoveAurasDueToSpell(ZM_CAPTURE_BUFF);
- }
- }
-}
-
bool OutdoorPvPObjectiveZM_GraveYard::Update(uint32 diff)
{
bool retval = m_State != m_OldState;
@@ -279,7 +236,7 @@ int32 OutdoorPvPObjectiveZM_GraveYard::HandleOpenGo(Player *plr, uint64 guid)
uint32 retval = OutdoorPvPObjective::HandleOpenGo(plr, guid);
if(retval>=0)
{
- if(plr->HasAura(ZM_BATTLE_STANDARD_A,0) && m_GraveYardState != ZM_GRAVEYARD_A)
+ if(plr->HasAura(ZM_BATTLE_STANDARD_A) && m_GraveYardState != ZM_GRAVEYARD_A)
{
if(m_GraveYardState == ZM_GRAVEYARD_H)
sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_LOOSE_GY_H));
@@ -288,11 +245,11 @@ int32 OutdoorPvPObjectiveZM_GraveYard::HandleOpenGo(Player *plr, uint64 guid)
AddObject(0,ZM_Banner_A.entry,ZM_Banner_A.map,ZM_Banner_A.x,ZM_Banner_A.y,ZM_Banner_A.z,ZM_Banner_A.o,ZM_Banner_A.rot0,ZM_Banner_A.rot1,ZM_Banner_A.rot2,ZM_Banner_A.rot3);
objmgr.RemoveGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, HORDE); // rem gy
objmgr.AddGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, ALLIANCE, false); // add gy
- ((OutdoorPvPZM*)m_PvP)->BuffTeam(ALLIANCE);
+ m_PvP->TeamApplyBuff(TEAM_ALLIANCE, ZM_CAPTURE_BUFF);
plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A);
sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_A));
}
- else if(plr->HasAura(ZM_BATTLE_STANDARD_H,0) && m_GraveYardState != ZM_GRAVEYARD_H)
+ else if(plr->HasAura(ZM_BATTLE_STANDARD_H) && m_GraveYardState != ZM_GRAVEYARD_H)
{
if(m_GraveYardState == ZM_GRAVEYARD_A)
sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_LOOSE_GY_A));
@@ -301,7 +258,7 @@ int32 OutdoorPvPObjectiveZM_GraveYard::HandleOpenGo(Player *plr, uint64 guid)
AddObject(0,ZM_Banner_H.entry,ZM_Banner_H.map,ZM_Banner_H.x,ZM_Banner_H.y,ZM_Banner_H.z,ZM_Banner_H.o,ZM_Banner_H.rot0,ZM_Banner_H.rot1,ZM_Banner_H.rot2,ZM_Banner_H.rot3);
objmgr.RemoveGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, ALLIANCE); // rem gy
objmgr.AddGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, HORDE, false); // add gy
- ((OutdoorPvPZM*)m_PvP)->BuffTeam(HORDE);
+ m_PvP->TeamApplyBuff(TEAM_HORDE, ZM_CAPTURE_BUFF);
plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H);
sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_H));
}
diff --git a/src/game/OutdoorPvPZM.h b/src/game/OutdoorPvPZM.h
index b9d5ae7bc2e..33e42209f41 100644
--- a/src/game/OutdoorPvPZM.h
+++ b/src/game/OutdoorPvPZM.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,14 +19,14 @@
#ifndef OUTDOOR_PVP_ZM_
#define OUTDOOR_PVP_ZM_
-#include "OutdoorPvP.h"
+#include "OutdoorPvPImpl.h"
#include "Language.h"
const uint32 OutdoorPvPZMBuffZonesNum = 5;
// the buff is cast in these zones
const uint32 OutdoorPvPZMBuffZones[OutdoorPvPZMBuffZonesNum] = {3521,3607,3717,3715,3716};
// cast on the players of the controlling faction
-const uint32 ZM_CAPTURE_BUFF = 33779; // twin spire blessing
+#define ZM_CAPTURE_BUFF 33779 // twin spire blessing
// spell that the field scout casts on the player to carry the flag
const uint32 ZM_BATTLE_STANDARD_A = 32430;
// spell that the field scout casts on the player to carry the flag
@@ -204,7 +204,6 @@ public:
void FillInitialWorldStates(WorldPacket &data);
void SendRemoveWorldStates(Player * plr);
void HandleKillImpl(Player * plr, Unit * killed);
- void BuffTeam(uint32 team);
private:
OutdoorPvPObjectiveZM_GraveYard * m_GraveYard;
uint32 m_AllianceTowersControlled;
diff --git a/src/game/Path.h b/src/game/Path.h
index 2b793aed892..2fd6723b01c 100644
--- a/src/game/Path.h
+++ b/src/game/Path.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp
index 75664032ce3..300106eb2c3 100644
--- a/src/game/Pet.cpp
+++ b/src/game/Pet.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,12 +21,10 @@
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "Log.h"
-#include "WorldSession.h"
#include "WorldPacket.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Pet.h"
-#include "MapManager.h"
#include "Formulas.h"
#include "SpellAuras.h"
#include "CreatureAI.h"
@@ -41,73 +39,25 @@ char const* petTypeSuffix[MAX_PET_TYPE] =
"'s Companion" // MINI_PET
};
-//numbers represent minutes * 100 while happy (you get 100 loyalty points per min while happy)
-uint32 const LevelUpLoyalty[6] =
-{
- 5500,
- 11500,
- 17000,
- 23500,
- 31000,
- 39500,
-};
-
-uint32 const LevelStartLoyalty[6] =
-{
- 2000,
- 4500,
- 7000,
- 10000,
- 13500,
- 17500,
-};
+#define PET_XP_FACTOR 0.1f
-Pet::Pet(PetType type) : Creature()
+Pet::Pet(Player *owner, PetType type) : Guardian(NULL, owner),
+m_petType(type), m_removed(false), m_happinessTimer(7500), m_duration(0),
+m_resetTalentsCost(0), m_resetTalentsTime(0), m_usedTalentCount(0), m_auraRaidUpdateMask(0), m_loading(false),
+m_declinedname(NULL), m_owner(owner)
{
- m_isPet = true;
+ m_summonMask |= SUMMON_MASK_PET;
m_name = "Pet";
- m_petType = type;
-
- m_removed = false;
m_regenTimer = 4000;
- m_happinessTimer = 7500;
- m_loyaltyTimer = 12000;
- m_duration = 0;
- m_bonusdamage = 0;
-
- m_loyaltyPoints = 0;
- m_TrainingPoints = 0;
- m_resetTalentsCost = 0;
- m_resetTalentsTime = 0;
-
- m_auraUpdateMask = 0;
- // pets always have a charminfo, even if they are not actually charmed
- CharmInfo* charmInfo = InitCharmInfo();
+ owner->SetPetAtLoginFlag(0);
- if(type == MINI_PET || type == POSSESSED_PET) // always passive
+ if(type == POSSESSED_PET) // always passive
SetReactState(REACT_PASSIVE);
- else if(type == GUARDIAN_PET) // always aggressive
- SetReactState(REACT_AGGRESSIVE);
-
- m_spells.clear();
- m_Auras.clear();
- m_CreatureSpellCooldowns.clear();
- m_CreatureCategoryCooldowns.clear();
- m_autospells.clear();
- m_declinedname = NULL;
- //m_isActive = true;
}
Pet::~Pet()
{
- if(m_uint32Values) // only for fully created Object
- {
- for (PetSpellMap::iterator i = m_spells.begin(); i != m_spells.end(); ++i)
- delete i->second;
- ObjectAccessor::Instance().RemoveObject(this);
- }
-
delete m_declinedname;
}
@@ -115,9 +65,11 @@ void Pet::AddToWorld()
{
///- Register the pet for guid lookup
if(!IsInWorld())
- {
+ {
+ ///- Register the pet for guid lookup
ObjectAccessor::Instance().AddObject(this);
Unit::AddToWorld();
+ AIM_Initialize();
}
}
@@ -126,32 +78,42 @@ void Pet::RemoveFromWorld()
///- Remove the pet from the accessor
if(IsInWorld())
{
- ObjectAccessor::Instance().RemoveObject(this);
///- Don't call the function for Creature, normal mobs + totems go in a different storage
Unit::RemoveFromWorld();
+ ObjectAccessor::Instance().RemoveObject(this);
}
}
-bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool current )
+bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool current )
{
+ m_loading = true;
+
uint32 ownerid = owner->GetGUIDLow();
QueryResult *result;
- if(petnumber)
- // known petnumber entry 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
- result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND id = '%u'",ownerid, petnumber);
- else if(current)
- // current pet (slot 0) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
- result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND slot = '0'",ownerid );
- else if(petentry)
+ if (petnumber)
+ // known petnumber entry 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags "
+ "FROM character_pet WHERE owner = '%u' AND id = '%u'",
+ ownerid, petnumber);
+ else if (current)
+ // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags "
+ "FROM character_pet WHERE owner = '%u' AND slot = '%u'",
+ ownerid, PET_SAVE_AS_CURRENT );
+ else if (petentry)
// known petentry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets)
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
- result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '0' OR slot = '3') ",ownerid, petentry );
+ // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags "
+ "FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '%u' OR slot > '%u') ",
+ ownerid, petentry,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT);
else
// any current or other non-stabled pet (for hunter "call pet")
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
- result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND (slot = '0' OR slot = '3') ",ownerid);
+ // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags "
+ "FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u') ",
+ ownerid,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT);
if(!result)
return false;
@@ -160,28 +122,36 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu
// update for case of current pet "slot = 0"
petentry = fields[1].GetUInt32();
- if(!petentry)
+ if (!petentry)
{
delete result;
return false;
}
- uint32 summon_spell_id = fields[21].GetUInt32();
+ uint32 summon_spell_id = fields[18].GetUInt32();
SpellEntry const* spellInfo = sSpellStore.LookupEntry(summon_spell_id);
bool is_temporary_summoned = spellInfo && GetSpellDuration(spellInfo) > 0;
// check temporary summoned pets like mage water elemental
- if(current && is_temporary_summoned)
+ if (current && is_temporary_summoned)
+ {
+ delete result;
+ return false;
+ }
+
+ uint32 pet_number = fields[0].GetUInt32();
+
+ if (current && owner->IsPetNeedBeTemporaryUnsummoned())
{
+ owner->SetTemporaryUnsummonedPetNumber(pet_number);
delete result;
return false;
}
Map *map = owner->GetMap();
uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_PET);
- uint32 pet_number = fields[0].GetUInt32();
- if(!Create(guid, map, petentry, pet_number))
+ if (!Create(guid, map, owner->GetPhaseMask(), petentry, pet_number))
{
delete result;
return false;
@@ -189,181 +159,159 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu
float px, py, pz;
owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
-
Relocate(px, py, pz, owner->GetOrientation());
- if(!IsPositionValid())
+ if (!IsPositionValid())
{
- sLog.outError("ERROR: Pet (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",
+ sLog.outError("Pet (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",
GetGUIDLow(), GetEntry(), GetPositionX(), GetPositionY());
delete result;
return false;
}
- setPetType(PetType(fields[22].GetUInt8()));
- SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,owner->getFaction());
+ setPetType(PetType(fields[19].GetUInt8()));
+ SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, owner->getFaction());
SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id);
CreatureInfo const *cinfo = GetCreatureInfo();
- if(cinfo->type == CREATURE_TYPE_CRITTER)
+ if (cinfo->type == CREATURE_TYPE_CRITTER)
{
- AIM_Initialize();
map->Add((Creature*)this);
delete result;
return true;
}
- if(getPetType()==HUNTER_PET || (getPetType()==SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK))
- m_charmInfo->SetPetNumber(pet_number, true);
- else
- m_charmInfo->SetPetNumber(pet_number, false);
- SetUInt64Value(UNIT_FIELD_SUMMONEDBY, owner->GetGUID());
+
+ m_charmInfo->SetPetNumber(pet_number, IsPermanentPetFor(owner));
+
+ // set current pet as current
+ // 0=current
+ // 1..MAX_PET_STABLES in stable slot
+ // PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
+ if(fields[8].GetUInt32() != 0)
+ {
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND slot = '%u' AND id <> '%u'",
+ PET_SAVE_NOT_IN_SLOT, ownerid, PET_SAVE_AS_CURRENT, m_charmInfo->GetPetNumber());
+ CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND id = '%u'",
+ PET_SAVE_AS_CURRENT, ownerid, m_charmInfo->GetPetNumber());
+ CharacterDatabase.CommitTransaction();
+ }
+
SetDisplayId(fields[3].GetUInt32());
SetNativeDisplayId(fields[3].GetUInt32());
- uint32 petlevel=fields[4].GetUInt32();
- SetUInt32Value(UNIT_NPC_FLAGS , 0);
- SetName(fields[11].GetString());
+ uint32 petlevel = fields[4].GetUInt32();
+ SetUInt32Value(UNIT_NPC_FLAGS, 0);
+ SetName(fields[9].GetString());
- switch(getPetType())
+ switch (getPetType())
{
-
case SUMMON_PET:
petlevel=owner->getLevel();
- SetUInt32Value(UNIT_FIELD_BYTES_0,2048);
+ SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
// this enables popup window (pet dismiss, cancel)
break;
case HUNTER_PET:
SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100);
- SetByteValue(UNIT_FIELD_BYTES_1, 1, fields[8].GetUInt32());
- SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE );
- SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY | UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5 );
-
- if(fields[12].GetBool())
- SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
- else
- SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);
+ SetByteValue(UNIT_FIELD_BYTES_1, 1, fields[7].GetUInt32());
+ SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE);
+ SetByteValue(UNIT_FIELD_BYTES_2, 2, fields[10].GetBool() ? UNIT_RENAME_NOT_ALLOWED : UNIT_RENAME_ALLOWED);
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
// this enables popup window (pet abandon, cancel)
- SetTP(fields[9].GetInt32());
- SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
- SetPower( POWER_HAPPINESS,fields[15].GetUInt32());
+ SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS));
+ SetPower(POWER_HAPPINESS, fields[13].GetUInt32());
setPowerType(POWER_FOCUS);
break;
default:
- sLog.outError("Pet have incorrect type (%u) for pet loading.",getPetType());
+ sLog.outError("Pet have incorrect type (%u) for pet loading.", getPetType());
}
- InitStatsForLevel( petlevel);
+
SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32());
- SetUInt64Value(UNIT_FIELD_CREATEDBY, owner->GetGUID());
+ SetCreatorGUID(owner->GetGUID());
SetReactState( ReactStates( fields[6].GetUInt8() ));
- m_loyaltyPoints = fields[7].GetInt32();
- uint32 savedhealth = fields[13].GetUInt32();
- uint32 savedmana = fields[14].GetUInt32();
+ SetCanModifyStats(true);
+ InitStatsForLevel(petlevel);
- // set current pet as current
- if(fields[10].GetUInt32() != 0)
+ if(getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current
{
- CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("UPDATE character_pet SET slot = '3' WHERE owner = '%u' AND slot = '0' AND id <> '%u'",ownerid, m_charmInfo->GetPetNumber());
- CharacterDatabase.PExecute("UPDATE character_pet SET slot = '0' WHERE owner = '%u' AND id = '%u'",ownerid, m_charmInfo->GetPetNumber());
- CharacterDatabase.CommitTransaction();
+ SetHealth(GetMaxHealth());
+ SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
}
-
- if(!is_temporary_summoned)
+ else
{
- // permanent controlled pets store state in DB
- Tokens tokens = StrSplit(fields[16].GetString(), " ");
-
- if(tokens.size() != 20)
- {
- delete result;
- return false;
- }
-
- int index;
- Tokens::iterator iter;
- for(iter = tokens.begin(), index = 0; index < 10; ++iter, ++index )
- {
- m_charmInfo->GetActionBarEntry(index)->Type = atol((*iter).c_str());
- ++iter;
- m_charmInfo->GetActionBarEntry(index)->SpellOrAction = atol((*iter).c_str());
-
- // patch for old data where some spells have ACT_DECIDE but should have ACT_CAST
- // so overwrite old state
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_charmInfo->GetActionBarEntry(index)->SpellOrAction);
- if (spellInfo && spellInfo->AttributesEx & SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET) m_charmInfo->GetActionBarEntry(index)->Type = ACT_CAST;
- }
-
- //init teach spells
- tokens = StrSplit(fields[17].GetString(), " ");
- for (iter = tokens.begin(), index = 0; index < 4; ++iter, ++index)
- {
- uint32 tmp = atol((*iter).c_str());
-
- ++iter;
-
- if(tmp)
- AddTeachSpell(tmp, atol((*iter).c_str()));
- else
- break;
- }
+ uint32 savedhealth = fields[11].GetUInt32();
+ uint32 savedmana = fields[12].GetUInt32();
+ SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
+ SetPower(POWER_MANA, savedmana > GetMaxPower(POWER_MANA) ? GetMaxPower(POWER_MANA) : savedmana);
}
- // since last save (in seconds)
- uint32 timediff = (time(NULL) - fields[18].GetUInt32());
+ owner->SetMinion(this, true);
+ map->Add((Creature*)this);
- delete result;
+ m_resetTalentsCost = fields[16].GetUInt32();
+ m_resetTalentsTime = fields[17].GetUInt64();
+ InitTalentForLevel();
- //load spells/cooldowns/auras
- SetCanModifyStats(true);
+ uint32 timediff = (time(NULL) - fields[15].GetUInt32());
_LoadAuras(timediff);
- //init AB
- if(is_temporary_summoned)
+ uint8 loadFlags = fields[20].GetUInt8();
+ owner->SetPetAtLoginFlag(loadFlags);
+ if (loadFlags & AT_LOAD_RESET_SPELLS)
{
- // Temporary summoned pets always have initial spell list at load
+ CharacterDatabase.PExecute("UPDATE character_pet SET load_flags = load_flags & ~ %u WHERE id = '%u'",uint32(AT_LOAD_RESET_SPELLS),pet_number);
+ loadFlags &= ~uint8(AT_LOAD_RESET_SPELLS);
+ CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u'",pet_number);
InitPetCreateSpells();
+ resetTalents(true);
}
else
{
- LearnPetPassives();
- CastPetAuras(current);
- }
+ // Load action bar data
+ if (!is_temporary_summoned)
+ {
+ // permanent controlled pets store state in DB
+ Tokens tokens = StrSplit(fields[14].GetString(), " ");
- if(getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current
- {
- SetHealth(GetMaxHealth());
- SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
- }
- else
- {
- SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
- SetPower(POWER_MANA, savedmana > GetMaxPower(POWER_MANA) ? GetMaxPower(POWER_MANA) : savedmana);
- }
+ if (tokens.size() != 20)
+ {
+ delete result;
+ return false;
+ }
- AIM_Initialize();
- map->Add((Creature*)this);
+ int index;
+ Tokens::iterator iter;
+ for(iter = tokens.begin(), index = 0; index < 10; ++iter, ++index )
+ {
+ m_charmInfo->GetActionBarEntry(index)->Type = atol((*iter).c_str());
+ ++iter;
+ m_charmInfo->GetActionBarEntry(index)->SpellOrAction = atol((*iter).c_str());
+ if(m_charmInfo->GetActionBarEntry(index)->Type == ACT_ENABLED && !IsAutocastableSpell(m_charmInfo->GetActionBarEntry(index)->SpellOrAction))
+ m_charmInfo->GetActionBarEntry(index)->Type = ACT_PASSIVE;
+ }
- // Spells should be loaded after pet is added to map, because in CanCast is check on it
- _LoadSpells();
- _LoadSpellCooldowns();
+ _LoadSpells();
+ _LoadSpellCooldowns();
+ LearnPetPassives();
+ InitLevelupSpellsForLevel();
+ CastPetAuras(current);
+ }
+ }
- owner->SetPet(this); // in DB stored only full controlled creature
+ delete result;
sLog.outDebug("New Pet has guid %u", GetGUIDLow());
- if(owner->GetTypeId() == TYPEID_PLAYER)
- {
- ((Player*)owner)->PetSpellInitialize();
- if(((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_PET);
- }
+ owner->PetSpellInitialize();
+
+ if(owner->GetGroup())
+ owner->SetGroupUpdateFlag(GROUP_UPDATE_PET);
- if(owner->GetTypeId() == TYPEID_PLAYER && getPetType() == HUNTER_PET)
+ if(getPetType() == HUNTER_PET)
{
result = CharacterDatabase.PQuery("SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", owner->GetGUIDLow(), GetCharmInfo()->GetPetNumber());
@@ -373,129 +321,122 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu
delete m_declinedname;
m_declinedname = new DeclinedName;
- Field *fields = result->Fetch();
+ Field *fields2 = result->Fetch();
for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
{
- m_declinedname->name[i] = fields[i].GetCppString();
+ m_declinedname->name[i] = fields2[i].GetCppString();
}
}
}
+ //InitLevelupSpellsForLevel();
+
+ m_loading = false;
+
+ SynchronizeLevelWithOwner();
return true;
}
void Pet::SavePetToDB(PetSaveMode mode)
{
- if(!GetEntry())
+ if (!GetEntry())
return;
// save only fully controlled creature
- if(!isControlled())
+ if (!isControlled())
+ return;
+
+ // not save not player pets
+ if(!IS_PLAYER_GUID(GetOwnerGUID()))
return;
+ Player* pOwner = (Player*)GetOwner();
+ if (!pOwner)
+ return;
+
+ // not save pet as current if another pet temporary unsummoned
+ if (mode == PET_SAVE_AS_CURRENT && pOwner->GetTemporaryUnsummonedPetNumber() &&
+ pOwner->GetTemporaryUnsummonedPetNumber() != m_charmInfo->GetPetNumber())
+ {
+ // pet will lost anyway at restore temporary unsummoned
+ if(getPetType()==HUNTER_PET)
+ return;
+
+ // for warlock case
+ mode = PET_SAVE_NOT_IN_SLOT;
+ }
+
uint32 curhealth = GetHealth();
uint32 curmana = GetPower(POWER_MANA);
- switch(mode)
+ // stable and not in slot saves
+ if(mode > PET_SAVE_AS_CURRENT)
{
- case PET_SAVE_IN_STABLE_SLOT_1:
- case PET_SAVE_IN_STABLE_SLOT_2:
- case PET_SAVE_NOT_IN_SLOT:
- {
- RemoveAllAuras();
-
- //only alive hunter pets get auras saved, the others don't
- if(!(getPetType() == HUNTER_PET && isAlive()))
- m_Auras.clear();
- }
- default:
- break;
+ RemoveAllAuras();
}
_SaveSpells();
_SaveSpellCooldowns();
_SaveAuras();
- switch(mode)
+ // current/stable/not_in_slot
+ if(mode >= PET_SAVE_AS_CURRENT)
{
- case PET_SAVE_AS_CURRENT:
- case PET_SAVE_IN_STABLE_SLOT_1:
- case PET_SAVE_IN_STABLE_SLOT_2:
- case PET_SAVE_NOT_IN_SLOT:
- {
- uint32 loyalty =1;
- if(getPetType()!=HUNTER_PET)
- loyalty = GetLoyaltyLevel();
-
- uint32 owner = GUID_LOPART(GetOwnerGUID());
- std::string name = m_name;
- CharacterDatabase.escape_string(name);
- CharacterDatabase.BeginTransaction();
- // remove current data
- CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND id = '%u'", owner,m_charmInfo->GetPetNumber() );
-
- // prevent duplicate using slot (except PET_SAVE_NOT_IN_SLOT)
- if(mode!=PET_SAVE_NOT_IN_SLOT)
- CharacterDatabase.PExecute("UPDATE character_pet SET slot = 3 WHERE owner = '%u' AND slot = '%u'", owner, uint32(mode) );
-
- // prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT
- if(getPetType()==HUNTER_PET && (mode==PET_SAVE_AS_CURRENT||mode==PET_SAVE_NOT_IN_SLOT))
- CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND (slot = '0' OR slot = '3')", owner );
- // save pet
- std::ostringstream ss;
- ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata,TeachSpelldata,savetime,resettalents_cost,resettalents_time,CreatedBySpell,PetType) "
- << "VALUES ("
- << m_charmInfo->GetPetNumber() << ", "
- << GetEntry() << ", "
- << owner << ", "
- << GetNativeDisplayId() << ", "
- << getLevel() << ", "
- << GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ", "
- << uint32(GetReactState()) << ", "
- << m_loyaltyPoints << ", "
- << GetLoyaltyLevel() << ", "
- << m_TrainingPoints << ", "
- << uint32(mode) << ", '"
- << name.c_str() << "', "
- << uint32((GetByteValue(UNIT_FIELD_BYTES_2, 2) == UNIT_RENAME_ALLOWED)?0:1) << ", "
- << (curhealth<1?1:curhealth) << ", "
- << curmana << ", "
- << GetPower(POWER_HAPPINESS) << ", '";
-
- for(uint32 i = 0; i < 10; i++)
- ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " ";
- ss << "', '";
-
- //save spells the pet can teach to it's Master
- {
- int i = 0;
- for(TeachSpellMap::iterator itr = m_teachspells.begin(); i < 4 && itr != m_teachspells.end(); ++i, ++itr)
- ss << itr->first << " " << itr->second << " ";
- for(; i < 4; ++i)
- ss << uint32(0) << " " << uint32(0) << " ";
- }
-
- ss << "', "
- << time(NULL) << ", "
- << uint32(m_resetTalentsCost) << ", "
- << uint64(m_resetTalentsTime) << ", "
- << GetUInt32Value(UNIT_CREATED_BY_SPELL) << ", "
- << uint32(getPetType()) << ")";
-
- CharacterDatabase.Execute( ss.str().c_str() );
-
- CharacterDatabase.CommitTransaction();
- break;
- }
- case PET_SAVE_AS_DELETED:
- {
- RemoveAllAuras();
- DeleteFromDB(m_charmInfo->GetPetNumber());
- break;
- }
- default:
- sLog.outError("Unknown pet save/remove mode: %d",mode);
+ uint32 owner = GUID_LOPART(GetOwnerGUID());
+ std::string name = m_name;
+ CharacterDatabase.escape_string(name);
+ CharacterDatabase.BeginTransaction();
+ // remove current data
+ CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND id = '%u'", owner,m_charmInfo->GetPetNumber() );
+
+ // prevent duplicate using slot (except PET_SAVE_NOT_IN_SLOT)
+ if(mode <= PET_SAVE_LAST_STABLE_SLOT)
+ CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND slot = '%u'",
+ PET_SAVE_NOT_IN_SLOT, owner, uint32(mode) );
+
+ // prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT
+ if(getPetType()==HUNTER_PET && (mode==PET_SAVE_AS_CURRENT||mode > PET_SAVE_LAST_STABLE_SLOT))
+ CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u')",
+ owner,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT);
+ // save pet
+ std::ostringstream ss;
+ ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags) "
+ << "VALUES ("
+ << m_charmInfo->GetPetNumber() << ", "
+ << GetEntry() << ", "
+ << owner << ", "
+ << GetNativeDisplayId() << ", "
+ << getLevel() << ", "
+ << GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ", "
+ << uint32(GetReactState()) << ", "
+ << uint32(GetFreeTalentPoints()) << ", "
+ << uint32(mode) << ", '"
+ << name.c_str() << "', "
+ << uint32((GetByteValue(UNIT_FIELD_BYTES_2, 2) == UNIT_RENAME_ALLOWED)?0:1) << ", "
+ << (curhealth<1?1:curhealth) << ", "
+ << curmana << ", "
+ << GetPower(POWER_HAPPINESS) << ", '";
+
+ for(uint32 i = 0; i < 10; ++i)
+ ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " ";
+ ss << "', "
+ << time(NULL) << ", "
+ << uint32(m_resetTalentsCost) << ", "
+ << uint64(m_resetTalentsTime) << ", "
+ << GetUInt32Value(UNIT_CREATED_BY_SPELL) << ", "
+ << uint32(getPetType()) << ", "
+ << (pOwner->GetAtLoginFlag()>>AT_LOAD_PET_FLAGS) << ")";
+
+ CharacterDatabase.Execute( ss.str().c_str() );
+ CharacterDatabase.CommitTransaction();
}
+ // delete
+ else
+ {
+ RemoveAllAuras();
+ DeleteFromDB(m_charmInfo->GetPetNumber());
+ }
+ pOwner->SetPetAtLoginFlag(0);
}
void Pet::DeleteFromDB(uint32 guidlow)
@@ -512,11 +453,7 @@ void Pet::setDeathState(DeathState s) // overwrite virtual
Creature::setDeathState(s);
if(getDeathState()==CORPSE)
{
- //remove summoned pet (no corpse)
- if(getPetType()==SUMMON_PET)
- Remove(PET_SAVE_NOT_IN_SLOT);
- // other will despawn at corpse desppawning (Pet::Update code)
- else
+ if(getPetType() == HUNTER_PET)
{
// pet corpse non lootable and non skinnable
SetUInt32Value( UNIT_DYNAMIC_FLAGS, 0x00 );
@@ -527,12 +464,12 @@ void Pet::setDeathState(DeathState s) // overwrite virtual
if(!mapEntry || (mapEntry->map_type != MAP_ARENA && mapEntry->map_type != MAP_BATTLEGROUND))
ModifyPower(POWER_HAPPINESS, -HAPPINESS_LEVEL_SIZE);
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
}
}
else if(getDeathState()==ALIVE)
{
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
CastPetAuras(true);
}
}
@@ -546,9 +483,8 @@ void Pet::Update(uint32 diff)
{
case CORPSE:
{
- if( m_deathTimer <= diff )
+ if(getPetType() != HUNTER_PET || m_deathTimer <= diff )
{
- assert(getPetType()!=SUMMON_PET && "Must be already removed.");
Remove(PET_SAVE_NOT_IN_SLOT); //hunters' pets never get removed because of death, NEVER!
return;
}
@@ -557,8 +493,9 @@ void Pet::Update(uint32 diff)
case ALIVE:
{
// unsummon pet that lost owner
- Unit* owner = GetOwner();
+ Player* owner = GetOwner();
if(!owner || (!IsWithinDistInMap(owner, OWNER_MAX_DISTANCE) && !isPossessed()) || isControlled() && !owner->GetPetGUID())
+ //if(!owner || (!IsWithinDistInMap(owner, OWNER_MAX_DISTANCE) && (owner->GetCharmGUID() && (owner->GetCharmGUID() != GetGUID()))) || (isControlled() && !owner->GetPetGUID()))
{
Remove(PET_SAVE_NOT_IN_SLOT, true);
return;
@@ -568,6 +505,7 @@ void Pet::Update(uint32 diff)
{
if( owner->GetPetGUID() != GetGUID() )
{
+ sLog.outError("Pet %u is not pet of owner %u, removed", GetEntry(), m_owner->GetName());
Remove(getPetType()==HUNTER_PET?PET_SAVE_AS_DELETED:PET_SAVE_NOT_IN_SLOT);
return;
}
@@ -584,18 +522,26 @@ void Pet::Update(uint32 diff)
}
}
- if(getPetType() != HUNTER_PET)
- break;
-
- //regenerate Focus
+ //regenerate focus for hunter pets or energy for deathknight's ghoul
if(m_regenTimer <= diff)
{
- RegenerateFocus();
+ switch (getPowerType())
+ {
+ case POWER_FOCUS:
+ case POWER_ENERGY:
+ Regenerate(getPowerType());
+ break;
+ default:
+ break;
+ }
m_regenTimer = 4000;
}
else
m_regenTimer -= diff;
+ if(getPetType() != HUNTER_PET)
+ break;
+
if(m_happinessTimer <= diff)
{
LooseHappiness();
@@ -604,14 +550,6 @@ void Pet::Update(uint32 diff)
else
m_happinessTimer -= diff;
- if(m_loyaltyTimer <= diff)
- {
- TickLoyaltyChange();
- m_loyaltyTimer = 12000;
- }
- else
- m_loyaltyTimer -= diff;
-
break;
}
default:
@@ -620,104 +558,52 @@ void Pet::Update(uint32 diff)
Creature::Update(diff);
}
-void Pet::RegenerateFocus()
+void Pet::Regenerate(Powers power)
{
- uint32 curValue = GetPower(POWER_FOCUS);
- uint32 maxValue = GetMaxPower(POWER_FOCUS);
+ uint32 curValue = GetPower(power);
+ uint32 maxValue = GetMaxPower(power);
if (curValue >= maxValue)
return;
- float addvalue = 24 * sWorld.getRate(RATE_POWER_FOCUS);
-
- AuraList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
- for(AuraList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
- if ((*i)->GetModifier()->m_miscvalue == POWER_FOCUS)
- addvalue *= ((*i)->GetModifierValue() + 100) / 100.0f;
-
- ModifyPower(POWER_FOCUS, (int32)addvalue);
-}
-
-void Pet::LooseHappiness()
-{
- uint32 curValue = GetPower(POWER_HAPPINESS);
- if (curValue <= 0)
- return;
- int32 addvalue = (140 >> GetLoyaltyLevel()) * 125; //value is 70/35/17/8/4 (per min) * 1000 / 8 (timer 7.5 secs)
- if(isInCombat()) //we know in combat happiness fades faster, multiplier guess
- addvalue = int32(addvalue * 1.5);
- ModifyPower(POWER_HAPPINESS, -addvalue);
-}
-
-void Pet::ModifyLoyalty(int32 addvalue)
-{
- uint32 loyaltylevel = GetLoyaltyLevel();
-
- if(addvalue > 0) //only gain influenced, not loss
- addvalue = int32((float)addvalue * sWorld.getRate(RATE_LOYALTY));
-
- if(loyaltylevel >= BEST_FRIEND && (addvalue + m_loyaltyPoints) > int32(GetMaxLoyaltyPoints(loyaltylevel)))
- return;
-
- m_loyaltyPoints += addvalue;
+ float addvalue = 0.0f;
- if(m_loyaltyPoints < 0)
+ switch (power)
{
- if(loyaltylevel > REBELLIOUS)
+ case POWER_FOCUS:
{
- //level down
- --loyaltylevel;
- SetLoyaltyLevel(LoyaltyLevel(loyaltylevel));
- m_loyaltyPoints = GetStartLoyaltyPoints(loyaltylevel);
- SetTP(m_TrainingPoints - int32(getLevel()));
+ // For hunter pets.
+ addvalue = 24 * sWorld.getRate(RATE_POWER_FOCUS);
+ break;
}
- else
+ case POWER_ENERGY:
{
- m_loyaltyPoints = 0;
- Unit* owner = GetOwner();
- if(owner && owner->GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_PET_BROKEN, 0);
- ((Player*)owner)->GetSession()->SendPacket(&data);
-
- //run away
- ((Player*)owner)->RemovePet(this,PET_SAVE_AS_DELETED);
- }
+ // For deathknight's ghoul.
+ addvalue = 20;
+ break;
}
- }
- //level up
- else if(m_loyaltyPoints > int32(GetMaxLoyaltyPoints(loyaltylevel)))
- {
- ++loyaltylevel;
- SetLoyaltyLevel(LoyaltyLevel(loyaltylevel));
- m_loyaltyPoints = GetStartLoyaltyPoints(loyaltylevel);
- SetTP(m_TrainingPoints + getLevel());
- }
-}
-
-void Pet::TickLoyaltyChange()
-{
- int32 addvalue;
-
- switch(GetHappinessState())
- {
- case HAPPY: addvalue = 20; break;
- case CONTENT: addvalue = 10; break;
- case UNHAPPY: addvalue = -20; break;
default:
return;
}
- ModifyLoyalty(addvalue);
+
+ // Apply modifiers (if any).
+ AuraEffectList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
+ for(AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
+ if ((*i)->GetMiscValue() == power)
+ addvalue *= ((*i)->GetAmount() + 100) / 100.0f;
+
+ ModifyPower(power, (int32)addvalue);
}
-void Pet::KillLoyaltyBonus(uint32 level)
+void Pet::LooseHappiness()
{
- if(level > 100)
+ uint32 curValue = GetPower(POWER_HAPPINESS);
+ if (curValue <= 0)
return;
-
- //at lower levels gain is faster | the lower loyalty the more loyalty is gained
- uint32 bonus = uint32(((100 - level) / 10) + (6 - GetLoyaltyLevel()));
- ModifyLoyalty(bonus);
+ int32 addvalue = 670; //value is 70/35/17/8/4 (per min) * 1000 / 8 (timer 7.5 secs)
+ if(isInCombat()) //we know in combat happiness fades faster, multiplier guess
+ addvalue = int32(addvalue * 1.5);
+ ModifyPower(POWER_HAPPINESS, -addvalue);
}
HappinessState Pet::GetHappinessState()
@@ -730,11 +616,6 @@ HappinessState Pet::GetHappinessState()
return CONTENT;
}
-void Pet::SetLoyaltyLevel(LoyaltyLevel level)
-{
- SetByteValue(UNIT_FIELD_BYTES_1, 1, level);
-}
-
bool Pet::CanTakeMoreActiveSpells(uint32 spellid)
{
uint8 activecount = 1;
@@ -745,8 +626,11 @@ bool Pet::CanTakeMoreActiveSpells(uint32 spellid)
chainstartstore[0] = spellmgr.GetFirstSpellInChain(spellid);
- for (PetSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
+ for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
{
+ if(itr->second.state == PETSPELL_REMOVED)
+ continue;
+
if(IsPassiveSpell(itr->first))
continue;
@@ -771,102 +655,9 @@ bool Pet::CanTakeMoreActiveSpells(uint32 spellid)
return true;
}
-bool Pet::HasTPForSpell(uint32 spellid)
-{
- int32 neededtrainp = GetTPForSpell(spellid);
- if((m_TrainingPoints - neededtrainp < 0 || neededtrainp < 0) && neededtrainp != 0)
- return false;
- return true;
-}
-
-int32 Pet::GetTPForSpell(uint32 spellid)
-{
- uint32 basetrainp = 0;
-
- SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spellid);
- SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spellid);
- for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
- {
- if(!_spell_idx->second->reqtrainpoints)
- return 0;
-
- basetrainp = _spell_idx->second->reqtrainpoints;
- break;
- }
-
- uint32 spenttrainp = 0;
- uint32 chainstart = spellmgr.GetFirstSpellInChain(spellid);
-
- for (PetSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
- {
- if(itr->second->state == PETSPELL_REMOVED)
- continue;
-
- if(spellmgr.GetFirstSpellInChain(itr->first) == chainstart)
- {
- SkillLineAbilityMap::const_iterator _lower = spellmgr.GetBeginSkillLineAbilityMap(itr->first);
- SkillLineAbilityMap::const_iterator _upper = spellmgr.GetEndSkillLineAbilityMap(itr->first);
-
- for(SkillLineAbilityMap::const_iterator _spell_idx2 = _lower; _spell_idx2 != _upper; ++_spell_idx2)
- {
- if(_spell_idx2->second->reqtrainpoints > spenttrainp)
- {
- spenttrainp = _spell_idx2->second->reqtrainpoints;
- break;
- }
- }
- }
- }
-
- return int32(basetrainp) - int32(spenttrainp);
-}
-
-uint32 Pet::GetMaxLoyaltyPoints(uint32 level)
-{
- return LevelUpLoyalty[level - 1];
-}
-
-uint32 Pet::GetStartLoyaltyPoints(uint32 level)
-{
- return LevelStartLoyalty[level - 1];
-}
-
-void Pet::SetTP(int32 TP)
-{
- m_TrainingPoints = TP;
- SetUInt32Value(UNIT_TRAINING_POINTS, (uint32)GetDispTP());
-}
-
-int32 Pet::GetDispTP()
-{
- if(getPetType()!= HUNTER_PET)
- return(0);
- if(m_TrainingPoints < 0)
- return -m_TrainingPoints;
- else
- return -(m_TrainingPoints + 1);
-}
-
void Pet::Remove(PetSaveMode mode, bool returnreagent)
{
- Unit* owner = GetOwner();
-
- if(owner)
- {
- if(owner->GetTypeId()==TYPEID_PLAYER)
- {
- ((Player*)owner)->RemovePet(this,mode,returnreagent);
- return;
- }
-
- // only if current pet in slot
- if(owner->GetPetGUID()==GetGUID())
- owner->SetPet(0);
- }
-
- CleanupsBeforeDelete();
- AddObjectToRemoveList();
- m_removed = true;
+ m_owner->RemovePet(this,mode,returnreagent);
}
void Pet::GivePetXP(uint32 xp)
@@ -900,18 +691,14 @@ void Pet::GivePetXP(uint32 xp)
{
newXP -= nextLvlXP;
- SetLevel( level + 1 );
- SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, uint32((Trinity::XP::xp_to_level(level+1))/4));
+ GivePetLevel(level+1);
+ SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(level+1)*PET_XP_FACTOR);
level = getLevel();
nextLvlXP = GetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP);
- GivePetLevel(level);
}
SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, newXP);
-
- if(getPetType() == HUNTER_PET)
- KillLoyaltyBonus(level);
}
void Pet::GivePetLevel(uint32 level)
@@ -919,16 +706,16 @@ void Pet::GivePetLevel(uint32 level)
if(!level)
return;
- InitStatsForLevel( level);
-
- SetTP(m_TrainingPoints + (GetLoyaltyLevel() - 1));
+ InitStatsForLevel(level);
+ InitLevelupSpellsForLevel();
+ InitTalentForLevel();
}
bool Pet::CreateBaseAtCreature(Creature* creature)
{
if(!creature)
{
- sLog.outError("CRITICAL ERROR: NULL pointer parsed into CreateBaseAtCreature()");
+ sLog.outError("CRITICAL: NULL pointer parsed into CreateBaseAtCreature()");
return false;
}
uint32 guid=objmgr.GenerateLowGuid(HIGHGUID_PET);
@@ -938,14 +725,14 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
sLog.outDebug("Create pet");
uint32 pet_number = objmgr.GeneratePetNumber();
- if(!Create(guid, creature->GetMap(), creature->GetEntry(), pet_number))
+ if(!Create(guid, creature->GetMap(), creature->GetPhaseMask(), creature->GetEntry(), pet_number))
return false;
Relocate(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
if(!IsPositionValid())
{
- sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
+ sLog.outError("Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
GetGUIDLow(), GetEntry(), GetPositionX(), GetPositionY());
return false;
}
@@ -953,15 +740,10 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
CreatureInfo const *cinfo = GetCreatureInfo();
if(!cinfo)
{
- sLog.outError("ERROR: CreateBaseAtCreature() failed, creatureInfo is missing!");
+ sLog.outError("CreateBaseAtCreature() failed, creatureInfo is missing!");
return false;
}
- if(cinfo->type == CREATURE_TYPE_CRITTER)
- {
- setPetType(MINI_PET);
- return true;
- }
SetDisplayId(creature->GetDisplayId());
SetNativeDisplayId(creature->GetNativeDisplayId());
SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS));
@@ -969,45 +751,44 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
setPowerType(POWER_FOCUS);
SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
- SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, uint32((Trinity::XP::xp_to_level(creature->getLevel()))/4));
- SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+ SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(creature->getLevel())*PET_XP_FACTOR);
SetUInt32Value(UNIT_NPC_FLAGS, 0);
- CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(creature->GetCreatureInfo()->family);
- if( char* familyname = cFamily->Name[sWorld.GetDefaultDbcLocale()] )
- SetName(familyname);
+ if(CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family))
+ SetName(cFamily->Name[sWorld.GetDefaultDbcLocale()]);
else
- SetName(creature->GetName());
+ SetName(creature->GetNameForLocaleIdx(objmgr.GetDBCLocaleIndex()));
- m_loyaltyPoints = 1000;
if(cinfo->type == CREATURE_TYPE_BEAST)
{
SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100);
SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE );
- SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY | UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5 );
SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);
-
- SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED) );
- SetLoyaltyLevel(REBELLIOUS);
+ SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED));
}
return true;
}
-bool Pet::InitStatsForLevel(uint32 petlevel)
+bool Guardian::InitStatsForLevel(uint32 petlevel)
{
CreatureInfo const *cinfo = GetCreatureInfo();
assert(cinfo);
- Unit* owner = GetOwner();
- if(!owner)
+ SetLevel(petlevel);
+
+ //Determine pet type
+ PetType petType = MAX_PET_TYPE;
+ if(HasSummonMask(SUMMON_MASK_PET) && m_owner->GetTypeId() == TYPEID_PLAYER)
{
- sLog.outError("ERROR: attempt to summon pet (Entry %u) without owner! Attempt terminated.", cinfo->Entry);
- return false;
+ if(m_owner->getClass() == CLASS_WARLOCK)
+ petType = SUMMON_PET;
+ else if(m_owner->getClass() == CLASS_HUNTER)
+ petType = HUNTER_PET;
+ else
+ sLog.outError("Unknown type pet %u is summoned by player class %u", GetEntry(), m_owner->getClass());
}
- uint32 creature_ID = (getPetType() == HUNTER_PET) ? 1 : cinfo->Entry;
-
- SetLevel(petlevel);
+ uint32 creature_ID = (petType == HUNTER_PET) ? 1 : cinfo->Entry;
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
@@ -1019,8 +800,9 @@ bool Pet::InitStatsForLevel(uint32 petlevel)
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0);
+ //scale
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family);
- if(cFamily && cFamily->minScale > 0.0f && getPetType()==HUNTER_PET)
+ if(cFamily && cFamily->minScale > 0.0f && petType==HUNTER_PET)
{
float scale;
if (getLevel() >= cFamily->maxScaleLevel)
@@ -1028,15 +810,14 @@ bool Pet::InitStatsForLevel(uint32 petlevel)
else if (getLevel() <= cFamily->minScaleLevel)
scale = cFamily->minScale;
else
- scale = cFamily->minScale + (getLevel() - cFamily->minScaleLevel) / cFamily->maxScaleLevel * (cFamily->maxScale - cFamily->minScale);
+ scale = cFamily->minScale + float(getLevel() - cFamily->minScaleLevel) / cFamily->maxScaleLevel * (cFamily->maxScale - cFamily->minScale);
SetFloatValue(OBJECT_FIELD_SCALE_X, scale);
}
- m_bonusdamage = 0;
+ //resistance
int32 createResistance[MAX_SPELL_SCHOOL] = {0,0,0,0,0,0,0};
-
- if(cinfo && getPetType() != HUNTER_PET)
+ if(cinfo && petType != HUNTER_PET)
{
createResistance[SPELL_SCHOOL_HOLY] = cinfo->resistance1;
createResistance[SPELL_SCHOOL_FIRE] = cinfo->resistance2;
@@ -1045,158 +826,125 @@ bool Pet::InitStatsForLevel(uint32 petlevel)
createResistance[SPELL_SCHOOL_SHADOW] = cinfo->resistance5;
createResistance[SPELL_SCHOOL_ARCANE] = cinfo->resistance6;
}
+ for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
+ SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(createResistance[i]));
- switch(getPetType())
+ //health, mana, armor and resistance
+ PetLevelInfo const* pInfo = objmgr.GetPetLevelInfo(creature_ID, petlevel);
+ if(pInfo) // exist in DB
{
- case SUMMON_PET:
- {
- if(owner->GetTypeId() == TYPEID_PLAYER)
- {
- switch(owner->getClass())
- {
- case CLASS_WARLOCK:
- {
+ SetCreateHealth(pInfo->health);
+ if(petType != HUNTER_PET) //hunter pet use focus
+ SetCreateMana(pInfo->mana);
- //the damage bonus used for pets is either fire or shadow damage, whatever is higher
- uint32 fire = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE);
- uint32 shadow = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW);
- uint32 val = (fire > shadow) ? fire : shadow;
+ if(pInfo->armor > 0)
+ SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
- SetBonusDamage(int32 (val * 0.15f));
- //bonusAP += val * 0.57;
- break;
- }
- case CLASS_MAGE:
- {
- //40% damage bonus of mage's frost damage
- float val = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST) * 0.4;
- if(val < 0)
- val = 0;
- SetBonusDamage( int32(val));
- break;
- }
- default:
- break;
- }
- }
+ for(int stat = 0; stat < MAX_STATS; ++stat)
+ SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
+ }
+ else // not exist in DB, use some default fake data
+ {
+ // remove elite bonuses included in DB values
+ //SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) );
+ //SetCreateMana( uint32(((float(cinfo->maxmana) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) );
+
+ SetCreateStat(STAT_STRENGTH, 22);
+ SetCreateStat(STAT_AGILITY, 22);
+ SetCreateStat(STAT_STAMINA, 25);
+ SetCreateStat(STAT_INTELLECT, 28);
+ SetCreateStat(STAT_SPIRIT, 27);
+ }
+
+ m_bonusdamage = 0;
+ switch(petType)
+ {
+ case SUMMON_PET:
+ {
+ //the damage bonus used for pets is either fire or shadow damage, whatever is higher
+ uint32 fire = m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE);
+ uint32 shadow = m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW);
+ uint32 val = (fire > shadow) ? fire : shadow;
+ SetBonusDamage(int32 (val * 0.15f));
+ //bonusAP += val * 0.57;
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)) );
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)) );
//SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower));
-
- PetLevelInfo const* pInfo = objmgr.GetPetLevelInfo(creature_ID, petlevel);
- if(pInfo) // exist in DB
- {
- SetCreateHealth(pInfo->health);
- SetCreateMana(pInfo->mana);
-
- if(pInfo->armor > 0)
- SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
-
- for(int stat = 0; stat < MAX_STATS; ++stat)
- {
- SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
- }
- }
- else // not exist in DB, use some default fake data
- {
- sLog.outErrorDb("Summoned pet (Entry: %u) not have pet stats data in DB",cinfo->Entry);
-
- // remove elite bonuses included in DB values
- SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) );
- SetCreateMana( uint32(((float(cinfo->maxmana) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) );
-
- SetCreateStat(STAT_STRENGTH, 22);
- SetCreateStat(STAT_AGILITY, 22);
- SetCreateStat(STAT_STAMINA, 25);
- SetCreateStat(STAT_INTELLECT, 28);
- SetCreateStat(STAT_SPIRIT, 27);
- }
break;
}
case HUNTER_PET:
{
- SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, uint32((Trinity::XP::xp_to_level(petlevel))/4));
-
+ SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(petlevel)*PET_XP_FACTOR);
//these formula may not be correct; however, it is designed to be close to what it should be
//this makes dps 0.5 of pets level
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)) );
//damage range is then petlevel / 2
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)) );
//damage is increased afterwards as strength and pet scaling modify attack power
-
- //stored standard pet stats are entry 1 in pet_levelinfo
- PetLevelInfo const* pInfo = objmgr.GetPetLevelInfo(creature_ID, petlevel);
- if(pInfo) // exist in DB
- {
- SetCreateHealth(pInfo->health);
- SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
- //SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower));
-
- for( int i = STAT_STRENGTH; i < MAX_STATS; i++)
- {
- SetCreateStat(Stats(i), float(pInfo->stats[i]));
- }
- }
- else // not exist in DB, use some default fake data
- {
- sLog.outErrorDb("Hunter pet levelstats missing in DB");
-
- // remove elite bonuses included in DB values
- SetCreateHealth( uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) );
-
- SetCreateStat(STAT_STRENGTH, 22);
- SetCreateStat(STAT_AGILITY, 22);
- SetCreateStat(STAT_STAMINA, 25);
- SetCreateStat(STAT_INTELLECT, 28);
- SetCreateStat(STAT_SPIRIT, 27);
- }
break;
}
- case GUARDIAN_PET:
- SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
- SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
-
+ default:
+ {
switch(GetEntry())
{
+ case 510: // mage Water Elemental
+ {
+ //40% damage bonus of mage's frost damage
+ float val = m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST) * 0.4;
+ if(val < 0)
+ val = 0;
+ SetBonusDamage( int32(val));
+ break;
+ }
case 1964: //force of nature
- SetCreateHealth(30 + 30*petlevel);
+ {
+ if(!pInfo)
+ SetCreateHealth(30 + 30*petlevel);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 2.5f - (petlevel / 2)));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 2.5f + (petlevel / 2)));
break;
+ }
case 15352: //earth elemental 36213
- SetCreateHealth(100 + 120*petlevel);
+ {
+ if(!pInfo)
+ SetCreateHealth(100 + 120*petlevel);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
break;
+ }
case 15438: //fire elemental
- SetCreateHealth(40*petlevel);
- SetCreateMana(28 + 10*petlevel);
+ {
+ if(!pInfo)
+ {
+ SetCreateHealth(40*petlevel);
+ SetCreateMana(28 + 10*petlevel);
+ }
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 4 - petlevel));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 4 + petlevel));
break;
+ }
default:
- SetCreateMana(28 + 10*petlevel);
- SetCreateHealth(28 + 30*petlevel);
-
- // FIXME: this is wrong formula, possible each guardian pet have own damage formula
- //these formula may not be correct; however, it is designed to be close to what it should be
- //this makes dps 0.5 of pets level
- SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
- //damage range is then petlevel / 2
- SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
+ {
+ if(!pInfo)
+ {
+ SetCreateMana(28 + 10*petlevel);
+ SetCreateHealth(28 + 30*petlevel);
+ }
+ // FIXME: this is wrong formula, possible each guardian pet have own damage formula
+ //these formula may not be correct; however, it is designed to be close to what it should be
+ //this makes dps 0.5 of pets level
+ SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
+ //damage range is then petlevel / 2
+ SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
break;
+ }
}
break;
- default:
- sLog.outError("Pet have incorrect type (%u) for levelup.", getPetType());
- break;
+ }
}
- for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
- SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(createResistance[i]));
-
UpdateAllStats();
SetHealth(GetMaxHealth());
@@ -1272,7 +1020,7 @@ void Pet::_LoadSpellCooldowns()
continue;
data << uint32(spell_id);
- data << uint32(uint32(db_time-curTime)*1000); // in m.secs
+ data << uint32(uint32(db_time-curTime)*IN_MILISECONDS);
_AddCreatureSpellCooldown(spell_id,db_time);
@@ -1310,7 +1058,7 @@ void Pet::_SaveSpellCooldowns()
void Pet::_LoadSpells()
{
- QueryResult *result = CharacterDatabase.PQuery("SELECT spell,slot,active FROM pet_spell WHERE guid = '%u'",m_charmInfo->GetPetNumber());
+ QueryResult *result = CharacterDatabase.PQuery("SELECT spell,active FROM pet_spell WHERE guid = '%u'",m_charmInfo->GetPetNumber());
if(result)
{
@@ -1318,7 +1066,7 @@ void Pet::_LoadSpells()
{
Field *fields = result->Fetch();
- addSpell(fields[0].GetUInt16(), fields[2].GetUInt16(), PETSPELL_UNCHANGED, fields[1].GetUInt16());
+ addSpell(fields[0].GetUInt32(), ActiveStates(fields[1].GetUInt16()), PETSPELL_UNCHANGED);
}
while( result->NextRow() );
@@ -1328,63 +1076,67 @@ void Pet::_LoadSpells()
void Pet::_SaveSpells()
{
- for (PetSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
+ for (PetSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
{
++next;
- if (itr->second->type == PETSPELL_FAMILY) continue; // prevent saving family passives to DB
- if (itr->second->state == PETSPELL_REMOVED || itr->second->state == PETSPELL_CHANGED)
- CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u' and spell = '%u'", m_charmInfo->GetPetNumber(), itr->first);
- if (itr->second->state == PETSPELL_NEW || itr->second->state == PETSPELL_CHANGED)
- CharacterDatabase.PExecute("INSERT INTO pet_spell (guid,spell,slot,active) VALUES ('%u', '%u', '%u','%u')", m_charmInfo->GetPetNumber(), itr->first, itr->second->slotId,itr->second->active);
-
- if (itr->second->state == PETSPELL_REMOVED)
- _removeSpell(itr->first);
- else
- itr->second->state = PETSPELL_UNCHANGED;
+
+ // prevent saving family passives to DB
+ if (itr->second.type == PETSPELL_FAMILY)
+ continue;
+
+ switch(itr->second.state)
+ {
+ case PETSPELL_REMOVED:
+ CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u' and spell = '%u'", m_charmInfo->GetPetNumber(), itr->first);
+ m_spells.erase(itr);
+ continue;
+ case PETSPELL_CHANGED:
+ CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u' and spell = '%u'", m_charmInfo->GetPetNumber(), itr->first);
+ CharacterDatabase.PExecute("INSERT INTO pet_spell (guid,spell,active) VALUES ('%u', '%u', '%u')", m_charmInfo->GetPetNumber(), itr->first, itr->second.active);
+ break;
+ case PETSPELL_NEW:
+ CharacterDatabase.PExecute("INSERT INTO pet_spell (guid,spell,active) VALUES ('%u', '%u', '%u')", m_charmInfo->GetPetNumber(), itr->first, itr->second.active);
+ break;
+ case PETSPELL_UNCHANGED:
+ continue;
+ }
+
+ itr->second.state = PETSPELL_UNCHANGED;
}
}
void Pet::_LoadAuras(uint32 timediff)
{
- m_Auras.clear();
- for (int i = 0; i < TOTAL_AURAS; i++)
- m_modAuras[i].clear();
-
- // all aura related fields
- for(int i = UNIT_FIELD_AURA; i <= UNIT_FIELD_AURASTATE; ++i)
- SetUInt32Value(i, 0);
+ sLog.outDebug("Loading auras for pet %u",GetGUIDLow());
- QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber());
+ QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_mask,stackcount,amount0, amount1, amount2 ,maxduration,remaintime,remaincharges FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber());
if(result)
{
do
{
+ int32 damage[3];
Field *fields = result->Fetch();
uint64 caster_guid = fields[0].GetUInt64();
uint32 spellid = fields[1].GetUInt32();
- uint32 effindex = fields[2].GetUInt32();
- uint32 stackcount= fields[3].GetUInt32();
- int32 damage = (int32)fields[4].GetUInt32();
- int32 maxduration = (int32)fields[5].GetUInt32();
- int32 remaintime = (int32)fields[6].GetUInt32();
- int32 remaincharges = (int32)fields[7].GetUInt32();
+ uint32 effmask = fields[2].GetUInt32();
+ uint32 stackcount = fields[3].GetUInt32();
+ damage[0] = int32(fields[4].GetUInt32());
+ damage[1] = int32(fields[5].GetUInt32());
+ damage[2] = int32(fields[6].GetUInt32());
+ int32 maxduration = (int32)fields[7].GetUInt32();
+ int32 remaintime = (int32)fields[8].GetUInt32();
+ int32 remaincharges = (int32)fields[9].GetUInt32();
SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid);
if(!spellproto)
{
- sLog.outError("Unknown aura (spellid %u, effindex %u), ignore.",spellid,effindex);
- continue;
- }
-
- if(effindex >= 3)
- {
- sLog.outError("Invalid effect index (spellid %u, effindex %u), ignore.",spellid,effindex);
+ sLog.outError("Unknown aura (spellid %u), ignore.",spellid);
continue;
}
// negative effects should continue counting down after logout
- if (remaintime != -1 && !IsPositiveEffect(spellid, effindex))
+ if (remaintime != -1 && !IsPositiveSpell(spellid))
{
if(remaintime <= int32(timediff))
continue;
@@ -1399,21 +1151,12 @@ void Pet::_LoadAuras(uint32 timediff)
remaincharges = spellproto->procCharges;
}
else
- remaincharges = -1;
+ remaincharges = 0;
- /// do not load single target auras (unless they were cast by the player)
- if (caster_guid != GetGUID() && IsSingleTargetSpell(spellproto))
- continue;
-
- for(uint32 i=0; i<stackcount; i++)
- {
- Aura* aura = CreateAura(spellproto, effindex, NULL, this, NULL);
-
- if(!damage)
- damage = aura->GetModifier()->m_amount;
- aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges);
- AddAura(aura);
- }
+ Aura* aura = new Aura(spellproto, effmask, NULL, this, NULL, NULL);
+ aura->SetLoadedState(caster_guid,maxduration,remaintime,remaincharges, stackcount, &damage[0]);
+ AddAura(aura);
+ sLog.outDetail("Added aura spellid %u, effectmask %u", spellproto->Id, effmask);
}
while( result->NextRow() );
@@ -1426,56 +1169,36 @@ void Pet::_SaveAuras()
CharacterDatabase.PExecute("DELETE FROM pet_aura WHERE guid = '%u'", m_charmInfo->GetPetNumber());
AuraMap const& auras = GetAuras();
- if (auras.empty())
- return;
-
- spellEffectPair lastEffectPair = auras.begin()->first;
- uint32 stackCounter = 1;
-
- for(AuraMap::const_iterator itr = auras.begin(); ; ++itr)
+ for(AuraMap::const_iterator itr = auras.begin(); itr !=auras.end() ; ++itr)
{
- if(itr == auras.end() || lastEffectPair != itr->first)
- {
- AuraMap::const_iterator itr2 = itr;
- // save previous spellEffectPair to db
- itr2--;
- SpellEntry const *spellInfo = itr2->second->GetSpellProto();
- /// do not save single target auras (unless they were cast by the player)
- if (!(itr2->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(spellInfo)))
- {
- if(!itr2->second->IsPassive())
- {
- // skip all auras from spell that apply at cast SPELL_AURA_MOD_SHAPESHIFT or pet area auras.
- uint8 i;
- for (i = 0; i < 3; i++)
- if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH ||
- spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_OWNER ||
- spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PET )
- break;
-
- if (i == 3)
- {
- CharacterDatabase.PExecute("INSERT INTO pet_aura (guid,caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges) "
- "VALUES ('%u', '" I64FMTD "', '%u', '%u', '%u', '%d', '%d', '%d', '%d')",
- m_charmInfo->GetPetNumber(), itr2->second->GetCasterGUID(),(uint32)itr2->second->GetId(), (uint32)itr2->second->GetEffIndex(), (uint32)itr2->second->GetStackAmount(), itr2->second->GetModifier()->m_amount,int(itr2->second->GetAuraMaxDuration()),int(itr2->second->GetAuraDuration()),int(itr2->second->m_procCharges));
- }
- }
- }
- if(itr == auras.end())
- break;
- }
+ // skip all auras from spell that apply at cast SPELL_AURA_MOD_SHAPESHIFT or pet area auras.
+ // do not save single target auras (unless they were cast by the player)
+ if (itr->second->IsPassive() || itr->second->IsAuraType(SPELL_AURA_MOD_STEALTH))
+ continue;
+ bool isCaster = itr->second->GetCasterGUID() == GetGUID();
+ if (!isCaster)
+ if (itr->second->IsSingleTarget()
+ || itr->second->IsAreaAura())
+ continue;
- if (lastEffectPair == itr->first)
- stackCounter++;
- else
+ int32 amounts[MAX_SPELL_EFFECTS];
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- lastEffectPair = itr->first;
- stackCounter = 1;
+ if (AuraEffect *partAura = itr->second->GetPartAura(i))
+ amounts[i] = partAura->GetAmount();
+ else
+ amounts[i] = 0;
}
+
+ CharacterDatabase.PExecute("INSERT INTO pet_aura (guid,caster_guid,spell,effect_mask,stackcount,amount0, amount1, amount2,maxduration,remaintime,remaincharges) "
+ "VALUES ('%u', '" I64FMTD "', '%u', '%u', '%d', '%d', '%d', '%d', '%d', '%d', '%u')",
+ m_charmInfo->GetPetNumber(), itr->second->GetCasterGUID(), itr->second->GetId(), (uint32)itr->second->GetEffectMask(),
+ (int32)itr->second->GetStackAmount(), amounts[0], amounts[1], amounts[2]
+ ,itr->second->GetAuraMaxDuration(), itr->second->GetAuraDuration(), (uint32)itr->second->GetAuraCharges());
}
}
-bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, uint16 slot_id, PetSpellType type)
+bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpellState state /*= PETSPELL_NEW*/, PetSpellType type /*= PETSPELL_NORMAL*/)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
if (!spellInfo)
@@ -1492,23 +1215,24 @@ bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, uint16 s
return false;
}
- // same spells don't have autocast option
- if (spellInfo->AttributesEx & SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET)
- active = ACT_CAST;
-
PetSpellMap::iterator itr = m_spells.find(spell_id);
if (itr != m_spells.end())
{
- if (itr->second->state == PETSPELL_REMOVED)
+ if (itr->second.state == PETSPELL_REMOVED)
{
- delete itr->second;
m_spells.erase(itr);
state = PETSPELL_CHANGED;
}
- else if (state == PETSPELL_UNCHANGED && itr->second->state != PETSPELL_UNCHANGED)
+ else if (state == PETSPELL_UNCHANGED && itr->second.state != PETSPELL_UNCHANGED)
{
// can be in case spell loading but learned at some previous spell loading
- itr->second->state = PETSPELL_UNCHANGED;
+ itr->second.state = PETSPELL_UNCHANGED;
+
+ if(active == ACT_ENABLED)
+ ToggleAutocast(spell_id, true);
+ else if(active == ACT_DISABLED)
+ ToggleAutocast(spell_id, false);
+
return false;
}
else
@@ -1517,184 +1241,326 @@ bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, uint16 s
uint32 oldspell_id = 0;
- PetSpell *newspell = new PetSpell;
- newspell->state = state;
- newspell->type = type;
+ PetSpell newspell;
+ newspell.state = state;
+ newspell.type = type;
if(active == ACT_DECIDE) //active was not used before, so we save it's autocast/passive state here
{
- if(IsPassiveSpell(spell_id))
- newspell->active = ACT_PASSIVE;
+ if(IsAutocastableSpell(spell_id))
+ newspell.active = ACT_DISABLED;
else
- newspell->active = ACT_DISABLED;
+ newspell.active = ACT_PASSIVE;
}
else
- newspell->active = active;
+ newspell.active = active;
- uint32 chainstart = spellmgr.GetFirstSpellInChain(spell_id);
-
- for (PetSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
+ // talent: unlearn all other talent ranks (high and low)
+ if(TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id))
{
- if(itr->second->state == PETSPELL_REMOVED) continue;
-
- if(spellmgr.GetFirstSpellInChain(itr->first) == chainstart)
+ if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id ))
{
- slot_id = itr->second->slotId;
- newspell->active = itr->second->active;
-
- if(newspell->active == ACT_ENABLED)
- ToggleAutocast(itr->first, false);
+ for(int i=0; i < MAX_TALENT_RANK; ++i)
+ {
+ // skip learning spell and no rank spell case
+ uint32 rankSpellId = talentInfo->RankID[i];
+ if(!rankSpellId || rankSpellId==spell_id)
+ continue;
- oldspell_id = itr->first;
- removeSpell(itr->first);
+ // skip unknown ranks
+ if(!HasSpell(rankSpellId))
+ continue;
+ removeSpell(rankSpellId,false);
+ }
}
}
-
- uint16 tmpslot=slot_id;
-
- if (tmpslot == 0xffff)
+ else if(spellmgr.GetSpellRank(spell_id)!=0)
{
- uint16 maxid = 0;
- PetSpellMap::iterator itr;
- for (itr = m_spells.begin(); itr != m_spells.end(); ++itr)
+ for (PetSpellMap::const_iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2)
{
- if(itr->second->state == PETSPELL_REMOVED) continue;
- if (itr->second->slotId > maxid) maxid = itr->second->slotId;
+ if(itr2->second.state == PETSPELL_REMOVED) continue;
+
+ if( spellmgr.IsRankSpellDueToSpell(spellInfo,itr2->first) )
+ {
+ // replace by new high rank
+ if(spellmgr.IsHighRankOfSpell(spell_id,itr2->first))
+ {
+ newspell.active = itr2->second.active;
+
+ if(newspell.active == ACT_ENABLED)
+ ToggleAutocast(itr2->first, false);
+
+ oldspell_id = itr2->first;
+ unlearnSpell(itr2->first,false);
+ break;
+ }
+ // ignore new lesser rank
+ else if(spellmgr.IsHighRankOfSpell(itr2->first,spell_id))
+ return false;
+ }
}
- tmpslot = maxid + 1;
}
- newspell->slotId = tmpslot;
m_spells[spell_id] = newspell;
if (IsPassiveSpell(spell_id))
CastSpell(this, spell_id, true);
- else if(state == PETSPELL_NEW)
- m_charmInfo->AddSpellToAB(oldspell_id, spell_id, (ActiveStates)active);
+ else
+ m_charmInfo->AddSpellToAB(oldspell_id, spell_id);
- if(newspell->active == ACT_ENABLED)
+ if(newspell.active == ACT_ENABLED)
ToggleAutocast(spell_id, true);
+ uint32 talentCost = GetTalentSpellCost(spell_id);
+ if (talentCost)
+ {
+ int32 free_points = GetMaxTalentPointsForLevel(getLevel());
+ m_usedTalentCount+=talentCost;
+ // update free talent points
+ free_points-=m_usedTalentCount;
+ SetFreeTalentPoints(free_points > 0 ? free_points : 0);
+ }
return true;
}
-bool Pet::learnSpell(uint16 spell_id)
+bool Pet::learnSpell(uint32 spell_id)
{
// prevent duplicated entires in spell book
if (!addSpell(spell_id))
return false;
- Unit* owner = GetOwner();
- if(owner->GetTypeId()==TYPEID_PLAYER)
- ((Player*)owner)->PetSpellInitialize();
+ if(!m_loading)
+ {
+ WorldPacket data(SMSG_PET_LEARNED_SPELL, 2);
+ data << uint16(spell_id);
+ m_owner->GetSession()->SendPacket(&data);
+ m_owner->PetSpellInitialize();
+ }
return true;
}
-void Pet::removeSpell(uint16 spell_id)
+void Pet::InitLevelupSpellsForLevel()
{
- PetSpellMap::iterator itr = m_spells.find(spell_id);
- if (itr == m_spells.end())
- return;
-
- if(itr->second->state == PETSPELL_REMOVED)
- return;
+ uint32 level = getLevel();
- if(itr->second->state == PETSPELL_NEW)
+ if(PetLevelupSpellSet const *levelupSpells = GetCreatureInfo()->family ? spellmgr.GetPetLevelupSpellList(GetCreatureInfo()->family) : NULL)
{
- delete itr->second;
- m_spells.erase(itr);
+ // PetLevelupSpellSet ordered by levels, process in reversed order
+ for(PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr)
+ {
+ // will called first if level down
+ if(itr->first > level)
+ unlearnSpell(itr->second,true); // will learn prev rank if any
+ // will called if level up
+ else
+ learnSpell(itr->second); // will unlearn prev rank if any
+ }
}
- else
- itr->second->state = PETSPELL_REMOVED;
- RemoveAurasDueToSpell(spell_id);
+ int32 petSpellsId = GetCreatureInfo()->PetSpellDataId ? -(int32)GetCreatureInfo()->PetSpellDataId : GetEntry();
+
+ // default spells (can be not learned if pet level (as owner level decrease result for example) less first possible in normal game)
+ if(PetDefaultSpellsEntry const *defSpells = spellmgr.GetPetDefaultSpellsEntry(petSpellsId))
+ {
+ for(int i = 0; i < MAX_CREATURE_SPELL_DATA_SLOT; ++i)
+ {
+ SpellEntry const* spellEntry = sSpellStore.LookupEntry(defSpells->spellid[i]);
+ if(!spellEntry)
+ continue;
+
+ // will called first if level down
+ if(spellEntry->spellLevel > level)
+ unlearnSpell(spellEntry->Id,false);
+ // will called if level up
+ else
+ learnSpell(spellEntry->Id);
+ }
+ }
}
-bool Pet::_removeSpell(uint16 spell_id)
+bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev)
{
- PetSpellMap::iterator itr = m_spells.find(spell_id);
- if (itr != m_spells.end())
+ if(removeSpell(spell_id,learn_prev))
{
- delete itr->second;
- m_spells.erase(itr);
+ if(!m_loading)
+ {
+ WorldPacket data(SMSG_PET_REMOVED_SPELL, 2);
+ data << uint16(spell_id);
+ m_owner->GetSession()->SendPacket(&data);
+ }
return true;
}
return false;
}
+bool Pet::removeSpell(uint32 spell_id, bool learn_prev)
+{
+ PetSpellMap::iterator itr = m_spells.find(spell_id);
+ if (itr == m_spells.end())
+ return false;
+
+ if(itr->second.state == PETSPELL_REMOVED)
+ return false;
+
+ if(itr->second.state == PETSPELL_NEW)
+ m_spells.erase(itr);
+ else
+ itr->second.state = PETSPELL_REMOVED;
+
+ RemoveAurasDueToSpell(spell_id);
+
+ uint32 talentCost = GetTalentSpellCost(spell_id);
+ if (talentCost > 0)
+ {
+ if (m_usedTalentCount > talentCost)
+ m_usedTalentCount-=talentCost;
+ else
+ m_usedTalentCount = 0;
+ // update free talent points
+ int32 free_points = GetMaxTalentPointsForLevel(getLevel()) - m_usedTalentCount;
+ SetFreeTalentPoints(free_points > 0 ? free_points : 0);
+ }
+
+ if (learn_prev)
+ {
+ if (uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id))
+ {
+ // replace to next spell
+ if(!talentCost && !IsPassiveSpell(prev_id))
+ m_charmInfo->AddSpellToAB(spell_id, prev_id);
+
+ learnSpell(prev_id);
+ }
+ else
+ learn_prev = false;
+ }
+
+ // if remove last rank or non-ranked then update action bar at server and client if need
+ if(!learn_prev && m_charmInfo->AddSpellToAB(spell_id, 0))
+ {
+ // need update action bar for last removed rank
+ if (Unit* owner = GetOwner())
+ if (owner->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)owner)->PetSpellInitialize();
+ }
+
+ return true;
+}
+
void Pet::InitPetCreateSpells()
{
m_charmInfo->InitPetActionBar();
-
m_spells.clear();
- int32 usedtrainpoints = 0, petspellid;
- PetCreateSpellEntry const* CreateSpells = objmgr.GetPetCreateSpellEntry(GetEntry());
- if(CreateSpells)
+
+ LearnPetPassives();
+ InitLevelupSpellsForLevel();
+
+ CastPetAuras(false);
+}
+
+bool Pet::resetTalents(bool no_cost)
+{
+ Unit *owner = GetOwner();
+ if (!owner || owner->GetTypeId()!=TYPEID_PLAYER)
+ return false;
+
+ CreatureInfo const * ci = GetCreatureInfo();
+ if(!ci)
+ return false;
+ // Check pet talent type
+ CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
+ if(!pet_family || pet_family->petTalentType < 0)
+ return false;
+
+ Player *player = (Player *)owner;
+
+ uint32 level = getLevel();
+ uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level);
+
+ if (m_usedTalentCount == 0)
{
- for(uint8 i = 0; i < 4; i++)
+ SetFreeTalentPoints(talentPointsForLevel);
+ return false;
+ }
+
+ uint32 cost = 0;
+
+ if(!no_cost)
+ {
+ cost = resetTalentsCost();
+
+ if (player->GetMoney() < cost)
{
- if(!CreateSpells->spellid[i])
- break;
+ player->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
+ return false;
+ }
+ }
- SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(CreateSpells->spellid[i]);
- if(!learn_spellproto)
- continue;
+ for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
+ {
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
- if(learn_spellproto->Effect[0] == SPELL_EFFECT_LEARN_SPELL || learn_spellproto->Effect[0] == SPELL_EFFECT_LEARN_PET_SPELL)
- {
- petspellid = learn_spellproto->EffectTriggerSpell[0];
- Unit* owner = GetOwner();
- if(owner->GetTypeId() == TYPEID_PLAYER && !((Player*)owner)->HasSpell(learn_spellproto->Id))
- {
- if(IsPassiveSpell(petspellid)) //learn passive skills when tamed, not sure if thats right
- ((Player*)owner)->learnSpell(learn_spellproto->Id);
- else
- AddTeachSpell(learn_spellproto->EffectTriggerSpell[0], learn_spellproto->Id);
- }
- }
- else
- petspellid = learn_spellproto->Id;
+ if (!talentInfo) continue;
- addSpell(petspellid);
+ TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
- SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(learn_spellproto->EffectTriggerSpell[0]);
- SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(learn_spellproto->EffectTriggerSpell[0]);
+ if(!talentTabInfo)
+ continue;
+
+ // unlearn only talents for pets family talent type
+ if(!((1 << pet_family->petTalentType) & talentTabInfo->petTalentMask))
+ continue;
- for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
+ for (int j = 0; j < MAX_TALENT_RANK; j++)
+ {
+ for(PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end();)
{
- usedtrainpoints += _spell_idx->second->reqtrainpoints;
- break;
+ if(itr->second.state == PETSPELL_REMOVED)
+ {
+ ++itr;
+ continue;
+ }
+ // remove learned spells (all ranks)
+ uint32 itrFirstId = spellmgr.GetFirstSpellInChain(itr->first);
+
+ // unlearn if first rank is talent or learned by talent
+ if (itrFirstId == talentInfo->RankID[j] || spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId))
+ {
+ removeSpell(itr->first,false);
+ itr = m_spells.begin();
+ continue;
+ }
+ else
+ ++itr;
}
}
}
- LearnPetPassives();
+ SetFreeTalentPoints(talentPointsForLevel);
- CastPetAuras(false);
+ if(!no_cost)
+ {
+ player->ModifyMoney(-(int32)cost);
- SetTP(-usedtrainpoints);
+ m_resetTalentsCost = cost;
+ m_resetTalentsTime = time(NULL);
+ }
+ if(!m_loading)
+ player->PetSpellInitialize();
+ return true;
}
-void Pet::CheckLearning(uint32 spellid)
+void Pet::InitTalentForLevel()
{
- //charmed case -> prevent crash
- if(GetTypeId() == TYPEID_PLAYER || getPetType() != HUNTER_PET)
- return;
-
- Unit* owner = GetOwner();
-
- if(m_teachspells.empty() || !owner || owner->GetTypeId() != TYPEID_PLAYER)
- return;
-
- TeachSpellMap::iterator itr = m_teachspells.find(spellid);
- if(itr == m_teachspells.end())
- return;
-
- if(urand(0, 100) < 10)
+ uint32 level = getLevel();
+ uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level);
+ // Reset talents in case low level (on level down) or wrong points for level (hunter can unlearn TP increase talent)
+ if(talentPointsForLevel == 0 || m_usedTalentCount > talentPointsForLevel)
{
- ((Player*)owner)->learnSpell(itr->second);
- m_teachspells.erase(itr);
+ // Remove all talent points
+ resetTalents(true);
}
+ SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount);
}
uint32 Pet::resetTalentsCost() const
@@ -1715,47 +1581,88 @@ uint32 Pet::resetTalentsCost() const
return (m_resetTalentsCost + 1*GOLD > 10*GOLD ? 10*GOLD : m_resetTalentsCost + 1*GOLD);
}
+uint8 Pet::GetMaxTalentPointsForLevel(uint32 level)
+{
+ uint8 points = (level >= 20) ? ((level - 16) / 4) : 0;
+ // Mod points from owner SPELL_AURA_MOD_PET_TALENT_POINTS
+ if (Unit *owner = GetOwner())
+ points+=owner->GetTotalAuraModifier(SPELL_AURA_MOD_PET_TALENT_POINTS);
+ return points;
+}
+
void Pet::ToggleAutocast(uint32 spellid, bool apply)
{
- if(IsPassiveSpell(spellid))
+ if(!IsAutocastableSpell(spellid))
return;
- //if(const SpellEntry *tempSpell = GetSpellStore()->LookupEntry(spellid))
- // if(tempSpell->EffectImplicitTargetA[0] != TARGET_SRC_CASTER
- // && tempSpell->EffectImplicitTargetA[0] != TARGET_UNIT_TARGET_ENEMY)
- // return;
-
- PetSpellMap::const_iterator itr = m_spells.find((uint16)spellid);
+ PetSpellMap::iterator itr = m_spells.find(spellid);
+ if(itr == m_spells.end())
+ return;
int i;
if(apply)
{
- for (i = 0; i < m_autospells.size() && m_autospells[i] != spellid; i++);
+ for (i = 0; i < m_autospells.size() && m_autospells[i] != spellid; ++i)
+ ; // just search
+
if (i == m_autospells.size())
{
m_autospells.push_back(spellid);
- itr->second->active = ACT_ENABLED;
- itr->second->state = PETSPELL_CHANGED;
+
+ if(itr->second.active != ACT_ENABLED)
+ {
+ itr->second.active = ACT_ENABLED;
+ if(itr->second.state != PETSPELL_NEW)
+ itr->second.state = PETSPELL_CHANGED;
+ }
}
}
else
{
AutoSpellList::iterator itr2 = m_autospells.begin();
- for (i = 0; i < m_autospells.size() && m_autospells[i] != spellid; i++, itr2++);
+ for (i = 0; i < m_autospells.size() && m_autospells[i] != spellid; ++i, itr2++)
+ ; // just search
+
if (i < m_autospells.size())
{
m_autospells.erase(itr2);
- itr->second->active = ACT_DISABLED;
- itr->second->state = PETSPELL_CHANGED;
+ if(itr->second.active != ACT_DISABLED)
+ {
+ itr->second.active = ACT_DISABLED;
+ if(itr->second.state != PETSPELL_NEW)
+ itr->second.state = PETSPELL_CHANGED;
+ }
}
}
}
-bool Pet::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 pet_number)
+bool Pet::IsPermanentPetFor(Player* owner)
+{
+ switch(getPetType())
+ {
+ case SUMMON_PET:
+ switch(owner->getClass())
+ {
+ case CLASS_WARLOCK:
+ return GetCreatureInfo()->type == CREATURE_TYPE_DEMON;
+ case CLASS_DEATH_KNIGHT:
+ return GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD;
+ default:
+ return false;
+ }
+ case HUNTER_PET:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Pet::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number)
{
SetMapId(map->GetId());
SetInstanceId(map->GetInstanceId());
+ SetPhaseMask(phaseMask,false);
Object::_Create(guidlow, pet_number, HIGHGUID_PET);
@@ -1765,18 +1672,15 @@ bool Pet::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 pet_number)
if(!InitEntry(Entry))
return false;
- SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE );
- SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY | UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5 );
-
- if(getPetType() == MINI_PET) // always non-attackable
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE);
return true;
}
bool Pet::HasSpell(uint32 spell) const
{
- return (m_spells.find(spell) != m_spells.end());
+ PetSpellMap::const_iterator itr = m_spells.find(spell);
+ return (itr != m_spells.end() && itr->second.state != PETSPELL_REMOVED );
}
// Get all passive spells in our skill line
@@ -1797,20 +1701,20 @@ void Pet::LearnPetPassives()
// Passive 01~10, Passive 00 (20782, not used), Ferocious Inspiration (34457)
// Scale 01~03 (34902~34904, bonus from owner, not used)
for(PetFamilySpellsSet::const_iterator petSet = petStore->second.begin(); petSet != petStore->second.end(); ++petSet)
- addSpell(*petSet, ACT_DECIDE, PETSPELL_NEW, 0xffff, PETSPELL_FAMILY);
+ addSpell(*petSet, ACT_DECIDE, PETSPELL_NEW, PETSPELL_FAMILY);
}
}
void Pet::CastPetAuras(bool current)
{
Unit* owner = GetOwner();
- if(!owner)
+ if(!owner || owner->GetTypeId()!=TYPEID_PLAYER)
return;
- if(getPetType() != HUNTER_PET && (getPetType() != SUMMON_PET || owner->getClass() != CLASS_WARLOCK))
+ if(!IsPermanentPetFor((Player*)owner))
return;
- for(PetAuraSet::iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
+ for(PetAuraSet::const_iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
{
PetAura const* pa = *itr;
++itr;
@@ -1837,3 +1741,36 @@ void Pet::CastPetAura(PetAura const* aura)
CastSpell(this, auraId, true);
}
+void Pet::learnSpellHighRank(uint32 spellid)
+{
+ learnSpell(spellid);
+
+ if(uint32 next = spellmgr.GetNextSpellInChain(spellid))
+ learnSpellHighRank(next);
+}
+
+void Pet::SynchronizeLevelWithOwner()
+{
+ Unit* owner = GetOwner();
+ if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ switch(getPetType())
+ {
+ // always same level
+ case SUMMON_PET:
+ GivePetLevel(owner->getLevel());
+ break;
+ // can't be greater owner level
+ case HUNTER_PET:
+ if(getLevel() > owner->getLevel())
+ {
+ GivePetLevel(owner->getLevel());
+ SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(owner->getLevel())/4);
+ SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, GetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP)-1);
+ }
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/game/Pet.h b/src/game/Pet.h
index d55c467826a..d66e13edf0c 100644
--- a/src/game/Pet.h
+++ b/src/game/Pet.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,28 +22,29 @@
#define TRINITYCORE_PET_H
#include "ObjectDefines.h"
-#include "Creature.h"
#include "Unit.h"
+#include "TemporarySummon.h"
enum PetType
{
SUMMON_PET = 0,
HUNTER_PET = 1,
- GUARDIAN_PET = 2,
- MINI_PET = 3,
- POSSESSED_PET = 4,
- MAX_PET_TYPE = 5
+ POSSESSED_PET = 2,
+ MAX_PET_TYPE = 4,
};
extern char const* petTypeSuffix[MAX_PET_TYPE];
+#define MAX_PET_STABLES 4
+
+// stored in character_pet.slot
enum PetSaveMode
{
- PET_SAVE_AS_DELETED =-1,
- PET_SAVE_AS_CURRENT = 0,
- PET_SAVE_IN_STABLE_SLOT_1 = 1,
- PET_SAVE_IN_STABLE_SLOT_2 = 2,
- PET_SAVE_NOT_IN_SLOT = 3
+ PET_SAVE_AS_DELETED = -1, // not saved in fact
+ PET_SAVE_AS_CURRENT = 0, // in current slot (with player)
+ PET_SAVE_FIRST_STABLE_SLOT = 1,
+ PET_SAVE_LAST_STABLE_SLOT = MAX_PET_STABLES, // last in DB stable slot index (including), all higher have same meaning as PET_SAVE_NOT_IN_SLOT
+ PET_SAVE_NOT_IN_SLOT = 100 // for avoid conflict with stable size grow will use 100
};
enum HappinessState
@@ -53,16 +54,6 @@ enum HappinessState
HAPPY = 3
};
-enum LoyaltyLevel
-{
- REBELLIOUS = 1,
- UNRULY = 2,
- SUBMISSIVE = 3,
- DEPENDABLE = 4,
- FAITHFUL = 5,
- BEST_FRIEND = 6
-};
-
enum PetSpellState
{
PETSPELL_UNCHANGED = 0,
@@ -79,11 +70,9 @@ enum PetSpellType
struct PetSpell
{
- uint16 slotId;
- uint16 active;
-
- PetSpellState state : 16;
- PetSpellType type : 16;
+ ActiveStates active;
+ PetSpellState state;
+ PetSpellType type;
};
enum ActionFeedback
@@ -100,6 +89,12 @@ enum PetTalk
PET_TALK_ATTACK = 1
};
+enum AtLoadFlags
+{
+ AT_LOAD_NONE = 0,
+ AT_LOAD_RESET_SPELLS = 1,
+};
+
enum PetNameInvalidReason
{
PET_NAME_INVALID = 1,
@@ -117,26 +112,24 @@ enum PetNameInvalidReason
PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 16
};
-typedef UNORDERED_MAP<uint16, PetSpell*> PetSpellMap;
-typedef std::map<uint32,uint32> TeachSpellMap;
+typedef UNORDERED_MAP<uint32, PetSpell> PetSpellMap;
typedef std::vector<uint32> AutoSpellList;
#define HAPPINESS_LEVEL_SIZE 333000
-extern const uint32 LevelUpLoyalty[6];
-extern const uint32 LevelStartLoyalty[6];
-
#define ACTIVE_SPELLS_MAX 4
-#define OWNER_MAX_DISTANCE 100
+#define OWNER_MAX_DISTANCE 100.0f
#define PET_FOLLOW_DIST 1
#define PET_FOLLOW_ANGLE (M_PI/2)
-class Pet : public Creature
+class Player;
+
+class Pet : public Guardian
{
public:
- explicit Pet(PetType type = MAX_PET_TYPE);
+ explicit Pet(Player *owner, PetType type = MAX_PET_TYPE);
virtual ~Pet();
void AddToWorld();
@@ -147,9 +140,11 @@ class Pet : public Creature
bool isControlled() const { return getPetType()==SUMMON_PET || getPetType()==HUNTER_PET; }
bool isTemporarySummoned() const { return m_duration > 0; }
- bool Create (uint32 guidlow, Map *map, uint32 Entry, uint32 pet_number);
+ bool IsPermanentPetFor(Player* owner); // pet have tab in character windows and set UNIT_FIELD_PETNUMBER
+
+ bool Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number);
bool CreateBaseAtCreature(Creature* creature);
- bool LoadPetFromDB( Unit* owner,uint32 petentry = 0,uint32 petnumber = 0, bool current = false );
+ bool LoadPetFromDB( Player* owner,uint32 petentry = 0,uint32 petnumber = 0, bool current = false );
void SavePetToDB(PetSaveMode mode);
void Remove(PetSaveMode mode, bool returnreagent = false);
static void DeleteFromDB(uint32 guidlow);
@@ -166,26 +161,16 @@ class Pet : public Creature
return m_autospells[pos];
}
- void RegenerateFocus();
+ void Regenerate(Powers power);
void LooseHappiness();
- void TickLoyaltyChange();
- void ModifyLoyalty(int32 addvalue);
HappinessState GetHappinessState();
- uint32 GetMaxLoyaltyPoints(uint32 level);
- uint32 GetStartLoyaltyPoints(uint32 level);
- void KillLoyaltyBonus(uint32 level);
- uint32 GetLoyaltyLevel() { return GetByteValue(UNIT_FIELD_BYTES_1, 1); }
- void SetLoyaltyLevel(LoyaltyLevel level);
void GivePetXP(uint32 xp);
void GivePetLevel(uint32 level);
- bool InitStatsForLevel(uint32 level);
+ void SynchronizeLevelWithOwner();
bool HaveInDiet(ItemPrototype const* item) const;
uint32 GetCurrentFoodBenefitLevel(uint32 itemlevel);
void SetDuration(int32 dur) { m_duration = dur; }
- int32 GetBonusDamage() { return m_bonusdamage; }
- void SetBonusDamage(int32 damage) { m_bonusdamage = damage; }
-
bool UpdateStats(Stats stat);
bool UpdateAllStats();
void UpdateResistances(uint32 school);
@@ -195,13 +180,10 @@ class Pet : public Creature
void UpdateAttackPowerAndDamage(bool ranged = false);
void UpdateDamagePhysical(WeaponAttackType attType);
- bool CanTakeMoreActiveSpells(uint32 SpellIconID);
- void ToggleAutocast(uint32 spellid, bool apply);
- bool HasTPForSpell(uint32 spellid);
- int32 GetTPForSpell(uint32 spellid);
+ bool CanTakeMoreActiveSpells(uint32 SpellIconID);
+ void ToggleAutocast(uint32 spellid, bool apply);
bool HasSpell(uint32 spell) const;
- void AddTeachSpell(uint32 learned_id, uint32 source_id) { m_teachspells[learned_id] = source_id; }
void LearnPetPassives();
void CastPetAuras(bool current);
@@ -214,43 +196,47 @@ class Pet : public Creature
void _LoadSpells();
void _SaveSpells();
- bool addSpell(uint16 spell_id,uint16 active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, uint16 slot_id=0xffff, PetSpellType type = PETSPELL_NORMAL);
- bool learnSpell(uint16 spell_id);
- void removeSpell(uint16 spell_id);
- bool _removeSpell(uint16 spell_id);
+ bool addSpell(uint32 spell_id,ActiveStates active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL);
+ bool learnSpell(uint32 spell_id);
+ void learnSpellHighRank(uint32 spellid);
+ void InitLevelupSpellsForLevel();
+ bool unlearnSpell(uint32 spell_id, bool learn_prev);
+ bool removeSpell(uint32 spell_id, bool learn_prev);
PetSpellMap m_spells;
- TeachSpellMap m_teachspells;
AutoSpellList m_autospells;
void InitPetCreateSpells();
- void CheckLearning(uint32 spellid);
+
+ bool resetTalents(bool no_cost = false);
uint32 resetTalentsCost() const;
+ void InitTalentForLevel();
- void SetTP(int32 TP);
- int32 GetDispTP();
+ uint8 GetMaxTalentPointsForLevel(uint32 level);
+ uint8 GetFreeTalentPoints() { return GetByteValue(UNIT_FIELD_BYTES_1, 1); }
+ void SetFreeTalentPoints(uint8 points) { SetByteValue(UNIT_FIELD_BYTES_1, 1, points); }
- int32 m_TrainingPoints;
uint32 m_resetTalentsCost;
time_t m_resetTalentsTime;
+ uint32 m_usedTalentCount;
- uint64 GetAuraUpdateMask() { return m_auraUpdateMask; }
- void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); }
- void UnsetAuraUpdateMask(uint8 slot) { m_auraUpdateMask &= ~(uint64(1) << slot); }
- void ResetAuraUpdateMask() { m_auraUpdateMask = 0; }
+ const uint64& GetAuraUpdateMaskForRaid() const { return m_auraRaidUpdateMask; }
+ void SetAuraUpdateMaskForRaid(uint8 slot) { m_auraRaidUpdateMask |= (uint64(1) << slot); }
+ void ResetAuraUpdateMaskForRaid() { m_auraRaidUpdateMask = 0; }
DeclinedName const* GetDeclinedNames() const { return m_declinedname; }
bool m_removed; // prevent overwrite pet state in DB at next Pet::Update if pet already removed(saved)
+
+ Player *GetOwner() { return m_owner; }
protected:
- uint32 m_regenTimer;
+ Player *m_owner;
uint32 m_happinessTimer;
- uint32 m_loyaltyTimer;
PetType m_petType;
int32 m_duration; // time until unsummon (used mostly for summoned guardians and not used for controlled pets)
- int32 m_loyaltyPoints;
- int32 m_bonusdamage;
- uint64 m_auraUpdateMask;
+ uint64 m_auraRaidUpdateMask;
+ bool m_loading;
+ uint32 m_regenTimer;
DeclinedName *m_declinedname;
@@ -265,4 +251,3 @@ class Pet : public Creature
}
};
#endif
-
diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp
index 75c1aa06c20..7851ee6773f 100644
--- a/src/game/PetAI.cpp
+++ b/src/game/PetAI.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
#include "Errors.h"
#include "Pet.h"
#include "Player.h"
-#include "Database/DBCStores.h"
+#include "DBCStores.h"
#include "Spell.h"
#include "ObjectAccessor.h"
#include "SpellMgr.h"
@@ -38,7 +38,7 @@ int PetAI::Permissible(const Creature *creature)
return PERMIT_BASE_NO;
}
-PetAI::PetAI(Creature *c) : CreatureAI(c), i_pet(*c), i_tracker(TIME_INTERVAL_LOOK)
+PetAI::PetAI(Creature *c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK)
{
m_AllySet.clear();
UpdateAllies();
@@ -51,46 +51,43 @@ void PetAI::EnterEvadeMode()
bool PetAI::_needToStop() const
{
// This is needed for charmed creatures, as once their target was reset other effects can trigger threat
- if(i_pet.isCharmed() && i_pet.getVictim() == i_pet.GetCharmer())
+ if(m_creature->isCharmed() && m_creature->getVictim() == m_creature->GetCharmer())
return true;
- return !i_pet.canAttack(i_pet.getVictim());
+ return !m_creature->canAttack(m_creature->getVictim());
}
void PetAI::_stopAttack()
{
- if( !i_pet.isAlive() )
+ if( !m_creature->isAlive() )
{
- DEBUG_LOG("Creature stoped attacking cuz his dead [guid=%u]", i_pet.GetGUIDLow());
- i_pet.GetMotionMaster()->Clear();
- i_pet.GetMotionMaster()->MoveIdle();
- i_pet.CombatStop();
- i_pet.getHostilRefManager().deleteReferences();
+ DEBUG_LOG("Creature stoped attacking cuz his dead [guid=%u]", m_creature->GetGUIDLow());
+ m_creature->GetMotionMaster()->Clear();
+ m_creature->GetMotionMaster()->MoveIdle();
+ m_creature->CombatStop();
+ m_creature->getHostilRefManager().deleteReferences();
return;
}
- Unit* owner = i_pet.GetCharmerOrOwner();
+ Unit* owner = m_creature->GetCharmerOrOwner();
- if(owner && i_pet.GetCharmInfo() && i_pet.GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
+ if(owner && m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
{
- i_pet.GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
+ m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
}
else
{
- i_pet.clearUnitState(UNIT_STAT_FOLLOW);
- i_pet.GetMotionMaster()->Clear();
- i_pet.GetMotionMaster()->MoveIdle();
+ m_creature->clearUnitState(UNIT_STAT_FOLLOW);
+ m_creature->GetMotionMaster()->Clear();
+ m_creature->GetMotionMaster()->MoveIdle();
}
- i_pet.AttackStop();
+ m_creature->AttackStop();
}
void PetAI::UpdateAI(const uint32 diff)
{
- if (!i_pet.isAlive())
- return;
-
- Unit* owner = i_pet.GetCharmerOrOwner();
+ Unit* owner = m_creature->GetCharmerOrOwner();
if(m_updateAlliesTimer <= diff)
// UpdateAllies self set update timer
@@ -98,42 +95,37 @@ void PetAI::UpdateAI(const uint32 diff)
else
m_updateAlliesTimer -= diff;
- // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.
- if( i_pet.getVictim() )
+ // m_creature->getVictim() can't be used for check in case stop fighting, m_creature->getVictim() clear at Unit death etc.
+ if( m_creature->getVictim() )
{
if( _needToStop() )
{
- DEBUG_LOG("Pet AI stoped attacking [guid=%u]", i_pet.GetGUIDLow());
+ DEBUG_LOG("Pet AI stoped attacking [guid=%u]", m_creature->GetGUIDLow());
_stopAttack();
return;
}
DoMeleeAttackIfReady();
}
- else
+ else if(owner && m_creature->GetCharmInfo()) //no victim
{
- if(me->isInCombat())
- _stopAttack();
- else if(owner && i_pet.GetCharmInfo()) //no victim
- {
- if(owner->isInCombat() && !(i_pet.HasReactState(REACT_PASSIVE) || i_pet.GetCharmInfo()->HasCommandState(COMMAND_STAY)))
- AttackStart(owner->getAttackerForHelper());
- else if(i_pet.GetCharmInfo()->HasCommandState(COMMAND_FOLLOW) && !i_pet.hasUnitState(UNIT_STAT_FOLLOW))
- i_pet.GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
- }
+ if(owner->isInCombat() && !(m_creature->HasReactState(REACT_PASSIVE) || m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY)))
+ AttackStart(owner->getAttackerForHelper());
+ else if(m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW) && !m_creature->hasUnitState(UNIT_STAT_FOLLOW))
+ m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
}
if(!me->GetCharmInfo())
return;
- if (i_pet.GetGlobalCooldown() == 0 && !i_pet.hasUnitState(UNIT_STAT_CASTING))
+ if (m_creature->GetGlobalCooldown() == 0 && !m_creature->hasUnitState(UNIT_STAT_CASTING))
{
bool inCombat = me->getVictim();
//Autocast
- for (uint8 i = 0; i < i_pet.GetPetAutoSpellSize(); i++)
+ for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i)
{
- uint32 spellID = i_pet.GetPetAutoSpellOnPos(i);
+ uint32 spellID = m_creature->GetPetAutoSpellOnPos(i);
if (!spellID)
continue;
@@ -153,19 +145,19 @@ void PetAI::UpdateAI(const uint32 diff)
continue;
}
- Spell *spell = new Spell(&i_pet, spellInfo, false, 0);
+ Spell *spell = new Spell(m_creature, spellInfo, false, 0);
- if(inCombat && !i_pet.hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(i_pet.getVictim()))
+ if(inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim()))
{
- m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(i_pet.getVictim(), spell));
+ m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(m_creature->getVictim(), spell));
continue;
}
else
{
bool spellUsed = false;
- for(std::set<uint64>::iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar)
+ for(std::set<uint64>::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar)
{
- Unit* Target = ObjectAccessor::GetUnit(i_pet,*tar);
+ Unit* Target = ObjectAccessor::GetUnit(*m_creature,*tar);
//only buff targets that are in combat, unless the spell can only be cast while out of combat
if(!Target)
@@ -196,19 +188,17 @@ void PetAI::UpdateAI(const uint32 diff)
SpellCastTargets targets;
targets.setUnitTarget( target );
- if( !i_pet.HasInArc(M_PI, target) )
+ if( !m_creature->HasInArc(M_PI, target) )
{
- i_pet.SetInFront(target);
+ m_creature->SetInFront(target);
if( target->GetTypeId() == TYPEID_PLAYER )
- i_pet.SendUpdateToPlayer( (Player*)target );
+ m_creature->SendUpdateToPlayer( (Player*)target );
if(owner && owner->GetTypeId() == TYPEID_PLAYER)
- i_pet.SendUpdateToPlayer( (Player*)owner );
+ m_creature->SendUpdateToPlayer( (Player*)owner );
}
- i_pet.AddCreatureSpellCooldown(spell->m_spellInfo->Id);
- if(i_pet.isPet())
- ((Pet*)&i_pet)->CheckLearning(spell->m_spellInfo->Id);
+ m_creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id);
spell->prepare(&targets);
}
@@ -222,10 +212,10 @@ void PetAI::UpdateAI(const uint32 diff)
void PetAI::UpdateAllies()
{
- Unit* owner = i_pet.GetCharmerOrOwner();
+ Unit* owner = m_creature->GetCharmerOrOwner();
Group *pGroup = NULL;
- m_updateAlliesTimer = 10000; //update friendly targets every 10 seconds, lesser checks increase performance
+ m_updateAlliesTimer = 10*IN_MILISECONDS; //update friendly targets every 10 seconds, lesser checks increase performance
if(!owner)
return;
@@ -240,7 +230,7 @@ void PetAI::UpdateAllies()
return;
m_AllySet.clear();
- m_AllySet.insert(i_pet.GetGUID());
+ m_AllySet.insert(m_creature->GetGUID());
if(pGroup) //add group
{
for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
diff --git a/src/game/PetAI.h b/src/game/PetAI.h
index 864195701c2..67ce6edefe3 100644
--- a/src/game/PetAI.h
+++ b/src/game/PetAI.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ class TRINITY_DLL_DECL PetAI : public CreatureAI
{
public:
- PetAI(Creature *c);
+ explicit PetAI(Creature *c);
void EnterEvadeMode();
void JustDied(Unit* who) { _stopAttack(); }
@@ -46,8 +46,8 @@ class TRINITY_DLL_DECL PetAI : public CreatureAI
void UpdateAllies();
- Creature &i_pet;
TimeTracker i_tracker;
+ bool inCombat;
std::set<uint64> m_AllySet;
uint32 m_updateAlliesTimer;
diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp
index a3644371f47..459055383cf 100644
--- a/src/game/PetHandler.cpp
+++ b/src/game/PetHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,18 +21,15 @@
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Log.h"
#include "Opcodes.h"
#include "Spell.h"
#include "ObjectAccessor.h"
-#include "MapManager.h"
#include "CreatureAI.h"
#include "Util.h"
#include "Pet.h"
-#include "Language.h"
void WorldSession::HandlePetAction( WorldPacket & recv_data )
{
@@ -49,25 +46,39 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
// used also for charmed creature
Unit* pet= ObjectAccessor::GetUnit(*_player, guid1);
- sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.\n", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) );
+ sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) );
if(!pet)
{
- sLog.outError( "Pet %u not exist.\n", uint32(GUID_LOPART(guid1)) );
+ sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid1)) );
return;
}
- if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
+ if(pet != GetPlayer()->GetFirstControlled())
{
- sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.\n", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName() );
+ sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName() );
return;
}
- if(!pet->isAlive())
- return;
-
+ //TODO: allow control charmed player?
if(pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
return;
+ if(GetPlayer()->m_Controlled.size() == 1)
+ HandlePetActionHelper(pet, guid1, spellid, flag, guid2);
+ else
+ {
+ //If a pet is dismissed, m_Controlled will change
+ std::vector<Unit*> controlled;
+ for(Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr)
+ if((*itr)->GetEntry() == pet->GetEntry() && (*itr)->isAlive())
+ controlled.push_back(*itr);
+ for(std::vector<Unit*>::iterator itr = controlled.begin(); itr != controlled.end(); ++itr)
+ HandlePetActionHelper(*itr, guid1, spellid, flag, guid2);
+ }
+}
+
+void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2)
+{
CharmInfo *charmInfo = pet->GetCharmInfo();
if(!charmInfo)
{
@@ -78,10 +89,6 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
switch(flag)
{
case ACT_COMMAND: //0x0700
- // Possessed or shared vision pets are only able to attack
- if ((pet->isPossessed() || pet->HasAuraType(SPELL_AURA_BIND_SIGHT)) && spellid != COMMAND_ATTACK)
- return;
-
switch(spellid)
{
case COMMAND_STAY: //flat=1792 //STAY
@@ -119,45 +126,58 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
// return;
pet->clearUnitState(UNIT_STAT_FOLLOW);
-
- if(pet->GetTypeId() != TYPEID_PLAYER && ((Creature*)pet)->IsAIEnabled)
+ // This is true if pet has no target or has target but targets differs.
+ if(pet->getVictim() != TargetUnit)
{
- ((Creature*)pet)->AI()->AttackStart(TargetUnit);
+ if (pet->getVictim())
+ pet->AttackStop();
- //10% chance to play special pet attack talk, else growl
- if(((Creature*)pet)->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
- pet->SendPetTalk((uint32)PET_TALK_ATTACK);
- else
+ if(pet->GetTypeId() != TYPEID_PLAYER && ((Creature*)pet)->IsAIEnabled)
{
- // 90% chance for pet and 100% chance for charmed creature
- pet->SendPetAIReaction(guid1);
+ ((Creature*)pet)->AI()->AttackStart(TargetUnit);
+
+ //10% chance to play special pet attack talk, else growl
+ if(((Creature*)pet)->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
+ pet->SendPetTalk((uint32)PET_TALK_ATTACK);
+ else
+ {
+ // 90% chance for pet and 100% chance for charmed creature
+ pet->SendPetAIReaction(guid1);
+ }
}
- }
- else // charmed player
- {
- if(pet->getVictim() && pet->getVictim() != TargetUnit)
- pet->AttackStop();
+ else // charmed player
+ {
+ if(pet->getVictim() && pet->getVictim() != TargetUnit)
+ pet->AttackStop();
- pet->Attack(TargetUnit,true);
- pet->SendPetAIReaction(guid1);
+ pet->Attack(TargetUnit,true);
+ pet->SendPetAIReaction(guid1);
+ }
}
break;
}
case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
- if(((Creature*)pet)->isPet())
+ if(pet->GetCharmerGUID() == GetPlayer()->GetGUID())
+ _player->StopCastingCharm();
+ else if(pet->GetOwnerGUID() == GetPlayer()->GetGUID())
{
- Pet* p = (Pet*)pet;
- if(p->getPetType() == HUNTER_PET)
- _player->RemovePet(p,PET_SAVE_AS_DELETED);
- else
- //dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
- p->setDeathState(CORPSE);
+ assert(pet->GetTypeId() == TYPEID_UNIT);
+ if(((Creature*)pet)->isPet())
+ {
+ if(((Pet*)pet)->getPetType() == HUNTER_PET)
+ GetPlayer()->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED);
+ else
+ //dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
+ pet->setDeathState(CORPSE);
+ }
+ else if(((Creature*)pet)->HasSummonMask(SUMMON_MASK_MINION))
+ {
+ ((Minion*)pet)->UnSummon();
+ }
}
- else // charmed or possessed
- _player->Uncharm();
break;
default:
- sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid);
+ sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid);
}
break;
case ACT_REACTION: // 0x600
@@ -171,28 +191,26 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
break;
}
break;
- case ACT_DISABLED: //0x8100 spell (disabled), ignore
- case ACT_CAST: //0x0100
- case ACT_ENABLED: //0xc100 spell
+ case ACT_DISABLED: // 0x8100 spell (disabled), ignore
+ case ACT_PASSIVE: // 0x0100
+ case ACT_ENABLED: // 0xC100 spell
{
- Unit* unit_target;
- if(guid2)
- unit_target = ObjectAccessor::GetUnit(*_player,guid2);
- else
- unit_target = NULL;
-
+ Unit* unit_target = NULL;
if (((Creature*)pet)->GetGlobalCooldown() > 0)
return;
+ if(guid2)
+ unit_target = ObjectAccessor::GetUnit(*_player,guid2);
+
// do not cast unknown spells
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid );
if(!spellInfo)
{
- sLog.outError("WORLD: unknown PET spell id %i\n", spellid);
+ sLog.outError("WORLD: unknown PET spell id %i", spellid);
return;
}
- for(uint32 i = 0; i < 3;i++)
+ for(uint32 i = 0; i < 3;++i)
{
if(spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_SRC || spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_DST || spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_DYNOBJ_ENEMY)
return;
@@ -206,25 +224,32 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
Spell *spell = new Spell(pet, spellInfo, false);
- int16 result = spell->PetCanCast(unit_target);
+ SpellCastResult result = spell->CheckPetCast(unit_target);
- //auto turn to target unless possessed
+ //auto turn to target unless possessed
if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed())
{
- pet->SetInFront(unit_target);
- if( unit_target->GetTypeId() == TYPEID_PLAYER )
- pet->SendUpdateToPlayer( (Player*)unit_target );
- if(Unit* powner = pet->GetCharmerOrOwner())
+ if(unit_target)
+ {
+ pet->SetInFront(unit_target);
+ if (unit_target->GetTypeId() == TYPEID_PLAYER)
+ pet->SendUpdateToPlayer( (Player*)unit_target );
+ }
+ else if(Unit *unit_target2 = spell->m_targets.getUnitTarget())
+ {
+ pet->SetInFront(unit_target2);
+ if (unit_target2->GetTypeId() == TYPEID_PLAYER)
+ pet->SendUpdateToPlayer( (Player*)unit_target2 );
+ }
+ if (Unit* powner = pet->GetCharmerOrOwner())
if(powner->GetTypeId() == TYPEID_PLAYER)
pet->SendUpdateToPlayer((Player*)powner);
- result = -1;
+ result = SPELL_CAST_OK;
}
- if(result == -1)
+ if(result == SPELL_CAST_OK)
{
((Creature*)pet)->AddCreatureSpellCooldown(spellid);
- if (((Creature*)pet)->isPet())
- ((Pet*)pet)->CheckLearning(spellid);
unit_target = spell->m_targets.getUnitTarget();
@@ -239,12 +264,15 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
if( unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed())
{
- pet->clearUnitState(UNIT_STAT_FOLLOW);
- if(pet->getVictim())
- pet->AttackStop();
- pet->GetMotionMaster()->Clear();
- if (((Creature*)pet)->IsAIEnabled)
- ((Creature*)pet)->AI()->AttackStart(unit_target);
+ // This is true if pet has no target or has target but targets differs.
+ if (pet->getVictim() != unit_target)
+ {
+ if (pet->getVictim())
+ pet->AttackStop();
+ pet->GetMotionMaster()->Clear();
+ if (((Creature*)pet)->IsAIEnabled)
+ ((Creature*)pet)->AI()->AttackStart(unit_target);
+ }
}
spell->prepare(&(spell->m_targets));
@@ -254,14 +282,13 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
if(pet->isPossessed())
{
WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
- data << uint32(spellid) << uint8(2) << uint8(result);
+ data << uint8(0) << uint32(spellid) << uint8(result);
switch (result)
{
case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
data << uint32(spellInfo->RequiresSpellFocus);
break;
- case SPELL_FAILED_REQUIRES_AREA:
- data << uint32(spellInfo->AreaId);
+ default:
break;
}
SendPacket(&data);
@@ -278,7 +305,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
break;
}
default:
- sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid);
+ sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid);
}
}
@@ -286,7 +313,7 @@ void WorldSession::HandlePetNameQuery( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data,4+8);
- sLog.outDetail( "HandlePetNameQuery. CMSG_PET_NAME_QUERY\n" );
+ sLog.outDetail( "HandlePetNameQuery. CMSG_PET_NAME_QUERY" );
uint32 petnumber;
uint64 petguid;
@@ -299,7 +326,7 @@ void WorldSession::HandlePetNameQuery( WorldPacket & recv_data )
void WorldSession::SendPetNameQuery( uint64 petguid, uint32 petnumber)
{
- Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, petguid);
+ Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid);
if(!pet || !pet->GetCharmInfo() || pet->GetCharmInfo()->GetPetNumber() != petnumber)
return;
@@ -326,7 +353,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data, 8+4+2+2);
- sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION\n" );
+ sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION" );
uint64 petguid;
uint32 position;
@@ -336,16 +363,11 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
recv_data >> petguid;
- // FIXME: charmed case
- //Pet* pet = ObjectAccessor::Instance().GetPet(petguid);
- if(ObjectAccessor::FindPlayer(petguid))
- return;
-
- Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, petguid);
+ Unit* pet = ObjectAccessor::GetUnit(*_player, petguid);
- if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
+ if(!pet || pet != _player->GetFirstControlled())
{
- sLog.outError( "HandlePetSetAction: Unknown pet or pet owner.\n" );
+ sLog.outError( "HandlePetSetAction: Unknown pet or pet owner." );
return;
}
@@ -357,32 +379,33 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
}
count = (recv_data.size() == 24) ? 2 : 1;
- for(uint8 i = 0; i < count; i++)
+ for(uint8 i = 0; i < count; ++i)
{
recv_data >> position;
recv_data >> spell_id;
recv_data >> act_state;
- sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X\n", _player->GetName(), position, spell_id, act_state);
+ sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state);
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
- if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_CAST) && spell_id && !pet->HasSpell(spell_id)))
+ if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id)))
{
//sign for autocast
if(act_state == ACT_ENABLED && spell_id)
{
- if(pet->isCharmed())
- charmInfo->ToggleCreatureAutocast(spell_id, true);
- else
+ if(pet->GetTypeId() == TYPEID_UNIT && ((Creature*)pet)->isPet())
((Pet*)pet)->ToggleAutocast(spell_id, true);
+ else
+ charmInfo->ToggleCreatureAutocast(spell_id, true);
}
//sign for no/turn off autocast
else if(act_state == ACT_DISABLED && spell_id)
{
- if(pet->isCharmed())
- charmInfo->ToggleCreatureAutocast(spell_id, false);
- else
+ if(pet->GetTypeId() == TYPEID_UNIT && ((Creature*)pet)->isPet())
((Pet*)pet)->ToggleAutocast(spell_id, false);
+ else
+ charmInfo->ToggleCreatureAutocast(spell_id, false);
+
}
charmInfo->GetActionBarEntry(position)->Type = act_state;
@@ -395,7 +418,7 @@ void WorldSession::HandlePetRename( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data, 8+1);
- sLog.outDetail( "HandlePetRename. CMSG_PET_RENAME\n" );
+ sLog.outDetail( "HandlePetRename. CMSG_PET_RENAME" );
uint64 petguid;
uint8 isdeclined;
@@ -478,7 +501,7 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
sLog.outDetail( "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid) );
// pet/charmed
- Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, guid);
+ Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
if(pet)
{
if(pet->isPet())
@@ -492,7 +515,7 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
_player->RemovePet((Pet*)pet,PET_SAVE_AS_DELETED);
}
else if(pet->GetGUID() == _player->GetCharmGUID())
- _player->Uncharm();
+ _player->StopCastingCharm();
}
}
@@ -502,16 +525,16 @@ void WorldSession::HandlePetUnlearnOpcode(WorldPacket& recvPacket)
sLog.outDetail("CMSG_PET_UNLEARN");
uint64 guid;
- recvPacket >> guid;
+ recvPacket >> guid; // Pet guid
Pet* pet = _player->GetPet();
- if(!pet || pet->getPetType() != HUNTER_PET || pet->m_spells.size() <= 1)
+ if(!pet || pet->getPetType() != HUNTER_PET || pet->m_usedTalentCount == 0)
return;
if(guid != pet->GetGUID())
{
- sLog.outError( "HandlePetUnlearnOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
+ sLog.outError( "HandlePetUnlearnOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
return;
}
@@ -521,38 +544,7 @@ void WorldSession::HandlePetUnlearnOpcode(WorldPacket& recvPacket)
sLog.outError("WorldSession::HandlePetUnlearnOpcode: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
return;
}
-
- uint32 cost = pet->resetTalentsCost();
-
- if (GetPlayer()->GetMoney() < cost)
- {
- GetPlayer()->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
- return;
- }
-
- for(PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end();)
- {
- uint32 spell_id = itr->first; // Pet::removeSpell can invalidate iterator at erase NEW spell
- ++itr;
- pet->removeSpell(spell_id);
- }
-
- pet->SetTP(pet->getLevel() * (pet->GetLoyaltyLevel() - 1));
-
- for(uint8 i = 0; i < 10; i++)
- {
- if(charmInfo->GetActionBarEntry(i)->SpellOrAction && charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED)
- charmInfo->GetActionBarEntry(i)->SpellOrAction = 0;
- }
-
- // relearn pet passives
- pet->LearnPetPassives();
-
- pet->m_resetTalentsTime = time(NULL);
- pet->m_resetTalentsCost = cost;
- GetPlayer()->ModifyMoney(-(int32)cost);
-
- GetPlayer()->PetSpellInitialize();
+ pet->resetTalents();
}
void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
@@ -566,22 +558,22 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
uint8 state; //1 for on, 0 for off
recvPacket >> guid >> spellid >> spellid2 >> state;
- if(!_player->GetPet() && !_player->GetCharm())
+ if(!_player->GetGuardianPet() && !_player->GetCharm())
return;
if(ObjectAccessor::FindPlayer(guid))
return;
- Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
+ Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid);
- if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
+ if(!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm()))
{
- sLog.outError( "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
+ sLog.outError( "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
return;
}
// do not add not learned spells/ passive spells
- if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
+ if(!pet->HasSpell(spellid) || IsAutocastableSpell(spellid))
return;
CharmInfo *charmInfo = pet->GetCharmInfo();
@@ -591,11 +583,10 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
return;
}
- if(pet->isCharmed())
- //state can be used as boolean
- pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state);
- else
+ if(pet->isPet())
((Pet*)pet)->ToggleAutocast(spellid, state);
+ else
+ pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state);
for(uint8 i = 0; i < 10; ++i)
{
@@ -608,21 +599,25 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
{
sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL");
- CHECK_PACKET_SIZE(recvPacket,8+4);
+ CHECK_PACKET_SIZE(recvPacket,8+1+4+1);
uint64 guid;
uint32 spellid;
+ uint8 cast_count;
+ uint8 unk_flags; // flags (if 0x02 - some additional data are received)
+
+ recvPacket >> guid >> cast_count >> spellid >> unk_flags;
- recvPacket >> guid >> spellid;
+ sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags);
// This opcode is also sent from charmed and possessed units (players and creatures)
- if(!_player->GetPet() && !_player->GetCharm())
+ if(!_player->GetGuardianPet() && !_player->GetCharm())
return;
Unit* caster = ObjectAccessor::GetUnit(*_player, guid);
- if(!caster || (caster != _player->GetPet() && caster != _player->GetCharm()))
+ if(!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm()))
{
- sLog.outError( "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
+ sLog.outError( "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
return;
}
@@ -632,7 +627,7 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
if(!spellInfo)
{
- sLog.outError("WORLD: unknown PET spell id %i\n", spellid);
+ sLog.outError("WORLD: unknown PET spell id %i", spellid);
return;
}
@@ -647,10 +642,11 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
caster->clearUnitState(UNIT_STAT_FOLLOW);
Spell *spell = new Spell(caster, spellInfo, false);
+ spell->m_cast_count = cast_count; // probably pending spell cast
spell->m_targets = targets;
- int16 result = spell->PetCanCast(NULL);
- if(result == -1)
+ SpellCastResult result = spell->CheckPetCast(NULL);
+ if(result == SPELL_CAST_OK)
{
if(caster->GetTypeId() == TYPEID_UNIT)
{
@@ -659,7 +655,6 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
if(pet->isPet())
{
Pet* p = (Pet*)pet;
- p->CheckLearning(spellid);
// 10% chance to play special pet attack talk, else growl
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
if(p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
@@ -706,3 +701,15 @@ void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, Dec
SendPacket(&data);
}
+void WorldSession::HandlePetLearnTalent( WorldPacket & recv_data )
+{
+ sLog.outDebug("WORLD: CMSG_PET_LEARN_TALENT");
+
+ CHECK_PACKET_SIZE(recv_data, 8+4+4);
+
+ uint64 guid;
+ uint32 talent_id, requested_rank;
+ recv_data >> guid >> talent_id >> requested_rank;
+
+ _player->LearnPetTalent(guid, talent_id, requested_rank);
+}
diff --git a/src/game/PetitionsHandler.cpp b/src/game/PetitionsHandler.cpp
index 7ae368140c7..19457caa048 100644
--- a/src/game/PetitionsHandler.cpp
+++ b/src/game/PetitionsHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +28,6 @@
#include "Opcodes.h"
#include "Guild.h"
#include "ArenaTeam.h"
-#include "MapManager.h"
#include "GossipDef.h"
#include "SocialMgr.h"
@@ -83,7 +82,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str());
// prevent cheating
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guidNPC,UNIT_NPC_FLAG_PETITIONER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guidNPC,UNIT_NPC_FLAG_PETITIONER);
if (!pCreature)
{
sLog.outDebug("WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC));
@@ -92,7 +91,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
uint32 charterid = 0;
uint32 cost = 0;
@@ -199,9 +198,9 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
if(!charter)
return;
- charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT, charter->GetGUIDLow());
- // ITEM_FIELD_ENCHANTMENT is guild/arenateam id
- // ITEM_FIELD_ENCHANTMENT+1 is current signatures count (showed on item)
+ charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow());
+ // ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id
+ // ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item)
charter->SetState(ITEM_CHANGED, _player);
_player->SendNewItem(charter, 1, true, false);
@@ -255,7 +254,7 @@ void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data)
QueryResult *result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low);
if(!result)
{
- sLog.outError("any petition on server...");
+ sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName());
return;
}
Field *fields = result->Fetch();
@@ -280,10 +279,10 @@ void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data)
data << petitionguid_low; // guild guid (in Trinity always same as GUID_LOPART(petitionguid)
data << signs; // sign's count
- for(uint8 i = 1; i <= signs; i++)
+ for(uint8 i = 1; i <= signs; ++i)
{
- Field *fields = result->Fetch();
- uint64 plguid = fields[0].GetUInt64();
+ Field *fields2 = result->Fetch();
+ uint64 plguid = fields2[0].GetUInt64();
data << plguid; // Player GUID
data << (uint32)0; // there 0 ...
@@ -463,7 +462,7 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data)
if(!result)
{
- sLog.outError("any petition on server...");
+ sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName());
return;
}
@@ -565,7 +564,7 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data)
// update signs count on charter, required testing...
//Item *item = _player->GetItemByGuid(petitionguid));
//if(item)
- // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+1, signs);
+ // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs);
// update for owner if online
if(Player *owner = objmgr.GetPlayer(ownerguid))
@@ -691,10 +690,10 @@ void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data)
data << GUID_LOPART(petitionguid); // guild guid (in Trinity always same as GUID_LOPART(petition guid)
data << signs; // sign's count
- for(uint8 i = 1; i <= signs; i++)
+ for(uint8 i = 1; i <= signs; ++i)
{
- Field *fields = result->Fetch();
- uint64 plguid = fields[0].GetUInt64();
+ Field *fields2 = result->Fetch();
+ plguid = fields2[0].GetUInt64();
data << plguid; // Player GUID
data << (uint32)0; // there 0 ...
@@ -827,7 +826,7 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data)
if(type == 9) // create guild
{
Guild* guild = new Guild;
- if(!guild->create(_player->GetGUID(), name))
+ if(!guild->create(_player, name))
{
delete guild;
delete result;
@@ -907,7 +906,7 @@ void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data)
void WorldSession::SendPetitionShowList(uint64 guid)
{
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_PETITIONER);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER);
if (!pCreature)
{
sLog.outDebug("WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
@@ -916,7 +915,7 @@ void WorldSession::SendPetitionShowList(uint64 guid)
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
uint8 count = 0;
if(pCreature->isTabardDesigner())
@@ -960,7 +959,7 @@ void WorldSession::SendPetitionShowList(uint64 guid)
data << uint32(5); // unknown
data << uint32(5); // required signs?
}
- //for(uint8 i = 0; i < count; i++)
+ //for(uint8 i = 0; i < count; ++i)
//{
// data << uint32(i); // index
// data << uint32(GUILD_CHARTER); // charter entry
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index e91728ab9be..88932020d38 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,13 +23,13 @@
#include "Database/DatabaseEnv.h"
#include "Log.h"
#include "Opcodes.h"
-#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "UpdateMask.h"
#include "Player.h"
+#include "Vehicle.h"
#include "SkillDiscovery.h"
#include "QuestDef.h"
#include "GossipDef.h"
@@ -49,7 +49,6 @@
#include "Group.h"
#include "Guild.h"
#include "Pet.h"
-#include "SpellAuras.h"
#include "Util.h"
#include "Transports.h"
#include "Weather.h"
@@ -63,11 +62,13 @@
#include "Database/DatabaseImpl.h"
#include "Spell.h"
#include "SocialMgr.h"
-#include "GameEvent.h"
+#include "GameEventMgr.h"
+#include "AchievementMgr.h"
+#include "SpellAuras.h"
#include <cmath>
-#define ZONE_UPDATE_INTERVAL 1000
+#define ZONE_UPDATE_INTERVAL (1*IN_MILISECONDS)
#define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3))
#define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1)
@@ -132,9 +133,20 @@ PlayerTaxi::PlayerTaxi()
memset(m_taximask, 0, sizeof(m_taximask));
}
-void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 level)
+void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint32 level)
{
- // capital and taxi hub masks
+ // class specific initial known nodes
+ switch(chrClass)
+ {
+ case CLASS_DEATH_KNIGHT:
+ {
+ for(int i = 0; i < TaxiMaskSize; ++i)
+ m_taximask[i] |= sOldContinentsNodesMask[i];
+ break;
+ }
+ }
+
+ // race specific initial known nodes: capital and taxi hub masks
switch(race)
{
case RACE_HUMAN: SetTaximaskNode(2); break; // Human
@@ -149,6 +161,7 @@ void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 level)
case RACE_BLOODELF: SetTaximaskNode(82); break; // Blood Elf
case RACE_DRAENEI: SetTaximaskNode(94); break; // Draenei
}
+
// new continent starting masks (It will be accessible only at new map)
switch(Player::TeamForRace(race))
{
@@ -188,7 +201,7 @@ void PlayerTaxi::AppendTaximaskTo( ByteBuffer& data, bool all )
}
}
-bool PlayerTaxi::LoadTaxiDestinationsFromString( const std::string& values )
+bool PlayerTaxi::LoadTaxiDestinationsFromString( const std::string& values, uint32 team )
{
ClearTaxiDestinations();
@@ -216,6 +229,10 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString( const std::string& values )
return false;
}
+ // can't load taxi path without mount set (quest taxi path?)
+ if(!objmgr.GetTaxiMount(GetTaxiSource(),team,true))
+ return false;
+
return true;
}
@@ -245,16 +262,21 @@ uint32 PlayerTaxi::GetCurrentTaxiPath() const
return path;
}
-//== Player ====================================================
+std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)
+{
+ ss << "'";
+ for(int i = 0; i < TaxiMaskSize; ++i)
+ ss << taxi.m_taximask[i] << " ";
+ ss << "'";
+ return ss;
+}
-const int32 Player::ReputationRank_Length[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000};
+//== Player ====================================================
UpdateMask Player::updateVisualBits;
-Player::Player (WorldSession *session): Unit()
+Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputationMgr(this)
{
- m_transport = 0;
-
m_speakTime = 0;
m_speakCount = 0;
@@ -280,6 +302,7 @@ Player::Player (WorldSession *session): Unit()
m_comboPoints = 0;
m_usedTalentCount = 0;
+ m_questRewardTalentCount = 0;
m_regenTimer = 0;
m_weaponChangeTimer = 0;
@@ -306,7 +329,7 @@ Player::Player (WorldSession *session): Unit()
// group is initialized in the reference constructor
SetGroupInvite(NULL);
m_groupUpdateMask = 0;
- m_auraUpdateMask = 0;
+ m_auraRaidUpdateMask = 0;
duel = NULL;
@@ -315,7 +338,8 @@ Player::Player (WorldSession *session): Unit()
m_atLoginFlags = AT_LOGIN_NONE;
- m_dontMove = false;
+ mSemaphoreTeleport_Near = false;
+ mSemaphoreTeleport_Far = false;
pTrader = 0;
ClearTrade();
@@ -332,10 +356,11 @@ Player::Player (WorldSession *session): Unit()
m_DailyQuestChanged = false;
m_lastDailyQuestTime = 0;
- m_regenTimer = 0;
- m_weaponChangeTimer = 0;
- m_breathTimer = 0;
- m_isunderwater = 0;
+ for (int i=0; i<MAX_TIMERS; i++)
+ m_MirrorTimer[i] = DISABLED_MIRROR_TIMER;
+
+ m_MirrorTimerFlags = UNDERWATER_NONE;
+ m_MirrorTimerFlagsLast = UNDERWATER_NONE;
m_isInWater = false;
m_drunkTimer = 0;
m_drunk = 0;
@@ -345,12 +370,13 @@ Player::Player (WorldSession *session): Unit()
m_swingErrorMsg = 0;
- m_DetectInvTimer = 1000;
+ m_DetectInvTimer = 1*IN_MILISECONDS;
m_bgBattleGroundID = 0;
+ m_bgTypeID = BATTLEGROUND_TYPE_NONE;
for (int j=0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; j++)
{
- m_bgBattleGroundQueueID[j].bgQueueType = 0;
+ m_bgBattleGroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
m_bgBattleGroundQueueID[j].invitedToInstance = 0;
}
m_bgTeam = 0;
@@ -362,6 +388,7 @@ Player::Player (WorldSession *session): Unit()
m_canParry = false;
m_canBlock = false;
m_canDualWield = false;
+ m_canTitanGrip = false;
m_ammoDPS = 0.0f;
m_temporaryUnsummonedPetNumber = 0;
@@ -400,12 +427,22 @@ Player::Player (WorldSession *session): Unit()
m_InstanceValid = true;
m_dungeonDifficulty = DIFFICULTY_NORMAL;
+ m_lastPotionId = 0;
+
for (int i = 0; i < BASEMOD_END; i++)
{
m_auraBaseMod[i][FLAT_MOD] = 0.0f;
m_auraBaseMod[i][PCT_MOD] = 1.0f;
}
+ for (int i = 0; i < MAX_COMBAT_RATING; i++)
+ m_baseRatingValue[i] = 0;
+
+ m_baseSpellDamage = 0;
+ m_baseSpellHealing = 0;
+ m_baseFeralAP = 0;
+ m_baseManaRegen = 0;
+
// Honor System
m_lastHonorUpdateTime = time(NULL);
@@ -419,7 +456,9 @@ Player::Player (WorldSession *session): Unit()
//Default movement to run mode
m_unit_movement_flags = 0;
- m_miniPet = 0;
+ m_mover = this;
+ m_seer = this;
+
m_bgAfkReportedTimer = 0;
m_contestedPvPTimer = 0;
@@ -427,13 +466,16 @@ Player::Player (WorldSession *session): Unit()
m_isActive = true;
- m_farsightVision = false;
+ m_runes = NULL;
+
+ m_lastFallTime = 0;
+ m_lastFallZ = 0;
+
+ m_ControlledByPlayer = true;
}
Player::~Player ()
{
- CleanupsBeforeDelete();
-
// it must be unloaded already in PlayerLogout and accessed only for loggined player
//m_social = NULL;
@@ -443,7 +485,6 @@ Player::~Player ()
if(m_items[i])
delete m_items[i];
}
- CleanupChannels();
for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
delete itr->second;
@@ -457,31 +498,28 @@ Player::~Player ()
delete PlayerTalkClass;
- if (m_transport)
- {
- m_transport->RemovePassenger(this);
- }
-
for(size_t x = 0; x < ItemSetEff.size(); x++)
if(ItemSetEff[x])
delete ItemSetEff[x];
- // clean up player-instance binds, may unload some instance saves
- for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
- for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
- itr->second.save->RemovePlayer(this);
-
delete m_declinedname;
+ delete m_runes;
}
void Player::CleanupsBeforeDelete()
{
- if(m_uint32Values) // only for fully created Object
- {
- TradeCancel(false);
- DuelComplete(DUEL_INTERUPTED);
- }
+ TradeCancel(false);
+ DuelComplete(DUEL_INTERUPTED);
+
Unit::CleanupsBeforeDelete();
+
+ if (m_transport)
+ m_transport->RemovePassenger(this);
+
+ // clean up player-instance binds, may unload some instance saves
+ for(uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i)
+ for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
+ itr->second.save->RemovePlayer(this);
}
bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 class_, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair, uint8 outfitId )
@@ -517,24 +555,8 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
uint8 powertype = cEntry->powerType;
- uint32 unitfield;
-
- switch(powertype)
- {
- case POWER_ENERGY:
- case POWER_MANA:
- unitfield = 0x00000000;
- break;
- case POWER_RAGE:
- unitfield = 0x00110000;
- break;
- default:
- sLog.outError("Invalid default powertype %u for player (class %u)",powertype,class_);
- return false;
- }
-
- SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE );
- SetFloatValue(UNIT_FIELD_COMBATREACH, DEFAULT_COMBAT_REACH );
+ SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE);
+ SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f);
switch(gender)
{
@@ -557,12 +579,13 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
uint32 RaceClassGender = ( race ) | ( class_ << 8 ) | ( gender << 16 );
SetUInt32Value(UNIT_FIELD_BYTES_0, ( RaceClassGender | ( powertype << 24 ) ) );
- SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield);
- SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY | UNIT_BYTE2_FLAG_UNK5 );
- SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE );
+ SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP );
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE );
+ SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); // fix cast time showed in spell tooltip on client
+ SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); // default for players in 3.0.3
- //-1 is default value
+ // -1 is default value
SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1));
SetUInt32Value(PLAYER_BYTES, (skin | (face << 8) | (hairStyle << 16) | (hairColor << 24)));
@@ -574,6 +597,7 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
SetUInt32Value( PLAYER_GUILD_TIMESTAMP, 0 );
SetUInt64Value( PLAYER__FIELD_KNOWN_TITLES, 0 ); // 0=disabled
+ SetUInt64Value( PLAYER__FIELD_KNOWN_TITLES1, 0 ); // 0=disabled
SetUInt32Value( PLAYER_CHOSEN_TITLE, 0 );
SetUInt32Value( PLAYER_FIELD_KILLS, 0 );
SetUInt32Value( PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 0 );
@@ -581,10 +605,20 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
SetUInt32Value( PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0 );
// set starting level
+ uint32 start_level = getClass() != CLASS_DEATH_KNIGHT
+ ? sWorld.getConfig(CONFIG_START_PLAYER_LEVEL)
+ : sWorld.getConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
+
if (GetSession()->GetSecurity() >= SEC_MODERATOR)
- SetUInt32Value (UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_GM_LEVEL));
- else
- SetUInt32Value (UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_PLAYER_LEVEL));
+ {
+ uint32 gm_level = sWorld.getConfig(CONFIG_START_GM_LEVEL);
+ if(gm_level > start_level)
+ start_level = gm_level;
+ }
+
+ SetUInt32Value(UNIT_FIELD_LEVEL, start_level);
+
+ InitRunes();
SetUInt32Value (PLAYER_FIELD_COINAGE, sWorld.getConfig(CONFIG_START_PLAYER_MONEY));
SetUInt32Value (PLAYER_FIELD_HONOR_CURRENCY, sWorld.getConfig(CONFIG_START_HONOR_POINTS));
@@ -600,40 +634,40 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
//Reputations if "StartAllReputation" is enabled, -- TODO: Fix this in a better way
if(sWorld.getConfig(CONFIG_START_ALL_REP))
{
- SetFactionReputation(sFactionStore.LookupEntry(942),42999);
- SetFactionReputation(sFactionStore.LookupEntry(935),42999);
- SetFactionReputation(sFactionStore.LookupEntry(936),42999);
- SetFactionReputation(sFactionStore.LookupEntry(1011),42999);
- SetFactionReputation(sFactionStore.LookupEntry(970),42999);
- SetFactionReputation(sFactionStore.LookupEntry(967),42999);
- SetFactionReputation(sFactionStore.LookupEntry(989),42999);
- SetFactionReputation(sFactionStore.LookupEntry(932),42999);
- SetFactionReputation(sFactionStore.LookupEntry(934),42999);
- SetFactionReputation(sFactionStore.LookupEntry(1038),42999);
- SetFactionReputation(sFactionStore.LookupEntry(1077),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(942),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(935),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(936),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1011),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(970),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(967),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(989),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(932),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(934),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1038),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1077),42999);
// Factions depending on team, like cities and some more stuff
switch(GetTeam())
{
case ALLIANCE:
- SetFactionReputation(sFactionStore.LookupEntry(72),42999);
- SetFactionReputation(sFactionStore.LookupEntry(47),42999);
- SetFactionReputation(sFactionStore.LookupEntry(69),42999);
- SetFactionReputation(sFactionStore.LookupEntry(930),42999);
- SetFactionReputation(sFactionStore.LookupEntry(730),42999);
- SetFactionReputation(sFactionStore.LookupEntry(978),42999);
- SetFactionReputation(sFactionStore.LookupEntry(54),42999);
- SetFactionReputation(sFactionStore.LookupEntry(946),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(72),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(47),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(69),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(930),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(730),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(978),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(54),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(946),42999);
break;
case HORDE:
- SetFactionReputation(sFactionStore.LookupEntry(76),42999);
- SetFactionReputation(sFactionStore.LookupEntry(68),42999);
- SetFactionReputation(sFactionStore.LookupEntry(81),42999);
- SetFactionReputation(sFactionStore.LookupEntry(911),42999);
- SetFactionReputation(sFactionStore.LookupEntry(729),42999);
- SetFactionReputation(sFactionStore.LookupEntry(941),42999);
- SetFactionReputation(sFactionStore.LookupEntry(530),42999);
- SetFactionReputation(sFactionStore.LookupEntry(947),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(76),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(68),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(81),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(911),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(729),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(941),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(530),42999);
+ GetReputationMgr().SetReputation(sFactionStore.LookupEntry(947),42999);
break;
default:
break;
@@ -648,6 +682,7 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
// base stats and related field values
InitStatsForLevel();
InitTaxiNodesForLevel();
+ InitGlyphsForLevel();
InitTalentForLevel();
InitPrimaryProffesions(); // to max set before any spell added
@@ -660,8 +695,16 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
SetPower(POWER_MANA,GetMaxPower(POWER_MANA));
}
+ if(getPowerType() == POWER_RUNIC_POWER)
+ {
+ SetPower(POWER_RUNE, 8);
+ SetMaxPower(POWER_RUNE, 8);
+ SetPower(POWER_RUNIC_POWER, 0);
+ SetMaxPower(POWER_RUNIC_POWER, 1000);
+ }
+
// original spells
- learnDefaultSpells(true);
+ learnDefaultSpells();
// original action bar
std::list<uint16>::const_iterator action_itr[4];
@@ -703,6 +746,11 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
uint32 item_id = oEntry->ItemId[j];
+
+ // Hack for not existed item id in dbc 3.0.3
+ if(item_id==40582)
+ continue;
+
ItemPrototype const* iProto = objmgr.GetItemPrototype(item_id);
if(!iProto)
{
@@ -710,7 +758,9 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
continue;
}
- uint32 count = iProto->Stackable; // max stack by default (mostly 1)
+ // max stack by default (mostly 1), 1 for infinity stackable
+ uint32 count = iProto->Stackable > 0 ? uint32(iProto->Stackable) : 1;
+
if(iProto->Class==ITEM_CLASS_CONSUMABLE && iProto->SubClass==ITEM_SUBCLASS_FOOD)
{
switch(iProto->Spells[0].SpellCategory)
@@ -760,9 +810,9 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
}
// if this is ammo then use it
- uint8 msg = CanUseAmmo( pItem->GetProto()->ItemId );
+ msg = CanUseAmmo( pItem->GetEntry() );
if( msg == EQUIP_ERR_OK )
- SetAmmo( pItem->GetProto()->ItemId );
+ SetAmmo( pItem->GetEntry() );
}
}
}
@@ -806,25 +856,14 @@ bool Player::StoreNewItemInBestSlots(uint32 titem_id, uint32 titem_amount)
return false;
}
-void Player::StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue)
-{
- uint32 BreathRegen = (uint32)-1;
-
- WorldPacket data(SMSG_START_MIRROR_TIMER, (21));
- data << (uint32)Type;
- data << MaxValue;
- data << MaxValue;
- data << BreathRegen;
- data << (uint8)0;
- data << (uint32)0; // spell id
- GetSession()->SendPacket(&data);
-}
-
-void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen)
+void Player::SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen)
{
- if(Type==BREATH_TIMER)
- m_breathTimer = ((MaxValue + 1000) - CurrentValue) / Regen;
-
+ if (MaxValue == DISABLED_MIRROR_TIMER)
+ {
+ if (CurrentValue!=DISABLED_MIRROR_TIMER)
+ StopMirrorTimer(Type);
+ return;
+ }
WorldPacket data(SMSG_START_MIRROR_TIMER, (21));
data << (uint32)Type;
data << CurrentValue;
@@ -837,150 +876,201 @@ void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 Cur
void Player::StopMirrorTimer(MirrorTimerType Type)
{
- if(Type==BREATH_TIMER)
- m_breathTimer = 0;
-
+ m_MirrorTimer[Type] = DISABLED_MIRROR_TIMER;
WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4);
data << (uint32)Type;
GetSession()->SendPacket( &data );
}
-void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 damage)
+void Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
{
+ if(!isAlive() || isGameMaster())
+ return;
+
+ // Absorb, resist some environmental damage type
+ uint32 absorb = 0;
+ uint32 resist = 0;
+ if (type == DAMAGE_LAVA)
+ CalcAbsorbResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist);
+ else if (type == DAMAGE_SLIME)
+ CalcAbsorbResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist);
+
+ damage-=absorb+resist;
+
+ DealDamageMods(this,damage,&absorb);
+
WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21));
- data << (uint64)guid;
- data << (uint8)(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL);
- data << (uint32)damage;
- data << (uint32)0;
- data << (uint32)0;
+ data << uint64(GetGUID());
+ data << uint8(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL);
+ data << uint32(damage);
+ data << uint32(absorb);
+ data << uint32(resist);
SendMessageToSet(&data, true);
DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- if(type==DAMAGE_FALL && !isAlive()) // DealDamage not apply item durability loss at self damage
+ if(!isAlive())
{
- DEBUG_LOG("We are fall to death, loosing 10 percents durability");
- DurabilityLossAll(0.10f,false);
- // durability lost message
- WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
- GetSession()->SendPacket(&data);
+ if(type==DAMAGE_FALL) // DealDamage not apply item durability loss at self damage
+ {
+ DEBUG_LOG("We are fall to death, loosing 10 percents durability");
+ DurabilityLossAll(0.10f,false);
+ // durability lost message
+ WorldPacket data2(SMSG_DURABILITY_DAMAGE_DEATH, 0);
+ GetSession()->SendPacket(&data2);
+ }
+
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM, 1, type);
}
}
-void Player::HandleDrowning()
+int32 Player::getMaxTimer(MirrorTimerType timer)
{
- if(!m_isunderwater)
- return;
-
- //if player is GM, have waterbreath, is dead or if breathing is disabled then return
- if(waterbreath || isGameMaster() || !isAlive() || GetSession()->GetSecurity() >= sWorld.getConfig(CONFIG_DISABLE_BREATHING))
+ switch (timer)
{
- StopMirrorTimer(BREATH_TIMER);
- m_isunderwater = 0;
- return;
+ case FATIGUE_TIMER:
+ return MINUTE*IN_MILISECONDS;
+ case BREATH_TIMER:
+ {
+ if (!isAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= sWorld.getConfig(CONFIG_DISABLE_BREATHING))
+ return DISABLED_MIRROR_TIMER;
+ int32 UnderWaterTime = 3*MINUTE*IN_MILISECONDS;
+ AuraEffectList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING);
+ for(AuraEffectList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
+ UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetAmount()) / 100.0f);
+ return UnderWaterTime;
+ }
+ case FIRE_TIMER:
+ {
+ if (!isAlive())
+ return DISABLED_MIRROR_TIMER;
+ return 1*IN_MILISECONDS;
+ }
+ default:
+ return 0;
}
+ return 0;
+}
- uint32 UnderWaterTime = 1*MINUTE*1000; // default length 1 min
+void Player::UpdateMirrorTimers()
+{
+ // Desync flags for update on next HandleDrowning
+ if (m_MirrorTimerFlags)
+ m_MirrorTimerFlagsLast = ~m_MirrorTimerFlags;
+}
- AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING);
- for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
- UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifierValue()) / 100.0f);
+void Player::HandleDrowning(uint32 time_diff)
+{
+ if (!m_MirrorTimerFlags)
+ return;
- if ((m_isunderwater & 0x01) && !(m_isunderwater & 0x80) && isAlive())
+ // In water
+ if (m_MirrorTimerFlags & UNDERWATER_INWATER)
{
- //single trigger timer
- if (!(m_isunderwater & 0x02))
- {
- m_isunderwater|= 0x02;
- m_breathTimer = UnderWaterTime + 1000;
- }
- //single trigger "Breathbar"
- if ( m_breathTimer <= UnderWaterTime && !(m_isunderwater & 0x04))
+ // Breath timer not activated - activate it
+ if (m_MirrorTimer[BREATH_TIMER] == DISABLED_MIRROR_TIMER)
{
- m_isunderwater|= 0x04;
- StartMirrorTimer(BREATH_TIMER, UnderWaterTime);
+ m_MirrorTimer[BREATH_TIMER] = getMaxTimer(BREATH_TIMER);
+ SendMirrorTimer(BREATH_TIMER, m_MirrorTimer[BREATH_TIMER], m_MirrorTimer[BREATH_TIMER], -1);
}
- //continuous trigger drowning "Damage"
- if ((m_breathTimer == 0) && (m_isunderwater & 0x01))
+ else // If activated - do tick
{
- //TODO: Check this formula
- uint64 guid = GetGUID();
- uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1);
-
- EnvironmentalDamage(guid, DAMAGE_DROWNING,damage);
- m_breathTimer = 2000;
+ m_MirrorTimer[BREATH_TIMER]-=time_diff;
+ // Timer limit - need deal damage
+ if (m_MirrorTimer[BREATH_TIMER] < 0)
+ {
+ m_MirrorTimer[BREATH_TIMER]+= 1*IN_MILISECONDS;
+ // Calculate and deal damage
+ // TODO: Check this formula
+ uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1);
+ EnvironmentalDamage(DAMAGE_DROWNING, damage);
+ }
+ else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INWATER)) // Update time in client if need
+ SendMirrorTimer(BREATH_TIMER, getMaxTimer(BREATH_TIMER), m_MirrorTimer[BREATH_TIMER], -1);
}
}
- //single trigger retract bar
- else if (!(m_isunderwater & 0x01) && !(m_isunderwater & 0x08) && (m_isunderwater & 0x02) && (m_breathTimer > 0) && isAlive())
+ else if (m_MirrorTimer[BREATH_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer
{
- m_isunderwater = 0x08;
-
- uint32 BreathRegen = 10;
- ModifyMirrorTimer(BREATH_TIMER, UnderWaterTime, m_breathTimer,BreathRegen);
- m_isunderwater = 0x10;
- }
- //remove bar
- else if ((m_breathTimer < 50) && !(m_isunderwater & 0x01) && (m_isunderwater == 0x10))
- {
- StopMirrorTimer(BREATH_TIMER);
- m_isunderwater = 0;
+ int32 UnderWaterTime = getMaxTimer(BREATH_TIMER);
+ // Need breath regen
+ m_MirrorTimer[BREATH_TIMER]+=10*time_diff;
+ if (m_MirrorTimer[BREATH_TIMER] >= UnderWaterTime || !isAlive())
+ StopMirrorTimer(BREATH_TIMER);
+ else if (m_MirrorTimerFlagsLast & UNDERWATER_INWATER)
+ SendMirrorTimer(BREATH_TIMER, UnderWaterTime, m_MirrorTimer[BREATH_TIMER], 10);
}
-}
-
-void Player::HandleLava()
-{
- bool ValidArea = false;
- if ((m_isunderwater & 0x80) && isAlive())
+ // In dark water
+ if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER)
{
- //Single trigger Set BreathTimer
- if (!(m_isunderwater & 0x80))
+ // Fatigue timer not activated - activate it
+ if (m_MirrorTimer[FATIGUE_TIMER] == DISABLED_MIRROR_TIMER)
{
- m_isunderwater|= 0x04;
- m_breathTimer = 1000;
+ m_MirrorTimer[FATIGUE_TIMER] = getMaxTimer(FATIGUE_TIMER);
+ SendMirrorTimer(FATIGUE_TIMER, m_MirrorTimer[FATIGUE_TIMER], m_MirrorTimer[FATIGUE_TIMER], -1);
}
- //Reset BreathTimer and still in the lava
- if (!m_breathTimer)
+ else
{
- uint64 guid = GetGUID();
- uint32 damage = urand(600, 700); // TODO: Get more detailed information about lava damage
- uint32 dmgZone = GetZoneId(); // TODO: Find correct "lava dealing zone" flag in Area Table
-
- // Deal lava damage only in lava zones.
- switch(dmgZone)
+ m_MirrorTimer[FATIGUE_TIMER]-=time_diff;
+ // Timer limit - need deal damage or teleport ghost to graveyard
+ if (m_MirrorTimer[FATIGUE_TIMER] < 0)
{
- case 0x8D:
- ValidArea = false;
- break;
- case 0x94:
- ValidArea = false;
- break;
- case 0x2CE:
- ValidArea = false;
- break;
- case 0x2CF:
- ValidArea = false;
- break;
- default:
- if (dmgZone / 5 & 0x408)
- ValidArea = true;
+ m_MirrorTimer[FATIGUE_TIMER]+= 1*IN_MILISECONDS;
+ if (isAlive()) // Calculate and deal damage
+ {
+ uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1);
+ EnvironmentalDamage(DAMAGE_EXHAUSTED, damage);
+ }
+ else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) // Teleport ghost to graveyard
+ RepopAtGraveyard();
}
-
- // if is valid area and is not gamemaster then deal damage
- if ( ValidArea && !isGameMaster() )
- EnvironmentalDamage(guid, DAMAGE_LAVA, damage);
-
- m_breathTimer = 1000;
+ else if (!(m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER))
+ SendMirrorTimer(FATIGUE_TIMER, getMaxTimer(FATIGUE_TIMER), m_MirrorTimer[FATIGUE_TIMER], -1);
}
-
}
- //Death timer disabled and WaterFlags reset
- else if (m_deathState == DEAD)
+ else if (m_MirrorTimer[FATIGUE_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer
+ {
+ int32 DarkWaterTime = getMaxTimer(FATIGUE_TIMER);
+ m_MirrorTimer[FATIGUE_TIMER]+=10*time_diff;
+ if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !isAlive())
+ StopMirrorTimer(FATIGUE_TIMER);
+ else if (m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER)
+ SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10);
+ }
+
+ if (m_MirrorTimerFlags & (UNDERWATER_INLAVA|UNDERWATER_INSLIME))
{
- m_breathTimer = 0;
- m_isunderwater = 0;
+ // Breath timer not activated - activate it
+ if (m_MirrorTimer[FIRE_TIMER] == DISABLED_MIRROR_TIMER)
+ m_MirrorTimer[FIRE_TIMER] = getMaxTimer(FIRE_TIMER);
+ else
+ {
+ m_MirrorTimer[FIRE_TIMER]-=time_diff;
+ if (m_MirrorTimer[FIRE_TIMER] < 0)
+ {
+ m_MirrorTimer[FIRE_TIMER]+= 1*IN_MILISECONDS;
+ // Calculate and deal damage
+ // TODO: Check this formula
+ uint32 damage = urand(600, 700);
+ if (m_MirrorTimerFlags&UNDERWATER_INLAVA)
+ EnvironmentalDamage(DAMAGE_LAVA, damage);
+ else
+ EnvironmentalDamage(DAMAGE_SLIME, damage);
+ }
+ }
}
+ else
+ m_MirrorTimer[FIRE_TIMER] = DISABLED_MIRROR_TIMER;
+
+ // Recheck timers flag
+ m_MirrorTimerFlags&=~UNDERWATER_EXIST_TIMERS;
+ for (int i = 0; i< MAX_TIMERS; ++i)
+ if (m_MirrorTimer[i]!=DISABLED_MIRROR_TIMER)
+ {
+ m_MirrorTimerFlags|=UNDERWATER_EXIST_TIMERS;
+ break;
+ }
+ m_MirrorTimerFlagsLast = m_MirrorTimerFlags;
}
///The player sobers by 256 every 10 seconds
@@ -1058,8 +1148,6 @@ void Player::Update( uint32 p_time )
UpdateAfkReport(now);
- CheckExploreSystem();
-
if(isCharmed())
{
if(Unit *charmer = GetCharmer())
@@ -1203,14 +1291,15 @@ void Player::Update( uint32 p_time )
{
if(p_time >= m_zoneUpdateTimer)
{
- uint32 newzone = GetZoneId();
+ uint32 newzone, newarea;
+ GetZoneAndAreaId(newzone,newarea);
+
if( m_zoneUpdateId != newzone )
- UpdateZone(newzone); // also update area
+ UpdateZone(newzone,newarea); // also update area
else
{
// use area updates as well
// needed for free far all arenas for example
- uint32 newarea = GetAreaId();
if( m_areaUpdateId != newarea )
UpdateArea(newarea);
@@ -1245,21 +1334,8 @@ void Player::Update( uint32 p_time )
}
}
- //Breathtimer
- if(m_breathTimer > 0)
- {
- if(p_time >= m_breathTimer)
- m_breathTimer = 0;
- else
- m_breathTimer -= p_time;
-
- }
-
//Handle Water/drowning
- HandleDrowning();
-
- //Handle lava
- HandleLava();
+ HandleDrowning(p_time);
//Handle detect stealth players
if (m_DetectInvTimer > 0)
@@ -1286,7 +1362,7 @@ void Player::Update( uint32 p_time )
{
m_drunkTimer += p_time;
- if (m_drunkTimer > 10000)
+ if (m_drunkTimer > 10*IN_MILISECONDS)
HandleSobering();
}
@@ -1311,6 +1387,7 @@ void Player::Update( uint32 p_time )
Pet* pet = GetPet();
if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE) && !pet->isPossessed())
+ //if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
{
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
return;
@@ -1344,16 +1421,15 @@ void Player::setDeathState(DeathState s)
//FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequestOpcode and define pet unsummon here with (s == DEAD)
RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
- // remove uncontrolled pets
- RemoveMiniPet();
- RemoveGuardians();
-
// save value before aura remove in Unit::setDeathState
ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL);
// passive spell
if(!ressSpellId)
ressSpellId = GetResurrectionSpellId();
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, 1);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON, 1);
}
Unit::setDeathState(s);
@@ -1374,13 +1450,15 @@ void Player::setDeathState(DeathState s)
void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
{
- *p_data << GetGUID();
+ Field *fields = result->Fetch();
+
+ *p_data << uint64(GetGUID());
*p_data << m_name;
- *p_data << getRace();
+ *p_data << uint8(getRace());
uint8 pClass = getClass();
- *p_data << pClass;
- *p_data << getGender();
+ *p_data << uint8(pClass);
+ *p_data << uint8(getGender());
uint32 bytes = GetUInt32Value(PLAYER_BYTES);
*p_data << uint8(bytes);
@@ -1393,16 +1471,17 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
*p_data << uint8(getLevel()); // player level
// do not use GetMap! it will spawn a new instance since the bound instances are not loaded
- uint32 zoneId = MapManager::Instance().GetZoneId(GetMapId(), GetPositionX(),GetPositionY());
- sLog.outDebug("Player::BuildEnumData: m:%u, x:%f, y:%f, z:%f zone:%u", GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), zoneId);
- *p_data << zoneId;
- *p_data << GetMapId();
+ uint32 zoneId = fields[10].GetUInt32();
+ sLog.outDebug("Player::BuildEnumData: map:%u, x:%f, y:%f, z:%f zone:%u", GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), zoneId);
+ *p_data << uint32(zoneId);
+ *p_data << uint32(GetMapId());
*p_data << GetPositionX();
*p_data << GetPositionY();
*p_data << GetPositionZ();
- *p_data << (result ? result->Fetch()[13].GetUInt32() : 0);
+ // guild id
+ *p_data << uint32(fields[14].GetUInt32());
uint32 char_flags = 0;
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
@@ -1413,14 +1492,18 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
char_flags |= CHARACTER_FLAG_GHOST;
if(HasAtLoginFlag(AT_LOGIN_RENAME))
char_flags |= CHARACTER_FLAG_RENAME;
- // always send the flag if declined names aren't used
- // to let the client select a default method of declining the name
- if(!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) || (result && result->Fetch()[14].GetCppString() != ""))
+ if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED))
+ {
+ if(!fields[15].GetCppString().empty())
+ char_flags |= CHARACTER_FLAG_DECLINED;
+ }
+ else
char_flags |= CHARACTER_FLAG_DECLINED;
- *p_data << (uint32)char_flags; // character flags
-
- *p_data << (uint8)1; // unknown
+ *p_data << uint32(char_flags); // character flags
+ // character customize (flags?)
+ *p_data << uint32(HasAtLoginFlag(AT_LOGIN_CUSTOMIZE) ? 1 : 0);
+ *p_data << uint8(1); // unknown
// Pets info
{
@@ -1429,50 +1512,23 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
uint32 petFamily = 0;
// show pet at selection character in character list only for non-ghost character
- if(result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER))
+ if (result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT))
{
- Field* fields = result->Fetch();
-
- uint32 entry = fields[10].GetUInt32();
+ uint32 entry = fields[11].GetUInt32();
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry);
if(cInfo)
{
- petDisplayId = fields[11].GetUInt32();
- petLevel = fields[12].GetUInt32();
+ petDisplayId = fields[12].GetUInt32();
+ petLevel = fields[13].GetUInt32();
petFamily = cInfo->family;
}
}
- *p_data << (uint32)petDisplayId;
- *p_data << (uint32)petLevel;
- *p_data << (uint32)petFamily;
+ *p_data << uint32(petDisplayId);
+ *p_data << uint32(petLevel);
+ *p_data << uint32(petFamily);
}
- /*ItemPrototype const *items[EQUIPMENT_SLOT_END];
- for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
- items[i] = NULL;
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT slot,item_template FROM character_inventory WHERE guid = '%u' AND bag = 0",GetGUIDLow());
- if (result)
- {
- do
- {
- Field *fields = result->Fetch();
- uint8 slot = fields[0].GetUInt8() & 255;
- uint32 item_id = fields[1].GetUInt32();
- if( slot >= EQUIPMENT_SLOT_END )
- continue;
-
- items[slot] = objmgr.GetItemPrototype(item_id);
- if(!items[slot])
- {
- sLog.outError( "Player::BuildEnumData: Player %s have unknown item (id: #%u) in inventory, skipped.", GetName(),item_id );
- continue;
- }
- } while (result->NextRow());
- delete result;
- }*/
-
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++)
{
uint32 visualbase = PLAYER_VISIBLE_ITEM_1_0 + (slot * MAX_VISIBLE_ITEM_OFFSET);
@@ -1489,20 +1545,20 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
if (proto != NULL)
{
- *p_data << (uint32)proto->DisplayInfoID;
- *p_data << (uint8)proto->InventoryType;
- *p_data << (uint32)(enchant?enchant->aura_id:0);
+ *p_data << uint32(proto->DisplayInfoID);
+ *p_data << uint8(proto->InventoryType);
+ *p_data << uint32(enchant ? enchant->aura_id : 0);
}
else
{
- *p_data << (uint32)0;
- *p_data << (uint8)0;
- *p_data << (uint32)0; // enchant?
+ *p_data << uint32(0);
+ *p_data << uint8(0);
+ *p_data << uint32(0); // enchant?
}
}
- *p_data << (uint32)0; // first bag display id
- *p_data << (uint8)0; // first bag inventory type
- *p_data << (uint32)0; // enchant?
+ *p_data << uint32(0); // first bag display id
+ *p_data << uint8(0); // first bag inventory type
+ *p_data << uint32(0); // enchant?
}
bool Player::ToggleAFK()
@@ -1566,19 +1622,6 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if(!InBattleGround() && mEntry->IsBattleGroundOrArena())
return false;
- // 449 - Champions' Hall (Alliance) // 450 - Hall of Legends (Horde)
- if(mapid == 449 && GetTeam()==HORDE)
- {
- GetSession()->SendNotification(LANG_NO_ENTER_CHAMPIONS_HALL);
- return false;
- }
-
- if(mapid == 450 && GetTeam() == ALLIANCE)
- {
- GetSession()->SendNotification(LANG_NO_ENTER_HALL_OF_LEGENDS);
- return false;
- }
-
// client without expansion support
if(GetSession()->Expansion() < mEntry->Expansion())
{
@@ -1587,106 +1630,69 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if(GetTransport())
RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
- SendTransferAborted(mapid, TRANSFER_ABORT_INSUF_EXPAN_LVL1);
+ SendTransferAborted(mapid, TRANSFER_ABORT_INSUF_EXPAN_LVL, mEntry->Expansion());
return false; // normal client can't teleport to this map...
}
else
{
- sLog.outDebug("Player %s will teleported to map %u", GetName(), mapid);
+ sLog.outDebug("Player %s is being teleported to map %u", GetName(), mapid);
}
- // if we were on a transport, leave
- if (!(options & TELE_TO_NOT_LEAVE_TRANSPORT) && m_transport)
+ // reset movement flags at teleport, because player will continue move with these flags after teleport
+ SetUnitMovementFlags(0);
+
+ if (m_transport)
{
- m_transport->RemovePassenger(this);
- m_transport = NULL;
- m_movementInfo.t_x = 0.0f;
- m_movementInfo.t_y = 0.0f;
- m_movementInfo.t_z = 0.0f;
- m_movementInfo.t_o = 0.0f;
- m_movementInfo.t_time = 0;
+ if (options & TELE_TO_NOT_LEAVE_TRANSPORT)
+ AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ else
+ {
+ m_transport->RemovePassenger(this);
+ m_transport = NULL;
+ m_movementInfo.t_x = 0.0f;
+ m_movementInfo.t_y = 0.0f;
+ m_movementInfo.t_z = 0.0f;
+ m_movementInfo.t_o = 0.0f;
+ m_movementInfo.t_time = 0;
+ }
}
- SetSemaphoreTeleport(true);
-
- // The player was ported to another map and looses the duel immediatly.
+ // The player was ported to another map and looses the duel immediately.
// We have to perform this check before the teleport, otherwise the
// ObjectAccessor won't find the flag.
if (duel && GetMapId()!=mapid)
{
- GameObject* obj = ObjectAccessor::GetGameObject(*this, GetUInt64Value(PLAYER_DUEL_ARBITER));
+ GameObject* obj = GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER));
if (obj)
DuelComplete(DUEL_FLED);
}
- // reset movement flags at teleport, because player will continue move with these flags after teleport
- SetUnitMovementFlags(0);
-
if ((GetMapId() == mapid) && (!m_transport))
{
- // prepare zone change detect
- uint32 old_zone = GetZoneId();
-
- // near teleport
- if(!GetSession()->PlayerLogout())
- {
- WorldPacket data;
- BuildTeleportAckMsg(&data, x, y, z, orientation);
- GetSession()->SendPacket(&data);
- SetPosition( x, y, z, orientation, true);
- }
- else
- // this will be used instead of the current location in SaveToDB
- m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
- SetFallInformation(0, z);
-
- //BuildHeartBeatMsg(&data);
- //SendMessageToSet(&data, true);
if (!(options & TELE_TO_NOT_UNSUMMON_PET))
{
- //same map, only remove pet if out of range
- if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE))
- {
- if(pet->isControlled() && !pet->isTemporarySummoned() )
- m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber();
- else
- m_temporaryUnsummonedPetNumber = 0;
-
- RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
- }
+ //same map, only remove pet if out of range for new position
+ if(pet && !pet->IsWithinDist3d(x,y,z, OWNER_MAX_DISTANCE))
+ UnsummonPetTemporaryIfAny();
}
if(!(options & TELE_TO_NOT_LEAVE_COMBAT))
CombatStop();
- if (!(options & TELE_TO_NOT_UNSUMMON_PET))
- {
- // resummon pet
- if(pet && m_temporaryUnsummonedPetNumber)
- {
- Pet* NewPet = new Pet;
- if(!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true))
- delete NewPet;
-
- m_temporaryUnsummonedPetNumber = 0;
- }
- }
+ // this will be used instead of the current location in SaveToDB
+ m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+ SetFallInformation(0, z);
+ // code for finish transfer called in WorldSession::HandleMovementOpcodes()
+ // at client packet MSG_MOVE_TELEPORT_ACK
+ SetSemaphoreTeleportNear(true);
+ // near teleport, triggering send MSG_MOVE_TELEPORT_ACK from client at landing
if(!GetSession()->PlayerLogout())
{
- // don't reset teleport semaphore while logging out, otherwise m_teleport_dest won't be used in Player::SaveToDB
- SetSemaphoreTeleport(false);
-
- UpdateZone(GetZoneId());
- }
-
- // new zone
- if(old_zone != GetZoneId())
- {
- // honorless target
- if(pvpInfo.inHostileArea)
- CastSpell(this, 2479, true);
+ WorldPacket data;
+ BuildTeleportAckMsg(&data, x, y, z, orientation);
+ GetSession()->SendPacket(&data);
}
}
else
@@ -1698,10 +1704,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// Check enter rights before map getting to avoid creating instance copy for player
// this check not dependent from map instance copy and same for all instance copies of selected map
if (!MapManager::Instance().CanPlayerEnter(mapid, this))
- {
- SetSemaphoreTeleport(false);
return false;
- }
// If the map is not created, assume it is possible to enter it.
// It will be created in the WorldPortAck.
@@ -1726,15 +1729,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// remove pet on map change
if (pet)
- {
- //leaving map -> delete pet right away (doing this later will cause problems)
- if(pet->isControlled() && !pet->isTemporarySummoned())
- m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber();
- else
- m_temporaryUnsummonedPetNumber = 0;
-
- RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
- }
+ UnsummonPetTemporaryIfAny();
// remove all dyn objects
RemoveAllDynObjects();
@@ -1791,13 +1786,11 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// if the player is saved before worldportack (at logout for example)
// this will be used instead of the current location in SaveToDB
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP);
+ RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING);
// move packet sent by client always after far teleport
- // SetPosition(final_x, final_y, final_z, final_o, true);
- SetDontMove(true);
-
// code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet
+ SetSemaphoreTeleportFar(true);
}
else
return false;
@@ -1812,7 +1805,7 @@ void Player::AddToWorld()
///- The player should only be added when logging in
Unit::AddToWorld();
- for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++)
+ for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
{
if(m_items[i])
m_items[i]->AddToWorld();
@@ -1827,12 +1820,10 @@ void Player::RemoveFromWorld()
///- Release charmed creatures, unsummon totems and remove pets/guardians
StopCastingCharm();
StopCastingBindSight();
- UnsummonAllTotems();
- RemoveMiniPet();
- RemoveGuardians();
+ sOutdoorPvPMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId);
}
- for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++)
+ for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
{
if(m_items[i])
m_items[i]->RemoveFromWorld();
@@ -1842,6 +1833,15 @@ void Player::RemoveFromWorld()
///- It will crash when updating the ObjectAccessor
///- The player should only be removed when logging out
Unit::RemoveFromWorld();
+
+ if(m_uint32Values)
+ {
+ if(WorldObject *viewpoint = GetViewpoint())
+ {
+ sLog.outCrash("Player %s has viewpoint %u %u when removed from world", GetName(), viewpoint->GetEntry(), viewpoint->GetTypeId());
+ SetViewpoint(viewpoint, false);
+ }
+ }
}
void Player::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker )
@@ -1862,7 +1862,7 @@ void Player::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attack
addRage = damage/rageconversion*2.5;
// Berserker Rage effect
- if(HasAura(18499,0))
+ if(HasAura(18499))
addRage *= 1.3;
}
@@ -1883,13 +1883,20 @@ void Player::RegenerateAll()
{
RegenerateHealth();
if (!isInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
+ {
Regenerate(POWER_RAGE);
+ if(getClass() == CLASS_DEATH_KNIGHT)
+ Regenerate(POWER_RUNIC_POWER);
+ }
}
Regenerate( POWER_ENERGY );
Regenerate( POWER_MANA );
+ if(getClass() == CLASS_DEATH_KNIGHT)
+ Regenerate( POWER_RUNE );
+
m_regenTimer = regenDelay;
}
@@ -1909,11 +1916,11 @@ void Player::Regenerate(Powers power)
if (recentCast)
{
// Trinity Updates Mana in intervals of 2s, which is correct
- addvalue = GetFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT) * ManaIncreaseRate * 2.00f;
+ addvalue = GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * 2.00f;
}
else
{
- addvalue = GetFloatValue(PLAYER_FIELD_MOD_MANA_REGEN) * ManaIncreaseRate * 2.00f;
+ addvalue = GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * 2.00f;
}
} break;
case POWER_RAGE: // Regenerate rage
@@ -1924,8 +1931,20 @@ void Player::Regenerate(Powers power)
case POWER_ENERGY: // Regenerate energy (rogue)
addvalue = 20;
break;
+ case POWER_RUNIC_POWER:
+ {
+ float RunicPowerDecreaseRate = sWorld.getRate(RATE_POWER_RUNICPOWER_LOSS);
+ addvalue = 30 * RunicPowerDecreaseRate; // 3 RunicPower by tick
+ } break;
+ case POWER_RUNE:
+ {
+ for(uint32 i = 0; i < MAX_RUNES; ++i)
+ if(uint8 cd = GetRuneCooldown(i)) // if we have cooldown, reduce it...
+ SetRuneCooldown(i, cd - 1); // ... by 2 sec (because update is every 2 sec)
+ } break;
case POWER_FOCUS:
case POWER_HAPPINESS:
+ case POWER_HEALTH:
break;
}
@@ -1933,13 +1952,13 @@ void Player::Regenerate(Powers power)
// Exist only for POWER_MANA, POWER_ENERGY, POWER_FOCUS auras
if(power != POWER_MANA)
{
- AuraList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
- for(AuraList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
- if ((*i)->GetModifier()->m_miscvalue == power)
- addvalue *= ((*i)->GetModifierValue() + 100) / 100.0f;
+ AuraEffectList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
+ for(AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
+ if ((*i)->GetMiscValue() == power)
+ addvalue *= ((*i)->GetAmount() + 100) / 100.0f;
}
- if (power != POWER_RAGE)
+ if (power != POWER_RAGE && power != POWER_RUNIC_POWER)
{
curValue += uint32(addvalue);
if (curValue > maxValue)
@@ -1975,9 +1994,9 @@ void Player::RegenerateHealth()
addvalue = OCTRegenHPPerSpirit()* HealthIncreaseRate;
if (!isInCombat())
{
- AuraList const& mModHealthRegenPct = GetAurasByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
- for(AuraList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
- addvalue *= (100.0f + (*i)->GetModifierValue()) / 100.0f;
+ AuraEffectList const& mModHealthRegenPct = GetAurasByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
+ for(AuraEffectList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
+ addvalue *= (100.0f + (*i)->GetAmount()) / 100.0f;
}
else if(HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT))
addvalue *= GetTotalAuraModifier(SPELL_AURA_MOD_REGEN_DURING_COMBAT) / 100.0f;
@@ -2005,6 +2024,88 @@ bool Player::CanInteractWithNPCs(bool alive) const
return true;
}
+Creature*
+Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask)
+{
+ // unit checks
+ if (!guid)
+ return NULL;
+
+ if(!IsInWorld())
+ return NULL;
+
+ // exist (we need look pets also for some interaction (quest/etc)
+ Creature *unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid);
+ if (!unit)
+ return NULL;
+
+ // player check
+ if(!CanInteractWithNPCs(!unit->isSpiritService()))
+ return NULL;
+
+ // appropriate npc type
+ if(npcflagmask && !unit->HasFlag( UNIT_NPC_FLAGS, npcflagmask ))
+ return NULL;
+
+ // alive or spirit healer
+ if(!unit->isAlive() && (!unit->isSpiritService() || isAlive() ))
+ return NULL;
+
+ // not allow interaction under control, but allow with own pets
+ if(unit->GetCharmerGUID())
+ return NULL;
+
+ // not enemy
+ if( unit->IsHostileTo(this))
+ return NULL;
+
+ // not unfriendly
+ if(FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(unit->getFaction()))
+ if(factionTemplate->faction)
+ if(FactionEntry const* faction = sFactionStore.LookupEntry(factionTemplate->faction))
+ if(faction->reputationListID >= 0 && GetReputationMgr().GetRank(faction) <= REP_UNFRIENDLY)
+ return NULL;
+
+ // not too far
+ if(!unit->IsWithinDistInMap(this,INTERACTION_DISTANCE))
+ return NULL;
+
+ return unit;
+}
+
+GameObject* Player::GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes type) const
+{
+ if(GameObject *go = GetMap()->GetGameObject(guid))
+ {
+ if(go->GetGoType() == type)
+ {
+ float maxdist;
+ switch(type)
+ {
+ // TODO: find out how the client calculates the maximal usage distance to spellless working
+ // gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number
+ case GAMEOBJECT_TYPE_GUILD_BANK:
+ case GAMEOBJECT_TYPE_MAILBOX:
+ maxdist = 10.0f;
+ break;
+ case GAMEOBJECT_TYPE_FISHINGHOLE:
+ maxdist = 20.0f+CONTACT_DISTANCE; // max spell range
+ break;
+ default:
+ maxdist = INTERACTION_DISTANCE;
+ break;
+ }
+
+ if (go->IsWithinDistInMap(this, maxdist))
+ return go;
+
+ sLog.outError("IsGameObjectOfTypeInRange: GameObject '%s' [GUID: %u] is too far away from player %s [GUID: %u] to be used by him (distance=%f, maximal 10 is allowed)", go->GetGOInfo()->name,
+ go->GetGUIDLow(), GetName(), GetGUIDLow(), go->GetDistance(this));
+ }
+ }
+ return NULL;
+}
+
bool Player::IsUnderWater() const
{
return IsInWater() &&
@@ -2037,21 +2138,39 @@ void Player::SetGameMaster(bool on)
setFaction(35);
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
- RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
+ if (Pet* pet = GetPet())
+ {
+ pet->setFaction(35);
+ pet->getHostilRefManager().setOnlineOfflineState(false);
+ }
+
+ RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
ResetContestedPvP();
getHostilRefManager().setOnlineOfflineState(false);
- CombatStop();
+ CombatStopWithPets();
+
+ SetPhaseMask(PHASEMASK_ANYWHERE,false); // see and visible in all phases
}
else
{
+ // restore phase
+ AuraEffectList const& phases = GetAurasByType(SPELL_AURA_PHASE);
+ SetPhaseMask(!phases.empty() ? phases.front()->GetMiscValue() : PHASEMASK_NORMAL,false);
+
m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON;
setFactionForRace(getRace());
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
+ if (Pet* pet = GetPet())
+ {
+ pet->setFaction(getFaction());
+ pet->getHostilRefManager().setOnlineOfflineState(true);
+ }
+
// restore FFA PvP Server state
if(sWorld.IsFFAPvPRealm())
- SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
+ SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
// restore FFA PvP area state, remove not allowed for GM mounts
UpdateArea(m_areaUpdateId);
@@ -2115,7 +2234,7 @@ void Player::UninviteFromGroup()
group->RemoveInvite(this);
- if(group->GetMembersCount() <= 1) // group has just 1 member => disband
+ if(group->GetMembersCount() <= 1) // group has just 1 member => disband
{
if(group->IsCreated())
{
@@ -2173,9 +2292,9 @@ void Player::GiveXP(uint32 xp, Unit* victim)
return;
// handle SPELL_AURA_MOD_XP_PCT auras
- Unit::AuraList const& ModXPPctAuras = GetAurasByType(SPELL_AURA_MOD_XP_PCT);
- for(Unit::AuraList::const_iterator i = ModXPPctAuras.begin();i != ModXPPctAuras.end(); ++i)
- xp = uint32(xp*(1.0f + (*i)->GetModifierValue() / 100.0f));
+ Unit::AuraEffectList const& ModXPPctAuras = GetAurasByType(SPELL_AURA_MOD_XP_PCT);
+ for(Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin();i != ModXPPctAuras.end(); ++i)
+ xp = uint32(xp*(1.0f + (*i)->GetAmount() / 100.0f));
// XP resting bonus for kill
uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0;
@@ -2223,13 +2342,15 @@ void Player::GiveLevel(uint32 level)
data << uint32(0);
data << uint32(0);
data << uint32(0);
+ data << uint32(0);
+ data << uint32(0);
// end for
for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) // Stats loop (0-4)
data << uint32(int32(info.stats[i]) - GetCreateStat(Stats(i)));
GetSession()->SendPacket(&data);
- SetUInt32Value(PLAYER_NEXT_LEVEL_XP, Trinity::XP::xp_to_level(level));
+ SetUInt32Value(PLAYER_NEXT_LEVEL_XP, objmgr.GetXPForLevel(level));
//update level, max level of skills
if(getLevel()!= level)
@@ -2246,6 +2367,7 @@ void Player::GiveLevel(uint32 level)
InitTalentForLevel();
InitTaxiNodesForLevel();
+ InitGlyphsForLevel();
UpdateAllStats();
@@ -2261,10 +2383,11 @@ void Player::GiveLevel(uint32 level)
SetPower(POWER_FOCUS, 0);
SetPower(POWER_HAPPINESS, 0);
- // give level to summoned pet
- Pet* pet = GetPet();
- if(pet && pet->getPetType()==SUMMON_PET)
- pet->GivePetLevel(level);
+ // update level to hunter/summon pet
+ if (Pet* pet = GetPet())
+ pet->SynchronizeLevelWithOwner();
+
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
}
void Player::InitTalentForLevel()
@@ -2282,7 +2405,8 @@ void Player::InitTalentForLevel()
}
else
{
- uint32 talentPointsForLevel = uint32((level-9)*sWorld.getRate(RATE_TALENT));
+ uint32 talentPointsForLevel = CalculateTalentsPoints();
+
// if used more that have then reset
if(m_usedTalentCount > talentPointsForLevel)
{
@@ -2309,7 +2433,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
objmgr.GetPlayerLevelInfo(getRace(),getClass(),getLevel(),&info);
SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) );
- SetUInt32Value(PLAYER_NEXT_LEVEL_XP, Trinity::XP::xp_to_level(getLevel()));
+ SetUInt32Value(PLAYER_NEXT_LEVEL_XP, objmgr.GetXPForLevel(getLevel()));
UpdateSkillsForLevel ();
@@ -2359,11 +2483,11 @@ void Player::InitStatsForLevel(bool reapplyMods)
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, 0.0f );
SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, 0.0f );
- SetUInt32Value(UNIT_FIELD_ATTACK_POWER, 0 );
- SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, 0 );
+ SetInt32Value(UNIT_FIELD_ATTACK_POWER, 0 );
+ SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, 0 );
SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER,0.0f);
- SetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, 0 );
- SetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS,0 );
+ SetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, 0 );
+ SetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS,0 );
SetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER,0.0f);
// Base crit values (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset
@@ -2398,9 +2522,12 @@ void Player::InitStatsForLevel(bool reapplyMods)
SetUInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE,0);
for(int i = 0; i < MAX_SPELL_SCHOOL; ++i)
{
- SetFloatValue(UNIT_FIELD_POWER_COST_MODIFIER+i,0.0f);
+ SetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i,0);
SetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+i,0.0f);
}
+ // Reset no reagent cost field
+ for(int i = 0; i < 3; i++)
+ SetUInt32Value(PLAYER_NO_REAGENT_COST_1 + i, 0);
// Init data for form but skip reapply item mods for form
InitDataForForm(reapplyMods);
@@ -2417,15 +2544,18 @@ void Player::InitStatsForLevel(bool reapplyMods)
RemoveFlag( UNIT_FIELD_FLAGS,
UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_ATTACKABLE_1 |
UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_SILENCED | UNIT_FLAG_PACIFIED |
- UNIT_FLAG_DISABLE_ROTATE | UNIT_FLAG_IN_COMBAT | UNIT_FLAG_DISARMED |
+ UNIT_FLAG_STUNNED | UNIT_FLAG_IN_COMBAT | UNIT_FLAG_DISARMED |
UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING | UNIT_FLAG_NOT_SELECTABLE |
UNIT_FLAG_SKINNABLE | UNIT_FLAG_MOUNT | UNIT_FLAG_TAXI_FLIGHT );
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE ); // must be set
+ SetFlag(UNIT_FIELD_FLAGS_2,UNIT_FLAG2_REGENERATE_POWER);// must be set
+
// cleanup player flags (will be re-applied if need at aura load), to avoid have ghost flag without ghost aura, for example.
- RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST | PLAYER_FLAGS_FFA_PVP);
+ RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST | PLAYER_ALLOW_ONLY_ABILITY);
- SetByteValue(UNIT_FIELD_BYTES_1, 2, 0x00); // one form stealth modified bytes
+ RemoveStandFlags(UNIT_STAND_FLAGS_ALL); // one form stealth modified bytes
+ RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP | UNIT_BYTE2_FLAG_SANCTUARY);
// restore if need some important flags
SetUInt32Value(PLAYER_FIELD_BYTES2, 0 ); // flags empty by default
@@ -2441,10 +2571,18 @@ void Player::InitStatsForLevel(bool reapplyMods)
SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE));
SetPower(POWER_FOCUS, 0);
SetPower(POWER_HAPPINESS, 0);
+ SetPower(POWER_RUNIC_POWER, 0);
+
+ // update level to hunter/summon pet
+ if (Pet* pet = GetPet())
+ pet->SynchronizeLevelWithOwner();
}
void Player::SendInitialSpells()
{
+ time_t curTime = time(NULL);
+ time_t infTime = curTime + MONTH/2;
+
uint16 spellCount = 0;
WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4)));
@@ -2477,12 +2615,15 @@ void Player::SendInitialSpells()
if(!sEntry)
continue;
+ // not send infinity cooldown
+ if(itr->second.end > infTime)
+ continue;
+
data << uint16(itr->first);
time_t cooldown = 0;
- time_t curTime = time(NULL);
if(itr->second.end > curTime)
- cooldown = (itr->second.end-curTime)*1000;
+ cooldown = (itr->second.end-curTime)*IN_MILISECONDS;
data << uint16(itr->second.itemid); // cast item id
data << uint16(sEntry->Category); // spell category
@@ -2573,13 +2714,13 @@ void Player::AddNewMailDeliverTime(time_t deliver_time)
}
}
-bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading, uint16 slot_id, bool disabled)
+bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
if (!spellInfo)
{
// do character spell book cleanup (all characters)
- if(loading && !learning) // spell load case
+ if(!IsInWorld() && !learning) // spell load case
{
sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.",spell_id);
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'",spell_id);
@@ -2593,7 +2734,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
if(!SpellMgr::IsSpellValid(spellInfo,this,false))
{
// do character spell book cleanup (all characters)
- if(loading && !learning) // spell load case
+ 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);
@@ -2606,29 +2747,80 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
+ bool dependent_set = false;
bool disabled_case = false;
bool superceded_old = false;
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
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(!SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
+ {
+ if(uint32 next = spellmgr.GetNextSpellInChain(spell_id))
+ {
+ if(HasSpell(next))
+ {
+ // high rank already known so this must !active
+ active = false;
+ next_active_spell_id = next;
+ }
+ }
+ }
+
+ // not do anything if already known in expected state
+ if(itr->second->state != PLAYERSPELL_REMOVED && itr->second->active == active &&
+ itr->second->dependent == dependent && itr->second->disabled == disabled)
+ {
+ if(!IsInWorld() && !learning) // explicitly load from DB and then exist in it already and set correctly
+ itr->second->state = PLAYERSPELL_UNCHANGED;
+
+ return false;
+ }
+
+ // dependent spell known as not dependent, overwrite state
+ if (itr->second->state != PLAYERSPELL_REMOVED && !itr->second->dependent && dependent)
+ {
+ itr->second->dependent = dependent;
+ if (itr->second->state != PLAYERSPELL_NEW)
+ itr->second->state = PLAYERSPELL_CHANGED;
+ dependent_set = true;
+ }
+
// update active state for known spell
if(itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled)
{
itr->second->active = active;
- // loading && !learning == explicitly load from DB and then exist in it already and set correctly
- if(loading && !learning)
+ if(!IsInWorld() && !learning && !dependent_set) // explicitly load from DB and then exist in it already and set correctly
itr->second->state = PLAYERSPELL_UNCHANGED;
else if(itr->second->state != PLAYERSPELL_NEW)
itr->second->state = PLAYERSPELL_CHANGED;
- if(!active)
+ if(active)
{
- WorldPacket data(SMSG_REMOVED_SPELL, 4);
- data << uint16(spell_id);
- GetSession()->SendPacket(&data);
+ if (IsPassiveSpell(spell_id) && IsNeedCastPassiveSpellAtLearn(spellInfo))
+ CastSpell (this,spell_id,true);
+ }
+ else if(IsInWorld())
+ {
+ if(next_active_spell_id)
+ {
+ // update spell ranks in spellbook and action bar
+ WorldPacket data(SMSG_SUPERCEDED_SPELL, (4));
+ data << uint16(spell_id);
+ data << uint16(next_active_spell_id);
+ GetSession()->SendPacket( &data );
+ }
+ else
+ {
+ WorldPacket data(SMSG_REMOVED_SPELL, 4);
+ data << uint16(spell_id);
+ GetSession()->SendPacket(&data);
+ }
}
+
return active; // learn (show in spell book if active now)
}
@@ -2657,7 +2849,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
default: // known not saved yet spell (new or modified)
{
// can be in case spell loading but learned at some previous spell loading
- if(loading && !learning)
+ if(!IsInWorld() && !learning && !dependent_set)
itr->second->state = PLAYERSPELL_UNCHANGED;
return false;
@@ -2672,17 +2864,13 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
{
if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id ))
{
- for(int i=0; i <5; ++i)
+ for(int i=0; i < MAX_TALENT_RANK; ++i)
{
// skip learning spell and no rank spell case
uint32 rankSpellId = talentInfo->RankID[i];
if(!rankSpellId || rankSpellId==spell_id)
continue;
- // skip unknown ranks
- if(!HasSpell(rankSpellId))
- continue;
-
removeSpell(rankSpellId);
}
}
@@ -2690,52 +2878,54 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
// non talent spell: learn low ranks (recursive call)
else if(uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id))
{
- if(loading) // at spells loading, no output, but allow save
- addSpell(prev_spell,active,true,loading,SPELL_WITHOUT_SLOT_ID,disabled);
+ if(!IsInWorld() || disabled) // at spells loading, no output, but allow save
+ addSpell(prev_spell,active,true,true,disabled);
else // at normal learning
- learnSpell(prev_spell);
+ learnSpell(prev_spell,true);
}
PlayerSpell *newspell = new PlayerSpell;
- newspell->active = active;
- newspell->state = state;
- newspell->disabled = disabled;
+ newspell->state = state;
+ newspell->active = active;
+ newspell->dependent = dependent;
+ newspell->disabled = disabled;
// replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible
if(newspell->active && !newspell->disabled && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
{
- for( PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr )
+ for( PlayerSpellMap::iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2 )
{
- if(itr->second->state == PLAYERSPELL_REMOVED) continue;
- SpellEntry const *i_spellInfo = sSpellStore.LookupEntry(itr->first);
+ if(itr2->second->state == PLAYERSPELL_REMOVED) continue;
+ SpellEntry const *i_spellInfo = sSpellStore.LookupEntry(itr2->first);
if(!i_spellInfo) continue;
- if( spellmgr.IsRankSpellDueToSpell(spellInfo,itr->first) )
+ if( spellmgr.IsRankSpellDueToSpell(spellInfo,itr2->first) )
{
- if(itr->second->active)
+ if(itr2->second->active)
{
- if(spellmgr.IsHighRankOfSpell(spell_id,itr->first))
+ if(spellmgr.IsHighRankOfSpell(spell_id,itr2->first))
{
- if(!loading) // not send spell (re-/over-)learn packets at loading
+ if(IsInWorld()) // not send spell (re-/over-)learn packets at loading
{
WorldPacket data(SMSG_SUPERCEDED_SPELL, (4));
- data << uint16(itr->first);
+ data << uint16(itr2->first);
data << uint16(spell_id);
GetSession()->SendPacket( &data );
}
// mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new)
- itr->second->active = false;
- itr->second->state = PLAYERSPELL_CHANGED;
+ itr2->second->active = false;
+ if(itr2->second->state != PLAYERSPELL_NEW)
+ itr2->second->state = PLAYERSPELL_CHANGED;
superceded_old = true; // new spell replace old in action bars and spell book.
}
- else if(spellmgr.IsHighRankOfSpell(itr->first,spell_id))
+ else if(spellmgr.IsHighRankOfSpell(itr2->first,spell_id))
{
- if(!loading) // not send spell (re-/over-)learn packets at loading
+ if(IsInWorld()) // not send spell (re-/over-)learn packets at loading
{
WorldPacket data(SMSG_SUPERCEDED_SPELL, (4));
data << uint16(spell_id);
- data << uint16(itr->first);
+ data << uint16(itr2->first);
GetSession()->SendPacket( &data );
}
@@ -2749,23 +2939,6 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
}
}
- uint16 tmpslot=slot_id;
-
- if (tmpslot == SPELL_WITHOUT_SLOT_ID)
- {
- uint16 maxid = 0;
- PlayerSpellMap::iterator itr;
- for (itr = m_spells.begin(); itr != m_spells.end(); ++itr)
- {
- if(itr->second->state == PLAYERSPELL_REMOVED)
- continue;
- if (itr->second->slotId > maxid)
- maxid = itr->second->slotId;
- }
- tmpslot = maxid + 1;
- }
-
- newspell->slotId = tmpslot;
m_spells[spell_id] = newspell;
// return false if spell disabled
@@ -2785,23 +2958,8 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
// also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks
else if (IsPassiveSpell(spell_id))
{
- // if spell doesn't require a stance or the player is in the required stance
- if( ( !spellInfo->Stances &&
- spell_id != 5420 && spell_id != 5419 && spell_id != 7376 &&
- spell_id != 7381 && spell_id != 21156 && spell_id != 21009 &&
- spell_id != 21178 && spell_id != 33948 && spell_id != 40121 ) ||
- m_form != 0 && (spellInfo->Stances & (1<<(m_form-1))) ||
- (spell_id == 5420 && m_form == FORM_TREE) ||
- (spell_id == 5419 && m_form == FORM_TRAVEL) ||
- (spell_id == 7376 && m_form == FORM_DEFENSIVESTANCE) ||
- (spell_id == 7381 && m_form == FORM_BERSERKERSTANCE) ||
- (spell_id == 21156 && m_form == FORM_BATTLESTANCE)||
- (spell_id == 21178 && (m_form == FORM_BEAR || m_form == FORM_DIREBEAR) ) ||
- (spell_id == 33948 && m_form == FORM_FLIGHT) ||
- (spell_id == 40121 && m_form == FORM_FLIGHT_EPIC) )
- //Check CasterAuraStates
- if (!spellInfo->CasterAuraState || HasAuraState(AuraState(spellInfo->CasterAuraState)))
- CastSpell(this, spell_id, true);
+ if(IsNeedCastPassiveSpellAtLearn(spellInfo))
+ CastSpell(this, spell_id, true);
}
else if( IsSpellHaveEffect(spellInfo,SPELL_EFFECT_SKILL_STEP) )
{
@@ -2824,6 +2982,9 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
SpellLearnSkillNode const* spellLearnSkill = spellmgr.GetSpellLearnSkill(spell_id);
+ SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id);
+ SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id);
+
if(spellLearnSkill)
{
uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill);
@@ -2842,9 +3003,6 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
else
{
// not ranked skills
- SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id);
- SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id);
-
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
{
SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId);
@@ -2855,10 +3013,8 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
continue;
if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ||
- // poison special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
- pSkill->id==SKILL_POISONS && _spell_idx->second->max_value==0 ||
- // lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
- pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 )
+ // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
+ (pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0 )
{
switch(GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0))
{
@@ -2882,41 +3038,81 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool loading,
SpellLearnSpellMap::const_iterator spell_begin = spellmgr.GetBeginSpellLearnSpell(spell_id);
SpellLearnSpellMap::const_iterator spell_end = spellmgr.GetEndSpellLearnSpell(spell_id);
- for(SpellLearnSpellMap::const_iterator itr = spell_begin; itr != spell_end; ++itr)
+ for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2)
{
- if(!itr->second.autoLearned)
+ if(!itr2->second.autoLearned)
{
- if(loading) // at spells loading, no output, but allow save
- addSpell(itr->second.spell,true,true,loading);
+ if(!IsInWorld() || !itr2->second.active) // at spells loading, no output, but allow save
+ addSpell(itr2->second.spell,itr2->second.active,true,true,false);
else // at normal learning
- learnSpell(itr->second.spell);
+ learnSpell(itr2->second.spell,true);
}
}
+ if(!GetSession()->PlayerLoading())
+ {
+ // not ranked skills
+ for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
+ {
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE,_spell_idx->second->skillId);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS,_spell_idx->second->skillId);
+ }
+
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL,spell_id);
+ }
+
// return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell
return active && !disabled && !superceded_old;
}
-void Player::learnSpell(uint32 spell_id)
+bool Player::IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const
+{
+ bool need_cast = false;
+
+ switch(spellInfo->Id)
+ {
+ // some spells not have stance data expacted cast at form change or present
+ case 5420: need_cast = (m_form == FORM_TREE); break;
+ case 5419: need_cast = (m_form == FORM_TRAVEL); break;
+ case 7376: need_cast = (m_form == FORM_DEFENSIVESTANCE); break;
+ case 7381: need_cast = (m_form == FORM_BERSERKERSTANCE); break;
+ case 21156: need_cast = (m_form == FORM_BATTLESTANCE); break;
+ case 21178: need_cast = (m_form == FORM_BEAR || m_form == FORM_DIREBEAR); break;
+ case 33948: need_cast = (m_form == FORM_FLIGHT); break;
+ case 34764: need_cast = (m_form == FORM_FLIGHT); break;
+ case 40121: need_cast = (m_form == FORM_FLIGHT_EPIC); break;
+ case 40122: need_cast = (m_form == FORM_FLIGHT_EPIC); break;
+ // another spells have proper stance data
+ default: need_cast = !spellInfo->Stances || m_form != 0 && (spellInfo->Stances & (1<<(m_form-1))); break;
+ }
+
+ //Check CasterAuraStates
+ return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraState(spellInfo->CasterAuraState)));
+}
+
+void Player::learnSpell(uint32 spell_id, bool dependent)
{
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
bool disabled = (itr != m_spells.end()) ? itr->second->disabled : false;
bool active = disabled ? itr->second->active : true;
- bool learning = addSpell(spell_id,active);
+ bool learning = addSpell(spell_id,active,true,dependent,false);
// learn all disabled higher ranks (recursive)
- SpellChainNode const* node = spellmgr.GetSpellChainNode(spell_id);
- if (node)
+ if(disabled)
{
- PlayerSpellMap::iterator iter = m_spells.find(node->next);
- if (disabled && iter != m_spells.end() && iter->second->disabled )
- learnSpell(node->next);
+ SpellChainNode const* node = spellmgr.GetSpellChainNode(spell_id);
+ if(node)
+ {
+ PlayerSpellMap::iterator iter = m_spells.find(node->next);
+ if (iter != m_spells.end() && iter->second->disabled )
+ learnSpell(node->next,false);
+ }
}
- // prevent duplicated entires in spell book
- if(!learning)
+ // prevent duplicated entires in spell book, also not send if not in world (loading)
+ if(!learning || !IsInWorld ())
return;
WorldPacket data(SMSG_LEARNED_SPELL, 4);
@@ -2924,7 +3120,7 @@ void Player::learnSpell(uint32 spell_id)
GetSession()->SendPacket(&data);
}
-void Player::removeSpell(uint32 spell_id, bool disabled)
+void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_for_low_rank)
{
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
if (itr == m_spells.end())
@@ -2946,10 +3142,8 @@ void Player::removeSpell(uint32 spell_id, bool disabled)
for (uint32 i=reqMap.count(spell_id);i>0;i--,itr2++)
removeSpell(itr2->second,disabled);
- // removing
- WorldPacket data(SMSG_REMOVED_SPELL, 4);
- data << uint16(spell_id);
- GetSession()->SendPacket(&data);
+ bool cur_active = itr->second->active;
+ bool cur_dependent = itr->second->dependent;
if (disabled)
{
@@ -3042,10 +3236,8 @@ void Player::removeSpell(uint32 spell_id, bool disabled)
continue;
if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ||
- // poison special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
- pSkill->id==SKILL_POISONS && _spell_idx->second->max_value==0 ||
- // lockpicking special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
- pSkill->id==SKILL_LOCKPICKING && _spell_idx->second->max_value==0 )
+ // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
+ (pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0 )
{
// not reset skills for professions and racial abilities
if( (pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) &&
@@ -3063,6 +3255,82 @@ void Player::removeSpell(uint32 spell_id, bool disabled)
for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2)
removeSpell(itr2->second.spell, disabled);
+
+ // activate lesser rank in spellbook/action bar, and cast it if need
+ bool prev_activate = false;
+
+ if(uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id))
+ {
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
+
+ // if talent then lesser rank also talent and need learn
+ if(talentCosts)
+ {
+ //learnSpell (prev_id,false);
+ }
+ // if ranked non-stackable spell: need activate lesser rank and update dendence state
+ else if(cur_active && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
+ {
+ // need manually update dependence state (learn spell ignore like attempts)
+ PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
+ if (prev_itr != m_spells.end())
+ {
+ if(prev_itr->second->dependent != cur_dependent)
+ {
+ prev_itr->second->dependent = cur_dependent;
+ if(prev_itr->second->state != PLAYERSPELL_NEW)
+ prev_itr->second->state = PLAYERSPELL_CHANGED;
+ }
+
+ // now re-learn if need re-activate
+ if(cur_active && !prev_itr->second->active)
+ {
+ if(addSpell(prev_id,true,false,prev_itr->second->dependent,prev_itr->second->disabled))
+ {
+ if(update_action_bar_for_low_rank)
+ {
+ // downgrade spell ranks in spellbook and action bar
+ WorldPacket data(SMSG_SUPERCEDED_SPELL, (4));
+ data << uint16(spell_id);
+ data << uint16(prev_id);
+ GetSession()->SendPacket( &data );
+ prev_activate = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // remove from spell book if not replaced by lesser rank
+ if(!prev_activate)
+ {
+ WorldPacket data(SMSG_REMOVED_SPELL, 4);
+ data << uint16(spell_id);
+ GetSession()->SendPacket(&data);
+ }
+}
+
+
+void Player::RemoveSpellCooldown( uint32 spell_id, bool update /* = false */ )
+{
+ m_spellCooldowns.erase(spell_id);
+
+ if(update)
+ {
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
+ data << uint32(spell_id);
+ data << uint64(GetGUID());
+ SendDirectMessage(&data);
+ }
+}
+
+void Player::RemoveCategoryCooldown( uint32 cat )
+{
+ SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
+ if(i_scstore != sSpellCategoryStore.end())
+ for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
+ RemoveSpellCooldown(*i_scset, true);
}
void Player::RemoveArenaSpellCooldowns()
@@ -3077,13 +3345,13 @@ void Player::RemoveArenaSpellCooldowns()
SpellEntry const * entry = sSpellStore.LookupEntry(itr->first);
// check if spellentry is present and if the cooldown is less than 15 mins
if( entry &&
- entry->RecoveryTime <= 15 * MINUTE * 1000 &&
- entry->CategoryRecoveryTime <= 15 * MINUTE * 1000 )
+ entry->RecoveryTime <= 15 * MINUTE * IN_MILISECONDS &&
+ entry->CategoryRecoveryTime <= 15 * MINUTE * IN_MILISECONDS )
{
// notify player
WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
data << uint32(itr->first);
- data << GetGUID();
+ data << uint64(GetGUID());
GetSession()->SendPacket(&data);
// remove cooldown
m_spellCooldowns.erase(itr);
@@ -3108,7 +3376,7 @@ void Player::RemoveAllSpellCooldown()
void Player::_LoadSpellCooldowns(QueryResult *result)
{
- m_spellCooldowns.clear();
+ // some cooldowns can be already set at aura loading...
//QueryResult *result = CharacterDatabase.PQuery("SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'",GetGUIDLow());
@@ -3149,17 +3417,20 @@ void Player::_SaveSpellCooldowns()
CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow());
time_t curTime = time(NULL);
+ time_t infTime = curTime + MONTH/2;
// remove outdated and save active
for(SpellCooldowns::iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end();)
{
if(itr->second.end <= curTime)
m_spellCooldowns.erase(itr++);
- else
+ else if(itr->second.end <= infTime) // not save locked cooldowns, it will be reset or set at reload
{
CharacterDatabase.PExecute("INSERT INTO character_spell_cooldown (guid,spell,item,time) VALUES ('%u', '%u', '%u', '" I64FMTD "')", GetGUIDLow(), itr->first, itr->second.itemid, uint64(itr->second.end));
++itr;
}
+ else
+ ++itr;
}
}
@@ -3205,8 +3476,7 @@ bool Player::resetTalents(bool no_cost)
CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_TALENTS), GetGUIDLow());
}
- uint32 level = getLevel();
- uint32 talentPointsForLevel = level < 10 ? 0 : uint32((level-9)*sWorld.getRate(RATE_TALENT));
+ uint32 talentPointsForLevel = CalculateTalentsPoints();
if (m_usedTalentCount == 0)
{
@@ -3244,7 +3514,7 @@ bool Player::resetTalents(bool no_cost)
if( (getClassMask() & talentTabInfo->ClassMask) == 0 )
continue;
- for (int j = 0; j < 5; j++)
+ for (int j = 0; j < MAX_TALENT_RANK; j++)
{
for(PlayerSpellMap::iterator itr = GetSpellMap().begin(); itr != GetSpellMap().end();)
{
@@ -3275,6 +3545,8 @@ bool Player::resetTalents(bool no_cost)
if(!no_cost)
{
ModifyMoney(-(int32)cost);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS, cost);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS, 1);
m_resetTalentsCost = cost;
m_resetTalentsTime = time(NULL);
@@ -3283,19 +3555,14 @@ bool Player::resetTalents(bool no_cost)
//FIXME: remove pet before or after unlearn spells? for now after unlearn to allow removing of talent related, pet affecting auras
RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
- return true;
-}
-
-bool Player::_removeSpell(uint16 spell_id)
-{
- PlayerSpellMap::iterator itr = m_spells.find(spell_id);
- if (itr != m_spells.end())
+ if(m_canTitanGrip)
{
- delete itr->second;
- m_spells.erase(itr);
- return true;
+ m_canTitanGrip = false;
+ if(sWorld.getConfig(CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET))
+ AutoUnequipOffhandIfNeed();
}
- return false;
+
+ return true;
}
Mail* Player::GetMail(uint32 id)
@@ -3343,50 +3610,46 @@ void Player::InitVisibleBits()
{
updateVisualBits.SetCount(PLAYER_END);
- // TODO: really implement OWNER_ONLY and GROUP_ONLY. Flags can be found in UpdateFields.h
-
updateVisualBits.SetBit(OBJECT_FIELD_GUID);
updateVisualBits.SetBit(OBJECT_FIELD_TYPE);
+ updateVisualBits.SetBit(OBJECT_FIELD_ENTRY);
updateVisualBits.SetBit(OBJECT_FIELD_SCALE_X);
-
- updateVisualBits.SetBit(UNIT_FIELD_CHARM);
- updateVisualBits.SetBit(UNIT_FIELD_CHARM+1);
-
- updateVisualBits.SetBit(UNIT_FIELD_SUMMON);
- updateVisualBits.SetBit(UNIT_FIELD_SUMMON+1);
-
- updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY);
- updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY+1);
-
- updateVisualBits.SetBit(UNIT_FIELD_TARGET);
- updateVisualBits.SetBit(UNIT_FIELD_TARGET+1);
-
- updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT);
- updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT+1);
-
+ updateVisualBits.SetBit(UNIT_FIELD_CHARM + 0);
+ updateVisualBits.SetBit(UNIT_FIELD_CHARM + 1);
+ updateVisualBits.SetBit(UNIT_FIELD_SUMMON + 0);
+ updateVisualBits.SetBit(UNIT_FIELD_SUMMON + 1);
+ updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY + 0);
+ updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY + 1);
+ updateVisualBits.SetBit(UNIT_FIELD_TARGET + 0);
+ updateVisualBits.SetBit(UNIT_FIELD_TARGET + 1);
+ updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT + 0);
+ updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT + 1);
+ updateVisualBits.SetBit(UNIT_FIELD_BYTES_0);
updateVisualBits.SetBit(UNIT_FIELD_HEALTH);
updateVisualBits.SetBit(UNIT_FIELD_POWER1);
updateVisualBits.SetBit(UNIT_FIELD_POWER2);
updateVisualBits.SetBit(UNIT_FIELD_POWER3);
updateVisualBits.SetBit(UNIT_FIELD_POWER4);
updateVisualBits.SetBit(UNIT_FIELD_POWER5);
-
+ updateVisualBits.SetBit(UNIT_FIELD_POWER6);
+ updateVisualBits.SetBit(UNIT_FIELD_POWER7);
updateVisualBits.SetBit(UNIT_FIELD_MAXHEALTH);
updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER1);
updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER2);
updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER3);
updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER4);
updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER5);
-
+ updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER6);
+ updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER7);
updateVisualBits.SetBit(UNIT_FIELD_LEVEL);
updateVisualBits.SetBit(UNIT_FIELD_FACTIONTEMPLATE);
- updateVisualBits.SetBit(UNIT_FIELD_BYTES_0);
+ updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID + 0);
+ updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID + 1);
+ updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID + 2);
updateVisualBits.SetBit(UNIT_FIELD_FLAGS);
updateVisualBits.SetBit(UNIT_FIELD_FLAGS_2);
- for(uint16 i = UNIT_FIELD_AURA; i < UNIT_FIELD_AURASTATE; ++i)
- updateVisualBits.SetBit(i);
updateVisualBits.SetBit(UNIT_FIELD_AURASTATE);
- updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME);
+ updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME + 0);
updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME + 1);
updateVisualBits.SetBit(UNIT_FIELD_BOUNDINGRADIUS);
updateVisualBits.SetBit(UNIT_FIELD_COMBATREACH);
@@ -3399,10 +3662,12 @@ void Player::InitVisibleBits()
updateVisualBits.SetBit(UNIT_DYNAMIC_FLAGS);
updateVisualBits.SetBit(UNIT_CHANNEL_SPELL);
updateVisualBits.SetBit(UNIT_MOD_CAST_SPEED);
+ updateVisualBits.SetBit(UNIT_FIELD_BASE_MANA);
updateVisualBits.SetBit(UNIT_FIELD_BYTES_2);
+ updateVisualBits.SetBit(UNIT_FIELD_HOVERHEIGHT);
- updateVisualBits.SetBit(PLAYER_DUEL_ARBITER);
- updateVisualBits.SetBit(PLAYER_DUEL_ARBITER+1);
+ updateVisualBits.SetBit(PLAYER_DUEL_ARBITER + 0);
+ updateVisualBits.SetBit(PLAYER_DUEL_ARBITER + 1);
updateVisualBits.SetBit(PLAYER_FLAGS);
updateVisualBits.SetBit(PLAYER_GUILDID);
updateVisualBits.SetBit(PLAYER_GUILDRANK);
@@ -3413,29 +3678,29 @@ void Player::InitVisibleBits()
updateVisualBits.SetBit(PLAYER_GUILD_TIMESTAMP);
// PLAYER_QUEST_LOG_x also visible bit on official (but only on party/raid)...
- for(uint16 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_2; i+=4)
+ for(uint16 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_2; i += 4)
updateVisualBits.SetBit(i);
- //Players visible items are not inventory stuff
- //431) = 884 (0x374) = main weapon
- for(uint16 i = 0; i < EQUIPMENT_SLOT_END; i++)
+ // Players visible items are not inventory stuff
+ for(uint16 i = 0; i < EQUIPMENT_SLOT_END; ++i)
{
- // item creator
- updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + (i*MAX_VISIBLE_ITEM_OFFSET) + 0);
- updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + (i*MAX_VISIBLE_ITEM_OFFSET) + 1);
+ uint32 offset = i * MAX_VISIBLE_ITEM_OFFSET;
- uint16 visual_base = PLAYER_VISIBLE_ITEM_1_0 + (i*MAX_VISIBLE_ITEM_OFFSET);
+ // item creator
+ updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + 0 + offset);
+ updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + 1 + offset);
// item entry
- updateVisualBits.SetBit(visual_base + 0);
+ updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_0 + 0 + offset);
- // item enchantment IDs
- for(uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j)
- updateVisualBits.SetBit(visual_base + 1 + j);
+ // item enchantments
+ for(uint8 j = 0; j < MAX_ENCHANTMENT_SLOT; ++j)
+ updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_0 + 1 + j + offset);
// random properties
- updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 0 + (i*MAX_VISIBLE_ITEM_OFFSET));
- updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 1 + (i*MAX_VISIBLE_ITEM_OFFSET));
+ updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + offset);
+ updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_SEED + offset);
+ updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PAD + offset);
}
updateVisualBits.SetBit(PLAYER_CHOSEN_TITLE);
@@ -3453,7 +3718,6 @@ void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target )
if(target == this)
{
-
for(int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
{
if(m_items[i] == NULL)
@@ -3461,7 +3725,7 @@ void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target )
m_items[i]->BuildCreateUpdateBlockForPlayer( data, target );
}
- for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
+ for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
if(m_items[i] == NULL)
continue;
@@ -3494,7 +3758,7 @@ void Player::DestroyForPlayer( Player *target ) const
m_items[i]->DestroyForPlayer( target );
}
- for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
+ for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
if(m_items[i] == NULL)
continue;
@@ -3506,8 +3770,16 @@ void Player::DestroyForPlayer( Player *target ) const
bool Player::HasSpell(uint32 spell) const
{
- PlayerSpellMap::const_iterator itr = m_spells.find((uint16)spell);
- return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled);
+ PlayerSpellMap::const_iterator itr = m_spells.find(spell);
+ return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED &&
+ !itr->second->disabled);
+}
+
+bool Player::HasActiveSpell(uint32 spell) const
+{
+ PlayerSpellMap::const_iterator itr = m_spells.find(spell);
+ return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED &&
+ itr->second->active && !itr->second->disabled);
}
TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell) const
@@ -3515,22 +3787,22 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell
if (!trainer_spell)
return TRAINER_SPELL_RED;
- if (!trainer_spell->spell)
+ if (!trainer_spell->learnedSpell)
return TRAINER_SPELL_RED;
// known spell
- if(HasSpell(trainer_spell->spell))
+ if(HasSpell(trainer_spell->learnedSpell))
return TRAINER_SPELL_GRAY;
// check race/class requirement
- if(!IsSpellFitByClassAndRace(trainer_spell->spell))
+ if(!IsSpellFitByClassAndRace(trainer_spell->learnedSpell))
return TRAINER_SPELL_RED;
// check level requirement
- if(getLevel() < trainer_spell->reqlevel)
+ if(getLevel() < trainer_spell->reqLevel)
return TRAINER_SPELL_RED;
- if(SpellChainNode const* spell_chain = spellmgr.GetSpellChainNode(trainer_spell->spell))
+ if(SpellChainNode const* spell_chain = spellmgr.GetSpellChainNode(trainer_spell->learnedSpell))
{
// check prev.rank requirement
if(spell_chain->prev && !HasSpell(spell_chain->prev))
@@ -3545,11 +3817,11 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell
}
// check skill requirement
- if(trainer_spell->reqskill && GetBaseSkillValue(trainer_spell->reqskill) < trainer_spell->reqskillvalue)
+ if(trainer_spell->reqSkill && GetBaseSkillValue(trainer_spell->reqSkill) < trainer_spell->reqSkillValue)
return TRAINER_SPELL_RED;
// exist, already checked at loading
- SpellEntry const* spell = sSpellStore.LookupEntry(trainer_spell->spell);
+ SpellEntry const* spell = sSpellStore.LookupEntry(trainer_spell->learnedSpell);
// secondary prof. or not prof. spell
uint32 skill = spell->EffectMiscValue[1];
@@ -3559,7 +3831,7 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell
// check primary prof. limit
if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell->Id) && GetFreePrimaryProffesionPoints() == 0)
- return TRAINER_SPELL_RED;
+ return TRAINER_SPELL_GREEN_DISABLED;
return TRAINER_SPELL_GREEN;
}
@@ -3582,27 +3854,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
}
// remove from arena teams
- uint32 at_id = GetArenaTeamIdFromDB(playerguid,ARENA_TEAM_2v2);
- if(at_id != 0)
- {
- ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
- if(at)
- at->DelMember(playerguid);
- }
- at_id = GetArenaTeamIdFromDB(playerguid,ARENA_TEAM_3v3);
- if(at_id != 0)
- {
- ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
- if(at)
- at->DelMember(playerguid);
- }
- at_id = GetArenaTeamIdFromDB(playerguid,ARENA_TEAM_5v5);
- if(at_id != 0)
- {
- ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
- if(at)
- at->DelMember(playerguid);
- }
+ LeaveAllArenaTeams(playerguid);
// the player was uninvited already on logout so just remove from group
QueryResult *resultGroup = CharacterDatabase.PQuery("SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", guid);
@@ -3643,15 +3895,16 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
MailItemsInfo mi;
if(has_items)
{
- QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", mail_id);
+ // data needs to be at first place for Item::LoadFromDB
+ QueryResult *resultItems = CharacterDatabase.PQuery("SELECT data,item_guid,item_template FROM mail_items JOIN item_instance ON item_guid = guid WHERE mail_id='%u'", mail_id);
if(resultItems)
{
do
{
Field *fields2 = resultItems->Fetch();
- uint32 item_guidlow = fields2[0].GetUInt32();
- uint32 item_template = fields2[1].GetUInt32();
+ uint32 item_guidlow = fields2[1].GetUInt32();
+ uint32 item_template = fields2[2].GetUInt32();
ItemPrototype const* itemProto = objmgr.GetItemPrototype(item_template);
if(!itemProto)
@@ -3661,7 +3914,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
}
Item *pItem = NewItemOrBag(itemProto);
- if(!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)))
+ if(!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER),resultItems))
{
pItem->FSetState(ITEM_REMOVED);
pItem->SaveToDB(); // it also deletes item object !
@@ -3724,6 +3977,8 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE receiver = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u'",guid);
+ CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE guid = '%u'",guid);
+ CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE guid = '%u'",guid);
CharacterDatabase.CommitTransaction();
//LoginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID);
@@ -3754,6 +4009,10 @@ void Player::SetMovement(PlayerMovementType pType)
*/
void Player::BuildPlayerRepop()
{
+ WorldPacket data(SMSG_PRE_RESURRECT, GetPackGUID().size());
+ data.append(GetPackGUID());
+ GetSession()->SendPacket(&data);
+
if(getRace() == RACE_NIGHTELF)
CastSpell(this, 20584, true); // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
CastSpell(this, 8326, true); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
@@ -3798,7 +4057,8 @@ void Player::BuildPlayerRepop()
SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, (float)1.0); //see radius of death player?
- SetByteValue(UNIT_FIELD_BYTES_1, 3, PLAYER_STATE_FLAG_ALWAYS_STAND);
+ // set and clear other
+ SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND);
}
void Player::SendDelayResponse(const uint32 ml_seconds)
@@ -3843,13 +4103,15 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
SetPower(POWER_ENERGY, uint32(GetMaxPower(POWER_ENERGY)*restore_percent));
}
+ // trigger update zone for alive state zone updates
+ uint32 newzone, newarea;
+ GetZoneAndAreaId(newzone,newarea);
+ UpdateZone(newzone,newarea);
+
// update visibility
//ObjectAccessor::UpdateVisibilityForPlayer(this);
SetToNotify();
- // some items limited to specific map
- DestroyZoneLimitedItem( true, GetZoneId());
-
if(!applySickness)
return;
@@ -3869,13 +4131,9 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
{
int32 delta = (int32(getLevel()) - startLevel + 1)*MINUTE;
- for(int i =0; i < 3; ++i)
+ if(Aura* Aur = GetAura(SPELL_ID_PASSIVE_RESURRECTION_SICKNESS, GetGUID()))
{
- if(Aura* Aur = GetAura(SPELL_ID_PASSIVE_RESURRECTION_SICKNESS,i))
- {
- Aur->SetAuraDuration(delta*1000);
- Aur->UpdateAuraDuration();
- }
+ Aur->SetAuraDuration(delta*IN_MILISECONDS);
}
}
}
@@ -3894,7 +4152,7 @@ void Player::KillPlayer()
ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(GetMapId())->Instanceable());
// 6 minutes until repop at graveyard
- m_deathTimer = 6*MINUTE*1000;
+ m_deathTimer = 6*MINUTE*IN_MILISECONDS;
UpdateCorpseReclaimDelay(); // dependent at use SetDeathPvP() call before kill
SendCorpseReclaimDelay();
@@ -3915,8 +4173,7 @@ void Player::CreateCorpse()
Corpse *corpse = new Corpse( (m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) ? CORPSE_RESURRECTABLE_PVP : CORPSE_RESURRECTABLE_PVE );
SetPvPDeath(false);
- if(!corpse->Create(objmgr.GenerateLowGuid(HIGHGUID_CORPSE), this, GetMapId(), GetPositionX(),
- GetPositionY(), GetPositionZ(), GetOrientation()))
+ if(!corpse->Create(objmgr.GenerateLowGuid(HIGHGUID_CORPSE), this))
{
delete corpse;
return;
@@ -3944,7 +4201,7 @@ void Player::CreateCorpse()
flags |= CORPSE_FLAG_HIDE_HELM;
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
flags |= CORPSE_FLAG_HIDE_CLOAK;
- if(InBattleGround())
+ if(InBattleGround() && !InArena())
flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia
corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, flags );
@@ -4131,7 +4388,7 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g
DurabilityCostsEntry const *dcost = sDurabilityCostsStore.LookupEntry(ditemProto->ItemLevel);
if(!dcost)
{
- sLog.outError("ERROR: RepairDurability: Wrong item lvl %u", ditemProto->ItemLevel);
+ sLog.outError("RepairDurability: Wrong item lvl %u", ditemProto->ItemLevel);
return TotalCost;
}
@@ -4139,7 +4396,7 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g
DurabilityQualityEntry const *dQualitymodEntry = sDurabilityQualityStore.LookupEntry(dQualitymodEntryId);
if(!dQualitymodEntry)
{
- sLog.outError("ERROR: RepairDurability: Wrong dQualityModEntry %u", dQualitymodEntryId);
+ sLog.outError("RepairDurability: Wrong dQualityModEntry %u", dQualitymodEntryId);
return TotalCost;
}
@@ -4220,10 +4477,8 @@ void Player::RepopAtGraveyard()
WorldSafeLocsEntry const *ClosestGrave = NULL;
// Special handle for battleground maps
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId());
-
- if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY || bg->GetTypeID() == BATTLEGROUND_AV))
- ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam());
+ if( BattleGround *bg = GetBattleGround() )
+ ClosestGrave = bg->GetClosestGraveYard(this);
else
ClosestGrave = objmgr.GetClosestGraveYard( GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam() );
@@ -4384,7 +4639,7 @@ float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const
{
if(modGroup >= BASEMOD_END || modType > MOD_END)
{
- sLog.outError("ERROR: trial to access non existed BaseModGroup or wrong BaseModType!");
+ sLog.outError("trial to access non existed BaseModGroup or wrong BaseModType!");
return 0.0f;
}
@@ -4398,7 +4653,7 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const
{
if(modGroup >= BASEMOD_END)
{
- sLog.outError("ERROR: wrong BaseModGroup in GetTotalBaseModValue()!");
+ sLog.outError("wrong BaseModGroup in GetTotalBaseModValue()!");
return 0.0f;
}
@@ -4410,9 +4665,7 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const
uint32 Player::GetShieldBlockValue() const
{
- BaseModGroup modGroup = SHIELD_BLOCK_VALUE;
-
- float value = GetTotalBaseModValue(modGroup) + GetStat(STAT_STRENGTH)/20 - 1;
+ float value = (m_auraBaseMod[SHIELD_BLOCK_VALUE][FLAT_MOD] + GetStat(STAT_STRENGTH) * 0.5f - 10)*m_auraBaseMod[SHIELD_BLOCK_VALUE][PCT_MOD];
value = (value < 0) ? 0 : value;
@@ -4516,24 +4769,24 @@ float Player::GetRatingBonusValue(CombatRating cr) const
uint32 Player::GetMeleeCritDamageReduction(uint32 damage) const
{
- float melee = GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*2.0f;
- if (melee>25.0f) melee = 25.0f;
+ float melee = GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*2.2f;
+ if (melee>33.0f) melee = 33.0f;
return uint32 (melee * damage /100.0f);
}
uint32 Player::GetRangedCritDamageReduction(uint32 damage) const
{
- float ranged = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED)*2.0f;
- if (ranged>25.0f) ranged=25.0f;
+ float ranged = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED)*2.2f;
+ if (ranged>33.0f) ranged=33.0f;
return uint32 (ranged * damage /100.0f);
}
uint32 Player::GetSpellCritDamageReduction(uint32 damage) const
{
- float spell = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2.0f;
- // In wow script resilience limited to 25%
- if (spell>25.0f)
- spell = 25.0f;
+ float spell = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2.2f;
+ // In wow script resilience limited to 33%
+ if (spell>33.0f)
+ spell = 33.0f;
return uint32 (spell * damage / 100.0f);
}
@@ -4601,7 +4854,18 @@ float Player::OCTRegenMPPerSpirit()
void Player::ApplyRatingMod(CombatRating cr, int32 value, bool apply)
{
- ApplyModUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, value, apply);
+ m_baseRatingValue[cr]+=(apply ? value : -value);
+
+ int32 amount = uint32(m_baseRatingValue[cr]);
+ // Apply bonus from SPELL_AURA_MOD_RATING_FROM_STAT
+ // stat used stored in miscValueB for this aura
+ AuraEffectList const& modRatingFromStat = GetAurasByType(SPELL_AURA_MOD_RATING_FROM_STAT);
+ for(AuraEffectList::const_iterator i = modRatingFromStat.begin();i != modRatingFromStat.end(); ++i)
+ if ((*i)->GetMiscValue() & (1<<cr))
+ amount += int32(GetStat(Stats((*i)->GetMiscBValue())) * (*i)->GetAmount() / 100.0f);
+ if (amount < 0)
+ amount = 0;
+ SetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, uint32(amount));
float RatingCoeffecient = GetRatingCoefficient(cr);
float RatingChange = 0.0f;
@@ -4624,16 +4888,13 @@ void Player::ApplyRatingMod(CombatRating cr, int32 value, bool apply)
UpdateBlockPercentage();
break;
case CR_HIT_MELEE:
- RatingChange = value / RatingCoeffecient;
- m_modMeleeHitChance += apply ? RatingChange : -RatingChange;
+ UpdateMeleeHitChances();
break;
case CR_HIT_RANGED:
- RatingChange = value / RatingCoeffecient;
- m_modRangedHitChance += apply ? RatingChange : -RatingChange;
+ UpdateRangedHitChances();
break;
case CR_HIT_SPELL:
- RatingChange = value / RatingCoeffecient;
- m_modSpellHitChance += apply ? RatingChange : -RatingChange;
+ UpdateSpellHitChances();
break;
case CR_CRIT_MELEE:
if(affectStats)
@@ -4684,6 +4945,8 @@ void Player::ApplyRatingMod(CombatRating cr, int32 value, bool apply)
UpdateExpertise(OFF_ATTACK);
}
break;
+ case CR_ARMOR_PENETRATION:
+ break;
}
}
@@ -4731,6 +4994,7 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step)
new_value = max;
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,max));
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,skill_id);
return true;
}
@@ -4766,7 +5030,7 @@ bool Player::UpdateCraftSkill(uint32 spellid)
if(spellEntry && spellEntry->Mechanic==MECHANIC_DISCOVERY)
{
if(uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this))
- learnSpell(discoveredSpell);
+ learnSpell(discoveredSpell,false);
}
uint32 craft_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_CRAFTING);
@@ -4793,6 +5057,7 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLeve
case SKILL_HERBALISM:
case SKILL_LOCKPICKING:
case SKILL_JEWELCRAFTING:
+ case SKILL_INSCRIPTION:
return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator,gathering_skill_gain);
case SKILL_SKINNING:
if( sWorld.getConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)==0)
@@ -4821,6 +5086,11 @@ bool Player::UpdateFishingSkill()
return UpdateSkillPro(SKILL_FISHING,chance*10,gathering_skill_gain);
}
+// levels sync. with spell requirement for skill levels to learn
+// bonus abilities in sSkillLineAbilityStore
+// Used only to avoid scan DBC at each skill grow
+static uint32 bonusSkillLevels[] = {75,150,225,300,375,450};
+
bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step)
{
sLog.outDebug("UpdateSkillPro(SkillId %d, Chance %3.1f%%)", SkillId, Chance/10.0);
@@ -4855,6 +5125,15 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step)
new_value = MaxValue;
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(new_value,MaxValue));
+ for(uint32* bsl = &bonusSkillLevels[0]; *bsl; ++bsl)
+ {
+ if((SkillValue < *bsl && new_value >= *bsl))
+ {
+ learnSkillRewardedSpells( SkillId, new_value);
+ break;
+ }
+ }
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,SkillId);
sLog.outDebug("Player::UpdateSkillPro Chance=%3.1f%% taken", Chance/10.0);
return true;
}
@@ -4902,22 +5181,8 @@ void Player::UpdateWeaponSkill (WeaponAttackType attType)
UpdateAllCritPercentages();
}
-void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence)
+void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, bool defence)
{
-/* Not need, this checked on call this func from trigger system
- switch(outcome)
- {
- case MELEE_HIT_CRIT:
- case MELEE_HIT_DODGE:
- case MELEE_HIT_PARRY:
- case MELEE_HIT_BLOCK:
- case MELEE_HIT_BLOCK_CRIT:
- return;
-
- default:
- break;
- }
-*/
uint32 plevel = getLevel(); // if defense than pVictim == attacker
uint32 greylevel = Trinity::XP::GetGrayLevel(plevel);
uint32 moblevel = pVictim->getLevelForTarget(this);
@@ -5014,7 +5279,7 @@ void Player::UpdateSkillsToMaxSkillsForLevel()
if (GetUInt32Value(PLAYER_SKILL_INDEX(i)))
{
uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF;
- if( IsProfessionSkill(pskill) || pskill == SKILL_RIDING )
+ if( IsProfessionOrRidingSkill(pskill))
continue;
uint32 data = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i));
@@ -5042,7 +5307,12 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal)
if(i<PLAYER_MAX_SKILLS) //has skill
{
if(currVal)
+ {
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(currVal,maxVal));
+ learnSkillRewardedSpells(id, currVal);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,id);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL,id);
+ }
else //remove
{
// clear skill fields
@@ -5050,27 +5320,11 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal)
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),0);
SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0);
- // remove spells that depend on this skill when removing the skill
- for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
- {
- ++next;
- if(itr->second->state == PLAYERSPELL_REMOVED)
- continue;
-
- SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(itr->first);
- SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(itr->first);
-
- for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
- {
- if (_spell_idx->second->skillId == id)
- {
- // this may remove more than one spell (dependents)
- removeSpell(itr->first);
- next = m_spells.begin();
- break;
- }
- }
- }
+ // remove all spells that related to this skill
+ for (uint32 j=0; j<sSkillLineAbilityStore.GetNumRows(); ++j)
+ if(SkillLineAbilityEntry const *pAbility = sSkillLineAbilityStore.LookupEntry(j))
+ if (pAbility->skillId==id)
+ removeSpell(spellmgr.GetFirstSpellInChain(pAbility->spellId));
}
}
else if(currVal) //add
@@ -5090,24 +5344,26 @@ void Player::SetSkill(uint32 id, uint16 currVal, uint16 maxVal)
else
SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0));
SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(currVal,maxVal));
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL,id);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL,id);
// apply skill bonuses
SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0);
// temporary bonuses
- AuraList const& mModSkill = GetAurasByType(SPELL_AURA_MOD_SKILL);
- for(AuraList::const_iterator i = mModSkill.begin(); i != mModSkill.end(); ++i)
- if ((*i)->GetModifier()->m_miscvalue == int32(id))
- (*i)->ApplyModifier(true);
+ AuraEffectList const& mModSkill = GetAurasByType(SPELL_AURA_MOD_SKILL);
+ for(AuraEffectList::const_iterator j = mModSkill.begin(); j != mModSkill.end(); ++j)
+ if ((*j)->GetMiscValue() == int32(id))
+ (*j)->ApplyModifier(true);
// permanent bonuses
- AuraList const& mModSkillTalent = GetAurasByType(SPELL_AURA_MOD_SKILL_TALENT);
- for(AuraList::const_iterator i = mModSkillTalent.begin(); i != mModSkillTalent.end(); ++i)
- if ((*i)->GetModifier()->m_miscvalue == int32(id))
- (*i)->ApplyModifier(true);
+ AuraEffectList const& mModSkillTalent = GetAurasByType(SPELL_AURA_MOD_SKILL_TALENT);
+ for(AuraEffectList::const_iterator j = mModSkillTalent.begin(); j != mModSkillTalent.end(); ++j)
+ if ((*j)->GetMiscValue() == int32(id))
+ (*j)->ApplyModifier(true);
// Learn all spells for skill
- learnSkillRewardedSpells(id);
+ learnSkillRewardedSpells(id, currVal);
return;
}
}
@@ -5205,6 +5461,22 @@ uint16 Player::GetPureSkillValue(uint32 skill) const
return 0;
}
+int16 Player::GetSkillPermBonusValue(uint32 skill) const
+{
+ if(!skill)
+ return 0;
+
+ for (int i = 0; i < PLAYER_MAX_SKILLS; i++)
+ {
+ if ((GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF) == skill)
+ {
+ return SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i)));
+ }
+ }
+
+ return 0;
+}
+
int16 Player::GetSkillTempBonusValue(uint32 skill) const
{
if(!skill)
@@ -5221,7 +5493,7 @@ int16 Player::GetSkillTempBonusValue(uint32 skill) const
return 0;
}
-void Player::SendInitialActionButtons()
+void Player::SendInitialActionButtons() const
{
sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
@@ -5245,12 +5517,12 @@ void Player::SendInitialActionButtons()
sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
}
-void Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc)
+bool Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc)
{
if(button >= MAX_ACTION_BUTTONS)
{
sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() );
- return;
+ return false;
}
// check cheating with adding non-known spells to action bar
@@ -5259,13 +5531,13 @@ void Player::addActionButton(const uint8 button, const uint16 action, const uint
if(!sSpellStore.LookupEntry(action))
{
sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() );
- return;
+ return false;
}
if(!HasSpell(action))
{
sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() );
- return;
+ return false;
}
}
@@ -5283,6 +5555,7 @@ void Player::addActionButton(const uint8 button, const uint16 action, const uint
};
sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button );
+ return true;
}
void Player::removeActionButton(uint8 button)
@@ -5299,11 +5572,6 @@ void Player::removeActionButton(uint8 button)
sLog.outDetail( "Action Button '%u' Removed from Player '%u'", button, GetGUIDLow() );
}
-void Player::SetDontMove(bool dontMove)
-{
- m_dontMove = dontMove;
-}
-
bool Player::SetPosition(float x, float y, float z, float orientation, bool teleport)
{
// prevent crash when a bad coord is sent by the client
@@ -5360,17 +5628,17 @@ void Player::SaveRecallPosition()
void Player::SendMessageToSet(WorldPacket *data, bool self, bool to_possessor)
{
- MapManager::Instance().GetMap(GetMapId(), this)->MessageBroadcast(this, data, self, to_possessor);
+ GetMap()->MessageBroadcast(this, data, self, to_possessor);
}
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor)
{
- MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self, to_possessor);
+ GetMap()->MessageDistBroadcast(this, data, dist, self, to_possessor);
}
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor, bool own_team_only)
{
- MapManager::Instance().GetMap(GetMapId(), this)->MessageDistBroadcast(this, data, dist, self, to_possessor, own_team_only);
+ GetMap()->MessageDistBroadcast(this, data, dist, self, to_possessor, own_team_only);
}
void Player::SendDirectMessage(WorldPacket *data)
@@ -5378,6 +5646,20 @@ void Player::SendDirectMessage(WorldPacket *data)
GetSession()->SendPacket(data);
}
+void Player::SendCinematicStart(uint32 CinematicSequenceId)
+{
+ WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4);
+ data << uint32(CinematicSequenceId);
+ SendDirectMessage(&data);
+}
+
+void Player::SendMovieStart(uint32 MovieId)
+{
+ WorldPacket data(SMSG_TRIGGER_MOVIE, 4);
+ data << uint32(MovieId);
+ SendDirectMessage(&data);
+}
+
void Player::CheckExploreSystem()
{
if (!isAlive())
@@ -5386,14 +5668,14 @@ void Player::CheckExploreSystem()
if (isInFlight())
return;
- uint16 areaFlag=MapManager::Instance().GetBaseMap(GetMapId())->GetAreaFlag(GetPositionX(),GetPositionY());
+ uint16 areaFlag=MapManager::Instance().GetBaseMap(GetMapId())->GetAreaFlag(GetPositionX(),GetPositionY(),GetPositionZ());
if(areaFlag==0xffff)
return;
int offset = areaFlag / 32;
if(offset >= 128)
{
- sLog.outError("ERROR: Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < 64 ).",areaFlag,GetPositionX(),GetPositionY(),offset,offset);
+ sLog.outError("Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < 128 ).",areaFlag,GetPositionX(),GetPositionY(),offset,offset);
return;
}
@@ -5404,6 +5686,8 @@ void Player::CheckExploreSystem()
{
SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val));
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA);
+
AreaTableEntry const *p = GetAreaEntryByAreaFlagAndMap(areaFlag,GetMapId());
if(!p)
{
@@ -5462,7 +5746,7 @@ uint32 Player::TeamForRace(uint8 race)
case 1: return HORDE;
}
- sLog.outError("Race %u have wrong team id in DBC: wrong DBC files?",uint32(race),rEntry->TeamID);
+ sLog.outError("Race %u have wrong teamid %u in DBC: wrong DBC files?",uint32(race),rEntry->TeamID);
return ALLIANCE;
}
@@ -5484,438 +5768,33 @@ void Player::setFactionForRace(uint8 race)
setFaction( getFactionForRace(race) );
}
-void Player::UpdateReputation() const
-{
- sLog.outDetail( "WORLD: Player::UpdateReputation" );
-
- for(FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
- {
- SendFactionState(&(itr->second));
- }
-}
-
-void Player::SendFactionState(FactionState const* faction) const
-{
- if(faction->Flags & FACTION_FLAG_VISIBLE) //If faction is visible then update it
- {
- WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0
- data << (float) 0; // unk 2.4.0
- data << (uint32) 1; // count
- // for
- data << (uint32) faction->ReputationListID;
- data << (uint32) faction->Standing;
- // end for
- GetSession()->SendPacket(&data);
- }
-}
-
-void Player::SendInitialReputations()
-{
- WorldPacket data(SMSG_INITIALIZE_FACTIONS, (4+128*5));
- data << uint32 (0x00000080);
-
- RepListID a = 0;
-
- for (FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
- {
- // fill in absent fields
- for (; a != itr->first; a++)
- {
- data << uint8 (0x00);
- data << uint32 (0x00000000);
- }
-
- // fill in encountered data
- data << uint8 (itr->second.Flags);
- data << uint32 (itr->second.Standing);
-
- ++a;
- }
-
- // fill in absent fields
- for (; a != 128; a++)
- {
- data << uint8 (0x00);
- data << uint32 (0x00000000);
- }
-
- GetSession()->SendPacket(&data);
-}
-
-FactionState const* Player::GetFactionState( FactionEntry const* factionEntry) const
-{
- FactionStateList::const_iterator itr = m_factions.find(factionEntry->reputationListID);
- if (itr != m_factions.end())
- return &itr->second;
-
- return NULL;
-}
-
-void Player::SetFactionAtWar(FactionState* faction, bool atWar)
-{
- // not allow declare war to own faction
- if(atWar && (faction->Flags & FACTION_FLAG_PEACE_FORCED) )
- return;
-
- // already set
- if(((faction->Flags & FACTION_FLAG_AT_WAR) != 0) == atWar)
- return;
-
- if( atWar )
- faction->Flags |= FACTION_FLAG_AT_WAR;
- else
- faction->Flags &= ~FACTION_FLAG_AT_WAR;
-
- faction->Changed = true;
-}
-
-void Player::SetFactionInactive(FactionState* faction, bool inactive)
-{
- // always invisible or hidden faction can't be inactive
- if(inactive && ((faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) || !(faction->Flags & FACTION_FLAG_VISIBLE) ) )
- return;
-
- // already set
- if(((faction->Flags & FACTION_FLAG_INACTIVE) != 0) == inactive)
- return;
-
- if(inactive)
- faction->Flags |= FACTION_FLAG_INACTIVE;
- else
- faction->Flags &= ~FACTION_FLAG_INACTIVE;
-
- faction->Changed = true;
-}
-
-void Player::SetFactionVisibleForFactionTemplateId(uint32 FactionTemplateId)
-{
- FactionTemplateEntry const*factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId);
-
- if(!factionTemplateEntry)
- return;
-
- SetFactionVisibleForFactionId(factionTemplateEntry->faction);
-}
-
-void Player::SetFactionVisibleForFactionId(uint32 FactionId)
-{
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(FactionId);
- if(!factionEntry)
- return;
-
- if(factionEntry->reputationListID < 0)
- return;
-
- FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID);
- if (itr == m_factions.end())
- return;
-
- SetFactionVisible(&itr->second);
-}
-
-void Player::SetFactionVisible(FactionState* faction)
-{
- // always invisible or hidden faction can't be make visible
- if(faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN))
- return;
-
- // already set
- if(faction->Flags & FACTION_FLAG_VISIBLE)
- return;
-
- faction->Flags |= FACTION_FLAG_VISIBLE;
- faction->Changed = true;
-
- if(!m_session->PlayerLoading())
- {
- // make faction visible in reputation list at client
- WorldPacket data(SMSG_SET_FACTION_VISIBLE, 4);
- data << faction->ReputationListID;
- GetSession()->SendPacket(&data);
- }
-}
-
-void Player::SetInitialFactions()
-{
- for(unsigned int i = 1; i < sFactionStore.GetNumRows(); i++)
- {
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(i);
-
- if( factionEntry && (factionEntry->reputationListID >= 0))
- {
- FactionState newFaction;
- newFaction.ID = factionEntry->ID;
- newFaction.ReputationListID = factionEntry->reputationListID;
- newFaction.Standing = 0;
- newFaction.Flags = GetDefaultReputationFlags(factionEntry);
- newFaction.Changed = true;
-
- m_factions[newFaction.ReputationListID] = newFaction;
- }
- }
-}
-
-uint32 Player::GetDefaultReputationFlags(const FactionEntry *factionEntry) const
-{
- if (!factionEntry)
- return 0;
-
- uint32 raceMask = getRaceMask();
- uint32 classMask = getClassMask();
- for (int i=0; i < 4; i++)
- {
- if( (factionEntry->BaseRepRaceMask[i] & raceMask) &&
- (factionEntry->BaseRepClassMask[i]==0 ||
- (factionEntry->BaseRepClassMask[i] & classMask) ) )
- return factionEntry->ReputationFlags[i];
- }
- return 0;
-}
-
-int32 Player::GetBaseReputation(const FactionEntry *factionEntry) const
-{
- if (!factionEntry)
- return 0;
-
- uint32 raceMask = getRaceMask();
- uint32 classMask = getClassMask();
- for (int i=0; i < 4; i++)
- {
- if( (factionEntry->BaseRepRaceMask[i] & raceMask) &&
- (factionEntry->BaseRepClassMask[i]==0 ||
- (factionEntry->BaseRepClassMask[i] & classMask) ) )
- return factionEntry->BaseRepValue[i];
- }
-
- // in faction.dbc exist factions with (RepListId >=0, listed in character reputation list) with all BaseRepRaceMask[i]==0
- return 0;
-}
-
-int32 Player::GetReputation(uint32 faction_id) const
-{
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(faction_id);
-
- if (!factionEntry)
- {
- sLog.outError("Player::GetReputation: Can't get reputation of %s for unknown faction (faction template id) #%u.",GetName(), faction_id);
- return 0;
- }
-
- return GetReputation(factionEntry);
-}
-
-int32 Player::GetReputation(const FactionEntry *factionEntry) const
-{
- // Faction without recorded reputation. Just ignore.
- if(!factionEntry)
- return 0;
-
- FactionStateList::const_iterator itr = m_factions.find(factionEntry->reputationListID);
- if (itr != m_factions.end())
- return GetBaseReputation(factionEntry) + itr->second.Standing;
-
- return 0;
-}
-
ReputationRank Player::GetReputationRank(uint32 faction) const
{
- FactionEntry const*factionEntry = sFactionStore.LookupEntry(faction);
- if(!factionEntry)
- return MIN_REPUTATION_RANK;
-
- return GetReputationRank(factionEntry);
-}
-
-ReputationRank Player::ReputationToRank(int32 standing) const
-{
- int32 Limit = Reputation_Cap + 1;
- for (int i = MAX_REPUTATION_RANK-1; i >= MIN_REPUTATION_RANK; --i)
- {
- Limit -= ReputationRank_Length[i];
- if (standing >= Limit )
- return ReputationRank(i);
- }
- return MIN_REPUTATION_RANK;
-}
-
-ReputationRank Player::GetReputationRank(const FactionEntry *factionEntry) const
-{
- int32 Reputation = GetReputation(factionEntry);
- return ReputationToRank(Reputation);
-}
-
-ReputationRank Player::GetBaseReputationRank(const FactionEntry *factionEntry) const
-{
- int32 Reputation = GetBaseReputation(factionEntry);
- return ReputationToRank(Reputation);
-}
-
-bool Player::ModifyFactionReputation(uint32 FactionTemplateId, int32 DeltaReputation)
-{
- FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId);
-
- if(!factionTemplateEntry)
- {
- sLog.outError("Player::ModifyFactionReputation: Can't update reputation of %s for unknown faction (faction template id) #%u.", GetName(), FactionTemplateId);
- return false;
- }
-
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction);
-
- // Faction without recorded reputation. Just ignore.
- if(!factionEntry)
- return false;
-
- return ModifyFactionReputation(factionEntry, DeltaReputation);
-}
-
-bool Player::ModifyFactionReputation(FactionEntry const* factionEntry, int32 standing)
-{
- SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID);
- if (flist)
- {
- bool res = false;
- for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr)
- {
- FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr);
- if(factionEntryCalc)
- res = ModifyOneFactionReputation(factionEntryCalc, standing);
- }
- return res;
- }
- else
- return ModifyOneFactionReputation(factionEntry, standing);
-}
-
-bool Player::ModifyOneFactionReputation(FactionEntry const* factionEntry, int32 standing)
-{
- FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID);
- if (itr != m_factions.end())
- {
- int32 BaseRep = GetBaseReputation(factionEntry);
- int32 new_rep = BaseRep + itr->second.Standing + standing;
-
- if (new_rep > Reputation_Cap)
- new_rep = Reputation_Cap;
- else
- if (new_rep < Reputation_Bottom)
- new_rep = Reputation_Bottom;
-
- if(ReputationToRank(new_rep) <= REP_HOSTILE)
- SetFactionAtWar(&itr->second,true);
-
- itr->second.Standing = new_rep - BaseRep;
- itr->second.Changed = true;
-
- SetFactionVisible(&itr->second);
-
- for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
- {
- if(uint32 questid = GetQuestSlotQuestId(i))
- {
- Quest const* qInfo = objmgr.GetQuestTemplate(questid);
- if( qInfo && qInfo->GetRepObjectiveFaction() == factionEntry->ID )
- {
- QuestStatusData& q_status = mQuestStatus[questid];
- if( q_status.m_status == QUEST_STATUS_INCOMPLETE )
- {
- if(GetReputation(factionEntry) >= qInfo->GetRepObjectiveValue())
- if ( CanCompleteQuest( questid ) )
- CompleteQuest( questid );
- }
- else if( q_status.m_status == QUEST_STATUS_COMPLETE )
- {
- if(GetReputation(factionEntry) < qInfo->GetRepObjectiveValue())
- IncompleteQuest( questid );
- }
- }
- }
- }
-
- SendFactionState(&(itr->second));
-
- return true;
- }
- return false;
-}
-
-bool Player::SetFactionReputation(uint32 FactionTemplateId, int32 standing)
-{
- FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(FactionTemplateId);
-
- if(!factionTemplateEntry)
- {
- sLog.outError("Player::SetFactionReputation: Can't set reputation of %s for unknown faction (faction template id) #%u.", GetName(), FactionTemplateId);
- return false;
- }
-
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction);
-
- // Faction without recorded reputation. Just ignore.
- if(!factionEntry)
- return false;
-
- return SetFactionReputation(factionEntry, standing);
+ FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction);
+ return GetReputationMgr().GetRank(factionEntry);
}
-bool Player::SetFactionReputation(FactionEntry const* factionEntry, int32 standing)
+//Calculate total reputation percent player gain with quest/creature level
+int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest)
{
- SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID);
- if (flist)
- {
- bool res = false;
- for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr)
- {
- FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr);
- if(factionEntryCalc)
- res = SetOneFactionReputation(factionEntryCalc, standing);
- }
- return res;
- }
- else
- return SetOneFactionReputation(factionEntry, standing);
-}
+ float percent = 100.0f;
-bool Player::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing)
-{
- FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID);
- if (itr != m_factions.end())
- {
- if (standing > Reputation_Cap)
- standing = Reputation_Cap;
- else
- if (standing < Reputation_Bottom)
- standing = Reputation_Bottom;
+ float rate = for_quest ? sWorld.getRate(RATE_REPUTATION_LOWLEVEL_QUEST) : sWorld.getRate(RATE_REPUTATION_LOWLEVEL_KILL);
- int32 BaseRep = GetBaseReputation(factionEntry);
- itr->second.Standing = standing - BaseRep;
- itr->second.Changed = true;
+ if (rate != 1.0f && creatureOrQuestLevel <= MaNGOS::XP::GetGrayLevel(getLevel()))
+ percent *= rate;
- SetFactionVisible(&itr->second);
+ float repMod = GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN);
- if(ReputationToRank(standing) <= REP_HOSTILE)
- SetFactionAtWar(&itr->second,true);
-
- SendFactionState(&(itr->second));
- return true;
- }
- return false;
-}
-
-//Calculate total reputation percent player gain with quest/creature level
-int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest)
-{
- // for grey creature kill received 20%, in other case 100.
- int32 percent = (!for_quest && (creatureOrQuestLevel <= Trinity::XP::GetGrayLevel(getLevel()))) ? 20 : 100;
-
- int32 repMod = GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN);
+ if (!for_quest)
+ repMod += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_FACTION_REPUTATION_GAIN, faction);
percent += rep > 0 ? repMod : -repMod;
- if(percent <=0)
+ if (percent <= 0.0f)
return 0;
- return int32(sWorld.getRate(RATE_REPUTATION_GAIN)*rep*percent/100);
+ return int32(sWorld.getRate(RATE_REPUTATION_GAIN)*rep*percent/100.0f);
}
//Calculates how many reputation points player gains in victim's enemy factions
@@ -5934,37 +5813,37 @@ void Player::RewardReputation(Unit *pVictim, float rate)
if(Rep->repfaction1 && (!Rep->team_dependent || GetTeam()==ALLIANCE))
{
- int32 donerep1 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue1,false);
+ int32 donerep1 = CalculateReputationGain(pVictim->getLevel(), Rep->repvalue1, Rep->repfaction1, false);
donerep1 = int32(donerep1*rate);
FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(Rep->repfaction1);
- uint32 current_reputation_rank1 = GetReputationRank(factionEntry1);
- if(factionEntry1 && current_reputation_rank1 <= Rep->reputation_max_cap1)
- ModifyFactionReputation(factionEntry1, donerep1);
+ uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1);
+ if (factionEntry1 && current_reputation_rank1 <= Rep->reputation_max_cap1)
+ GetReputationMgr().ModifyReputation(factionEntry1, donerep1);
// Wiki: Team factions value divided by 2
- if(Rep->is_teamaward1)
+ if (factionEntry1 && Rep->is_teamaward1)
{
FactionEntry const *team1_factionEntry = sFactionStore.LookupEntry(factionEntry1->team);
if(team1_factionEntry)
- ModifyFactionReputation(team1_factionEntry, donerep1 / 2);
+ GetReputationMgr().ModifyReputation(team1_factionEntry, donerep1 / 2);
}
}
if(Rep->repfaction2 && (!Rep->team_dependent || GetTeam()==HORDE))
{
- int32 donerep2 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue2,false);
+ int32 donerep2 = CalculateReputationGain(pVictim->getLevel(), Rep->repvalue2, Rep->repfaction2, false);
donerep2 = int32(donerep2*rate);
FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(Rep->repfaction2);
- uint32 current_reputation_rank2 = GetReputationRank(factionEntry2);
- if(factionEntry2 && current_reputation_rank2 <= Rep->reputation_max_cap2)
- ModifyFactionReputation(factionEntry2, donerep2);
+ uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2);
+ if (factionEntry2 && current_reputation_rank2 <= Rep->reputation_max_cap2)
+ GetReputationMgr().ModifyReputation(factionEntry2, donerep2);
// Wiki: Team factions value divided by 2
- if(Rep->is_teamaward2)
+ if (factionEntry2 && Rep->is_teamaward2)
{
FactionEntry const *team2_factionEntry = sFactionStore.LookupEntry(factionEntry2->team);
if(team2_factionEntry)
- ModifyFactionReputation(team2_factionEntry, donerep2 / 2);
+ GetReputationMgr().ModifyReputation(team2_factionEntry, donerep2 / 2);
}
}
}
@@ -5977,10 +5856,10 @@ void Player::RewardReputation(Quest const *pQuest)
{
if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] )
{
- int32 rep = CalculateReputationGain(pQuest->GetQuestLevel(),pQuest->RewRepValue[i],true);
+ int32 rep = CalculateReputationGain(GetQuestLevel(pQuest), pQuest->RewRepValue[i], pQuest->RewRepFaction[i], true);
FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]);
if(factionEntry)
- ModifyFactionReputation(factionEntry, rep);
+ GetReputationMgr().ModifyReputation(factionEntry, rep);
}
}
@@ -6098,12 +5977,7 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt
victim_guid = 0; // Don't show HK: <rank> message, only log.
}
- if(k_level <= 5)
- k_grey = 0;
- else if( k_level <= 39 )
- k_grey = k_level - 5 - k_level/10;
- else
- k_grey = k_level - 1 - k_level/5;
+ k_grey = Trinity::XP::GetGrayLevel(k_level);
if(v_level<=k_grey)
return false;
@@ -6119,6 +5993,9 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt
ApplyModUInt32Value(PLAYER_FIELD_KILLS, 1, true);
// and those in a lifetime
ApplyModUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS, 1, true);
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL);
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS, pVictim->getClass());
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_RACE, pVictim->getRace());
}
else
{
@@ -6139,6 +6016,8 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt
if(groupsize > 1)
honor /= groupsize;
+ // apply honor multiplier from aura (not stacking-get highest)
+ honor = int32(float(honor) * (float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HONOR_GAIN_PCT))+100.0f)/100.0f);
honor *= (((float)urand(8,12))/10); // approx honor: 80% - 120% of real honor
}
@@ -6168,8 +6047,8 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt
{
// Check if allowed to receive it in current map
uint8 MapType = sWorld.getConfig(CONFIG_PVP_TOKEN_MAP_TYPE);
- if( (MapType == 1 && !InBattleGround() && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP))
- || (MapType == 2 && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP))
+ if( (MapType == 1 && !InBattleGround() && !HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
+ || (MapType == 2 && !HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
|| (MapType == 3 && !InBattleGround()) )
return true;
@@ -6227,24 +6106,18 @@ void Player::ModifyArenaPoints( int32 value )
uint32 Player::GetGuildIdFromDB(uint64 guid)
{
- std::ostringstream ss;
- ss<<"SELECT guildid FROM guild_member WHERE guid='"<<guid<<"'";
- QueryResult *result = CharacterDatabase.Query( ss.str().c_str() );
- if( result )
- {
- uint32 v = result->Fetch()[0].GetUInt32();
- delete result;
- return v;
- }
- else
+ QueryResult* result = CharacterDatabase.PQuery("SELECT guildid FROM guild_member WHERE guid='%u'", GUID_LOPART(guid));
+ if(!result)
return 0;
+
+ uint32 id = result->Fetch()[0].GetUInt32();
+ delete result;
+ return id;
}
uint32 Player::GetRankFromDB(uint64 guid)
{
- std::ostringstream ss;
- ss<<"SELECT rank FROM guild_member WHERE guid='"<<guid<<"'";
- QueryResult *result = CharacterDatabase.Query( ss.str().c_str() );
+ QueryResult *result = CharacterDatabase.PQuery( "SELECT rank FROM guild_member WHERE guid='%u'", GUID_LOPART(guid) );
if( result )
{
uint32 v = result->Fetch()[0].GetUInt32();
@@ -6268,10 +6141,8 @@ uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type)
uint32 Player::GetZoneIdFromDB(uint64 guid)
{
- std::ostringstream ss;
-
- ss<<"SELECT zone FROM characters WHERE guid='"<<GUID_LOPART(guid)<<"'";
- QueryResult *result = CharacterDatabase.Query( ss.str().c_str() );
+ uint32 guidLow = GUID_LOPART(guid);
+ QueryResult *result = CharacterDatabase.PQuery( "SELECT zone FROM characters WHERE guid='%u'", guidLow );
if (!result)
return 0;
Field* fields = result->Fetch();
@@ -6281,22 +6152,19 @@ uint32 Player::GetZoneIdFromDB(uint64 guid)
if (!zone)
{
// stored zone is zero, use generic and slow zone detection
- ss.str("");
- ss<<"SELECT map,position_x,position_y FROM characters WHERE guid='"<<GUID_LOPART(guid)<<"'";
- result = CharacterDatabase.Query(ss.str().c_str());
+ result = CharacterDatabase.PQuery("SELECT map,position_x,position_y,position_z FROM characters WHERE guid='%u'", guidLow);
if( !result )
return 0;
fields = result->Fetch();
- uint32 map = fields[0].GetUInt32();
+ uint32 map = fields[0].GetUInt32();
float posx = fields[1].GetFloat();
float posy = fields[2].GetFloat();
+ float posz = fields[3].GetFloat();
delete result;
- zone = MapManager::Instance().GetZoneId(map,posx,posy);
+ zone = MapManager::Instance().GetZoneId(map,posx,posy,posz);
- ss.str("");
- ss << "UPDATE characters SET zone='"<<zone<<"' WHERE guid='"<<GUID_LOPART(guid)<<"'";
- CharacterDatabase.Execute(ss.str().c_str());
+ CharacterDatabase.PExecute("UPDATE characters SET zone='%u' WHERE guid='%u'", zone, guidLow);
}
return zone;
@@ -6309,43 +6177,31 @@ void Player::UpdateArea(uint32 newArea)
m_areaUpdateId = newArea;
AreaTableEntry const* area = GetAreaEntryByAreaID(newArea);
-
- if(area && (area->flags & AREA_FLAG_ARENA))
- {
- if(!isGameMaster())
- SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
- }
- else
- {
- // remove ffa flag only if not ffapvp realm
- // removal in sanctuaries and capitals is handled in zone update
- if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && !sWorld.IsFFAPvPRealm())
- RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);
- }
+ pvpInfo.inFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);
+ UpdatePvPState(true);
UpdateAreaDependentAuras(newArea);
}
-void Player::UpdateZone(uint32 newZone)
+void Player::UpdateZone(uint32 newZone, uint32 newArea)
{
- uint32 oldZoneId = m_zoneUpdateId;
+ if(m_zoneUpdateId != newZone)
+ {
+ sOutdoorPvPMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId);
+ sOutdoorPvPMgr.HandlePlayerEnterZone(this, newZone);
+ SendInitWorldStates(newZone, newArea); // only if really enters to new zone, not just area change, works strange...
+ }
+
m_zoneUpdateId = newZone;
m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL;
// zone changed, so area changed as well, update it
- UpdateArea(GetAreaId());
+ UpdateArea(newArea);
AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone);
if(!zone)
return;
- // inform outdoor pvp
- if(oldZoneId != m_zoneUpdateId)
- {
- sOutdoorPvPMgr.HandlePlayerLeaveZone(this, oldZoneId);
- sOutdoorPvPMgr.HandlePlayerEnterZone(this, m_zoneUpdateId);
- }
-
if (sWorld.getConfig(CONFIG_WEATHER))
{
Weather *wth = sWorld.FindWeather(zone->ID);
@@ -6363,32 +6219,34 @@ void Player::UpdateZone(uint32 newZone)
}
}
- pvpInfo.inHostileArea =
- GetTeam() == ALLIANCE && zone->team == AREATEAM_HORDE ||
- GetTeam() == HORDE && zone->team == AREATEAM_ALLY ||
- sWorld.IsPvPRealm() && zone->team == AREATEAM_NONE ||
- InBattleGround(); // overwrite for battlegrounds, maybe batter some zone flags but current known not 100% fit to this
-
- if(pvpInfo.inHostileArea) // in hostile area
+ // in PvP, any not controlled zone (except zone->team == 6, default case)
+ // in PvE, only opposition team capital
+ switch(zone->team)
{
- if(!IsPvP() || pvpInfo.endTimer != 0)
- UpdatePvP(true, true);
- }
- else // in friendly area
- {
- if(IsPvP() && !HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_IN_PVP) && pvpInfo.endTimer == 0)
- pvpInfo.endTimer = time(0); // start toggle-off
+ case AREATEAM_ALLY:
+ pvpInfo.inHostileArea = GetTeam() != ALLIANCE && (sWorld.IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL);
+ break;
+ case AREATEAM_HORDE:
+ pvpInfo.inHostileArea = GetTeam() != HORDE && (sWorld.IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL);
+ break;
+ case AREATEAM_NONE:
+ // overwrite for battlegrounds, maybe batter some zone flags but current known not 100% fit to this
+ pvpInfo.inHostileArea = sWorld.IsPvPRealm() || InBattleGround() || (zone->flags & AREA_FLAG_OUTDOOR_PVP);
+ break;
+ default: // 6 in fact
+ pvpInfo.inHostileArea = false;
+ break;
}
- if(zone->flags & AREA_FLAG_SANCTUARY) // in sanctuary
+ pvpInfo.inNoPvPArea = false;
+ if((zone->flags & AREA_FLAG_SANCTUARY) || zone->mapid == 609) // in sanctuary
{
- SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY);
- if(sWorld.IsFFAPvPRealm())
- RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
+ SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
+ pvpInfo.inNoPvPArea = true;
}
else
{
- RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY);
+ RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
}
if(zone->flags & AREA_FLAG_CAPITAL) // in capital city
@@ -6396,9 +6254,7 @@ void Player::UpdateZone(uint32 newZone)
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
SetRestType(REST_TYPE_IN_CITY);
InnEnter(time(0),GetMapId(),0,0,0);
-
- if(sWorld.IsFFAPvPRealm())
- RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
+ pvpInfo.inNoPvPArea = true;
}
else // anywhere else
{
@@ -6410,28 +6266,26 @@ void Player::UpdateZone(uint32 newZone)
{
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
SetRestType(REST_TYPE_NO);
-
- if(sWorld.IsFFAPvPRealm())
- SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
}
}
else // not in tavern (leave city then)
{
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
SetRestType(REST_TYPE_NO);
-
- // Set player to FFA PVP when not in rested environment.
- if(sWorld.IsFFAPvPRealm())
- SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
}
}
}
+ UpdatePvPState();
+
// remove items with area/map limitations (delete only for alive player to allow back in ghost mode)
// if player resurrected at teleport this will be applied in resurrect code
if(isAlive())
DestroyZoneLimitedItem( true, newZone );
+ // check some item equip limitations (in result lost CanTitanGrip at talent reset, for example)
+ AutoUnequipOffhandIfNeed();
+
// recent client version not send leave/join channel packets for built-in local channels
UpdateLocalChannels( newZone );
@@ -6449,7 +6303,7 @@ void Player::CheckDuelDistance(time_t currTime)
return;
uint64 duelFlagGUID = GetUInt64Value(PLAYER_DUEL_ARBITER);
- GameObject* obj = ObjectAccessor::GetGameObject(*this, duelFlagGUID);
+ GameObject* obj = GetMap()->GetGameObject(duelFlagGUID);
if(!obj)
return;
@@ -6490,6 +6344,8 @@ void Player::DuelComplete(DuelCompleteType type)
if(!duel)
return;
+ sLog.outDebug("Duel Complete %s %s", GetName(), duel->opponent->GetName());
+
WorldPacket data(SMSG_DUEL_COMPLETE, (1));
data << (uint8)((type != DUEL_INTERUPTED) ? 1 : 0);
GetSession()->SendPacket(&data);
@@ -6504,6 +6360,13 @@ void Player::DuelComplete(DuelCompleteType type)
SendMessageToSet(&data,true);
}
+ if (type == DUEL_WON)
+ {
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL, 1);
+ if (duel->opponent)
+ duel->opponent->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
+ }
+
// cool-down duel spell
/*data.Initialize(SMSG_SPELL_COOLDOWN, 17);
@@ -6521,31 +6384,32 @@ void Player::DuelComplete(DuelCompleteType type)
duel->opponent->GetSession()->SendPacket(&data);*/
//Remove Duel Flag object
- GameObject* obj = ObjectAccessor::GetGameObject(*this, GetUInt64Value(PLAYER_DUEL_ARBITER));
+ GameObject* obj = GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER));
if(obj)
duel->initiator->RemoveGameObject(obj,true);
/* remove auras */
- std::vector<uint32> auras2remove;
- AuraMap const& vAuras = duel->opponent->GetAuras();
- for (AuraMap::const_iterator i = vAuras.begin(); i != vAuras.end(); ++i)
+ AuraMap &itsAuras = duel->opponent->GetAuras();
+ for(AuraMap::iterator i = itsAuras.begin(); i != itsAuras.end();)
{
if (!i->second->IsPositive() && i->second->GetCasterGUID() == GetGUID() && i->second->GetAuraApplyTime() >= duel->startTime)
- auras2remove.push_back(i->second->GetId());
+ {
+ duel->opponent->RemoveAura(i);
+ }
+ else
+ ++i;
}
- for(size_t i=0; i<auras2remove.size(); i++)
- duel->opponent->RemoveAurasDueToSpell(auras2remove[i]);
-
- auras2remove.clear();
- AuraMap const& auras = GetAuras();
- for (AuraMap::const_iterator i = auras.begin(); i != auras.end(); ++i)
+ AuraMap &myAuras = GetAuras();
+ for(AuraMap::iterator i = myAuras.begin(); i != myAuras.end();)
{
if (!i->second->IsPositive() && i->second->GetCasterGUID() == duel->opponent->GetGUID() && i->second->GetAuraApplyTime() >= duel->startTime)
- auras2remove.push_back(i->second->GetId());
+ {
+ RemoveAura(i);
+ }
+ else
+ ++i;
}
- for(size_t i=0; i<auras2remove.size(); i++)
- RemoveAurasDueToSpell(auras2remove[i]);
// cleanup combo points
if(GetComboTarget()==duel->opponent->GetGUID())
@@ -6592,7 +6456,12 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply)
sLog.outDetail("applying mods for item %u ",item->GetGUIDLow());
- uint32 attacktype = Player::GetAttackBySlot(slot);
+ uint8 attacktype = Player::GetAttackBySlot(slot);
+
+ //check disarm only on mod apply to allow remove item mods
+ if (apply && !CanUseAttackType(attacktype) )
+ return;
+
if(attacktype < MAX_ATTACK)
_ApplyWeaponDependentAuraMods(item,WeaponAttackType(attacktype),apply);
@@ -6610,19 +6479,38 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply)
sLog.outDebug("_ApplyItemMods complete.");
}
-void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply)
+void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply)
{
if(slot >= INVENTORY_SLOT_BAG_END || !proto)
return;
- for (int i = 0; i < 10; i++)
+ ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : 0;
+ ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : 0;
+
+ for (int i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{
- float val = float (proto->ItemStat[i].ItemStatValue);
+ uint32 statType = 0;
+ int32 val = 0;
+ // If set ScalingStatDistribution need get stats and values from it
+ if (ssd && ssv)
+ {
+ if (ssd->StatMod[i] < 0)
+ continue;
+ statType = ssd->StatMod[i];
+ val = (ssv->getssdMultiplier(proto->ScalingStatValue) * ssd->Modifier[i]) / 10000;
+ }
+ else
+ {
+ if (i >= proto->StatsCount)
+ continue;
+ statType = proto->ItemStat[i].ItemStatType;
+ val = proto->ItemStat[i].ItemStatValue;
+ }
- if(val==0)
+ if(val == 0)
continue;
- switch (proto->ItemStat[i].ItemStatType)
+ switch (statType)
{
case ITEM_MOD_MANA:
HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply);
@@ -6740,11 +6628,47 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply)
case ITEM_MOD_EXPERTISE_RATING:
ApplyRatingMod(CR_EXPERTISE, int32(val), apply);
break;
+ case ITEM_MOD_ATTACK_POWER:
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
+ break;
+ case ITEM_MOD_RANGED_ATTACK_POWER:
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
+ break;
+ case ITEM_MOD_FERAL_ATTACK_POWER:
+ ApplyFeralAPBonus(int32(val), apply);
+ break;
+ case ITEM_MOD_SPELL_HEALING_DONE:
+ ApplySpellHealingBonus(int32(val), apply);
+ break;
+ case ITEM_MOD_SPELL_DAMAGE_DONE:
+ ApplySpellDamageBonus(int32(val), apply);
+ break;
+ case ITEM_MOD_MANA_REGENERATION:
+ ApplyManaRegenBonus(int32(val), apply);
+ break;
+ case ITEM_MOD_ARMOR_PENETRATION_RATING:
+ ApplyRatingMod(CR_ARMOR_PENETRATION, int32(val), apply);
+ break;
+ case ITEM_MOD_SPELL_POWER:
+ ApplySpellHealingBonus(int32(val), apply);
+ ApplySpellDamageBonus(int32(val), apply);
+ break;
}
}
- if (proto->Armor)
- HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(proto->Armor), apply);
+ // If set ScalingStatValue armor get it or use item armor
+ uint32 armor = proto->Armor;
+ if (ssv)
+ {
+ if (uint32 ssvarmor = ssv->getArmorMod(proto->ScalingStatValue))
+ armor = ssvarmor;
+ }
+ // Add armor bonus from ArmorDamageModifier if > 0
+ if (proto->ArmorDamageModifier > 0)
+ armor+=proto->ArmorDamageModifier;
+ if (armor)
+ HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(armor), apply);
if (proto->Block)
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply);
@@ -6781,20 +6705,47 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply)
attType = OFF_ATTACK;
}
- if (proto->Damage[0].DamageMin > 0 )
+ float minDamage = proto->Damage[0].DamageMin;
+ float maxDamage = proto->Damage[0].DamageMax;
+ int32 extraDPS = 0;
+ // If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
+ if (ssv)
{
- damage = apply ? proto->Damage[0].DamageMin : BASE_MINDAMAGE;
+ if (extraDPS = ssv->getDPSMod(proto->ScalingStatValue))
+ {
+ float average = extraDPS * proto->Delay / 1000.0f;
+ minDamage = 0.7f * average;
+ maxDamage = 1.3f * average;
+ }
+ }
+ if (minDamage > 0 )
+ {
+ damage = apply ? minDamage : BASE_MINDAMAGE;
SetBaseWeaponDamage(attType, MINDAMAGE, damage);
//sLog.outError("applying mindam: assigning %f to weapon mindamage, now is: %f", damage, GetWeaponDamageRange(attType, MINDAMAGE));
}
- if (proto->Damage[0].DamageMax > 0 )
+ if (maxDamage > 0 )
{
- damage = apply ? proto->Damage[0].DamageMax : BASE_MAXDAMAGE;
+ damage = apply ? maxDamage : BASE_MAXDAMAGE;
SetBaseWeaponDamage(attType, MAXDAMAGE, damage);
}
- if(!IsUseEquipedWeapon(slot==EQUIPMENT_SLOT_MAINHAND))
+ // Apply feral bonus from ScalingStatValue if set
+ if (ssv)
+ {
+ if (int32 feral_bonus = ssv->getFeralBonus(proto->ScalingStatValue))
+ ApplyFeralAPBonus(feral_bonus, apply);
+ }
+ // Druids get feral AP bonus from weapon dps (lso use DPS from ScalingStatValue)
+ if(getClass() == CLASS_DRUID)
+ {
+ int32 feral_bonus = proto->getFeralBonus(extraDPS);
+ if (feral_bonus > 0)
+ ApplyFeralAPBonus(feral_bonus, apply);
+ }
+
+ if(IsInFeralForm() || !CanUseAttackType(attType))
return;
if (proto->Delay)
@@ -6813,20 +6764,20 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply)
void Player::_ApplyWeaponDependentAuraMods(Item *item,WeaponAttackType attackType,bool apply)
{
- AuraList const& auraCritList = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT);
- for(AuraList::const_iterator itr = auraCritList.begin(); itr!=auraCritList.end();++itr)
+ AuraEffectList const& auraCritList = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT);
+ for(AuraEffectList::const_iterator itr = auraCritList.begin(); itr!=auraCritList.end();++itr)
_ApplyWeaponDependentAuraCritMod(item,attackType,*itr,apply);
- AuraList const& auraDamageFlatList = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
- for(AuraList::const_iterator itr = auraDamageFlatList.begin(); itr!=auraDamageFlatList.end();++itr)
+ AuraEffectList const& auraDamageFlatList = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
+ for(AuraEffectList::const_iterator itr = auraDamageFlatList.begin(); itr!=auraDamageFlatList.end();++itr)
_ApplyWeaponDependentAuraDamageMod(item,attackType,*itr,apply);
- AuraList const& auraDamagePCTList = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for(AuraList::const_iterator itr = auraDamagePCTList.begin(); itr!=auraDamagePCTList.end();++itr)
+ AuraEffectList const& auraDamagePCTList = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
+ for(AuraEffectList::const_iterator itr = auraDamagePCTList.begin(); itr!=auraDamagePCTList.end();++itr)
_ApplyWeaponDependentAuraDamageMod(item,attackType,*itr,apply);
}
-void Player::_ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply)
+void Player::_ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attackType, AuraEffect* aura, bool apply)
{
// generic not weapon specific case processes in aura code
if(aura->GetSpellProto()->EquippedItemClass == -1)
@@ -6843,15 +6794,14 @@ void Player::_ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attac
if (item->IsFitToSpellRequirements(aura->GetSpellProto()))
{
- HandleBaseModValue(mod, FLAT_MOD, float (aura->GetModifierValue()), apply);
+ HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply);
}
}
-void Player::_ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply)
+void Player::_ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType attackType, AuraEffect* aura, bool apply)
{
// ignore spell mods for not wands
- Modifier const* modifier = aura->GetModifier();
- if((modifier->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)==0 && (getClassMask() & CLASSMASK_WAND_USERS)==0)
+ if((aura->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)==0 && (getClassMask() & CLASSMASK_WAND_USERS)==0)
return;
// generic not weapon specific case processes in aura code
@@ -6868,7 +6818,7 @@ void Player::_ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType att
}
UnitModifierType unitModType = TOTAL_VALUE;
- switch(modifier->m_auraname)
+ switch(aura->GetAuraName())
{
case SPELL_AURA_MOD_DAMAGE_DONE: unitModType = TOTAL_VALUE; break;
case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: unitModType = TOTAL_PCT; break;
@@ -6877,7 +6827,7 @@ void Player::_ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType att
if (item->IsFitToSpellRequirements(aura->GetSpellProto()))
{
- HandleStatModifier(unitMod, unitModType, float(aura->GetModifierValue()),apply);
+ HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()),apply);
}
}
@@ -6890,7 +6840,7 @@ void Player::ApplyItemEquipSpell(Item *item, bool apply, bool form_change)
if(!proto)
return;
- for (int i = 0; i < 5; i++)
+ for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = proto->Spells[i];
@@ -6916,29 +6866,15 @@ void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply
if(apply)
{
// Cannot be used in this stance/form
- if(GetErrorAtShapeshiftedCast(spellInfo, m_form)!=0)
+ if(GetErrorAtShapeshiftedCast(spellInfo, m_form) != SPELL_CAST_OK)
return;
if(form_change) // check aura active state from other form
{
- bool found = false;
- for (int k=0; k < 3; ++k)
- {
- spellEffectPair spair = spellEffectPair(spellInfo->Id, k);
- for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair); ++iter)
- {
- if(!item || iter->second->GetCastItemGUID() == item->GetGUID())
- {
- found = true;
- break;
- }
- }
- if(found)
- break;
- }
-
- if(found) // and skip re-cast already active aura at form change
- return;
+ AuraMap const& auras = GetAuras();
+ for(AuraMap::const_iterator itr = auras.lower_bound(spellInfo->Id); itr != auras.upper_bound(spellInfo->Id); ++itr)
+ if(!item || itr->second->GetCastItemGUID()==item->GetGUID())
+ return;
}
DEBUG_LOG("WORLD: cast %s Equip spellId - %i", (item ? "item" : "itemset"), spellInfo->Id);
@@ -6950,7 +6886,7 @@ void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply
if(form_change) // check aura compatibility
{
// Cannot be used in this stance/form
- if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==0)
+ if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==SPELL_CAST_OK)
return; // and remove only not compatible at form change
}
@@ -7030,7 +6966,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
if(spellData.SpellPPMRate)
{
uint32 WeaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate);
+ chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate, spellInfo);
}
else if(chance > 100.0f)
{
@@ -7080,7 +7016,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
if (entry && entry->PPMChance)
{
uint32 WeaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(WeaponSpeed, entry->PPMChance);
+ chance = GetPPMProcChance(WeaponSpeed, entry->PPMChance, spellInfo);
}
else if (entry && entry->customChance)
chance = entry->customChance;
@@ -7099,6 +7035,92 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
}
}
+void Player::CastItemUseSpell(Item *item,SpellCastTargets const& targets,uint8 cast_count, uint32 glyphIndex)
+{
+ ItemPrototype const* proto = item->GetProto();
+ // special learning case
+ if(proto->Spells[0].SpellId==SPELL_ID_GENERIC_LEARN || proto->Spells[0].SpellId==SPELL_ID_GENERIC_LEARN_PET)
+ {
+ uint32 learn_spell_id = proto->Spells[0].SpellId;
+ uint32 learning_spell_id = proto->Spells[1].SpellId;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(learn_spell_id);
+ if(!spellInfo)
+ {
+ sLog.outError("Player::CastItemUseSpell: Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, learn_spell_id);
+ SendEquipError(EQUIP_ERR_NONE,item,NULL);
+ return;
+ }
+
+ Spell *spell = new Spell(this, spellInfo,false);
+ spell->m_CastItem = item;
+ spell->m_cast_count = cast_count; //set count of casts
+ spell->m_currentBasePoints[0] = learning_spell_id;
+ spell->prepare(&targets);
+ return;
+ }
+
+ // use triggered flag only for items with many spell casts and for not first cast
+ int count = 0;
+
+ // item spells casted at use
+ for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
+ {
+ _Spell const& spellData = proto->Spells[i];
+
+ // no spell
+ if(!spellData.SpellId)
+ continue;
+
+ // wrong triggering type
+ if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
+ continue;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId);
+ if(!spellInfo)
+ {
+ sLog.outError("Player::CastItemUseSpell: Item (Entry: %u) in have wrong spell id %u, ignoring",proto->ItemId, spellData.SpellId);
+ continue;
+ }
+
+ Spell *spell = new Spell(this, spellInfo, (count > 0));
+ spell->m_CastItem = item;
+ spell->m_cast_count = cast_count; // set count of casts
+ spell->m_glyphIndex = glyphIndex; // glyph index
+ spell->prepare(&targets);
+
+ ++count;
+ }
+
+ // Item enchantments spells casted at use
+ for(int e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot)
+ {
+ uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot));
+ SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
+ if(!pEnchant) continue;
+ for (int s=0;s<3;s++)
+ {
+ if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_USE_SPELL)
+ continue;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(pEnchant->spellid[s]);
+ if (!spellInfo)
+ {
+ sLog.outError("Player::CastItemUseSpell Enchant %i, cast unknown spell %i", pEnchant->ID, pEnchant->spellid[s]);
+ continue;
+ }
+
+ Spell *spell = new Spell(this, spellInfo, (count > 0));
+ spell->m_CastItem = item;
+ spell->m_cast_count = cast_count; // set count of casts
+ spell->m_glyphIndex = glyphIndex; // glyph index
+ spell->prepare(&targets);
+
+ ++count;
+ }
+ }
+}
+
void Player::_RemoveAllItemMods()
{
sLog.outDebug("_RemoveAllItemMods start.");
@@ -7288,12 +7310,6 @@ void Player::RemovedInsignia(Player* looterPlr)
looterPlr->SendLoot(bones->GetGUID(), LOOT_INSIGNIA);
}
-/*Loot type MUST be
-1-corpse, go
-2-skinning
-3-Fishing
-*/
-
void Player::SendLootRelease( uint64 guid )
{
WorldPacket data( SMSG_LOOT_RELEASE_RESPONSE, (8+1) );
@@ -7303,6 +7319,9 @@ void Player::SendLootRelease( uint64 guid )
void Player::SendLoot(uint64 guid, LootType loot_type)
{
+ if (uint64 lguid = GetLootGUID())
+ m_session->DoLootRelease(lguid);
+
Loot *loot = 0;
PermissionTypes permission = ALL_PERMISSION;
@@ -7310,8 +7329,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
if (IS_GAMEOBJECT_GUID(guid))
{
sLog.outDebug(" IS_GAMEOBJECT_GUID(guid)");
- GameObject *go =
- ObjectAccessor::GetGameObject(*this, guid);
+ GameObject *go = GetMap()->GetGameObject(guid);
// not check distance for GO in case owned GO (fishing bobber case, for example)
// And permit out of range GO with no owner in case fishing hole
@@ -7323,7 +7341,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
loot = &go->loot;
- if(go->getLootState() == GO_READY)
+ if (go->getLootState() == GO_READY)
{
uint32 lootid = go->GetLootId();
@@ -7337,15 +7355,15 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
return;
}
- if(lootid)
+ if (lootid)
{
sLog.outDebug(" if(lootid)");
loot->clear();
- loot->FillLoot(lootid, LootTemplates_Gameobject, this);
+ loot->FillLoot(lootid, LootTemplates_Gameobject, this, false);
}
- if(loot_type == LOOT_FISHING)
- go->getFishLoot(loot);
+ if (loot_type == LOOT_FISHING)
+ go->getFishLoot(loot,this);
go->SetLootState(GO_ACTIVATED);
}
@@ -7360,39 +7378,28 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
return;
}
- if(loot_type == LOOT_DISENCHANTING)
- {
- loot = &item->loot;
+ loot = &item->loot;
- if(!item->m_lootGenerated)
- {
- item->m_lootGenerated = true;
- loot->clear();
- loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this);
- }
- }
- else if(loot_type == LOOT_PROSPECTING)
+ if (!item->m_lootGenerated)
{
- loot = &item->loot;
+ item->m_lootGenerated = true;
+ loot->clear();
- if(!item->m_lootGenerated)
+ switch(loot_type)
{
- item->m_lootGenerated = true;
- loot->clear();
- loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this);
- }
- }
- else
- {
- loot = &item->loot;
-
- if(!item->m_lootGenerated)
- {
- item->m_lootGenerated = true;
- loot->clear();
- loot->FillLoot(item->GetEntry(), LootTemplates_Item, this);
-
- loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot);
+ case LOOT_DISENCHANTING:
+ loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this,true);
+ break;
+ case LOOT_PROSPECTING:
+ loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this,true);
+ break;
+ case LOOT_MILLING:
+ loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this,true);
+ break;
+ default:
+ loot->FillLoot(item->GetEntry(), LootTemplates_Item, this,true);
+ loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot);
+ break;
}
}
}
@@ -7414,7 +7421,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
uint32 pLevel = bones->loot.gold;
bones->loot.clear();
if(GetBattleGround()->GetTypeID() == BATTLEGROUND_AV)
- loot->FillLoot(1, LootTemplates_Creature, this);
+ loot->FillLoot(1, LootTemplates_Creature, this, true);
// It may need a better formula
// Now it works like this: lvl10: ~6copper, lvl70: ~9silver
bones->loot.gold = (uint32)( urand(50, 150) * 0.016f * pow( ((float)pLevel)/5.76f, 2.5f) * sWorld.getRate(RATE_DROP_MONEY) );
@@ -7425,7 +7432,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
}
else
{
- Creature *creature = ObjectAccessor::GetCreature(*this, guid);
+ Creature *creature = GetMap()->GetCreature(guid);
// must be in range and creature must be alive for pickpocket and must be dead for another loot
if (!creature || creature->isAlive()!=(loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this,INTERACTION_DISTANCE))
@@ -7434,7 +7441,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
return;
}
- if(loot_type == LOOT_PICKPOCKETING && IsFriendlyTo(creature))
+ if (loot_type == LOOT_PICKPOCKETING && IsFriendlyTo(creature))
{
SendLootRelease(guid);
return;
@@ -7442,15 +7449,15 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
loot = &creature->loot;
- if(loot_type == LOOT_PICKPOCKETING)
+ if (loot_type == LOOT_PICKPOCKETING)
{
- if ( !creature->lootForPickPocketed )
+ if (!creature->lootForPickPocketed)
{
creature->lootForPickPocketed = true;
loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId)
- loot->FillLoot(lootid, LootTemplates_Pickpocketing, this);
+ loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, false);
// Generate extra money for pick pocket loot
const uint32 a = urand(0, creature->getLevel()/2);
@@ -7474,17 +7481,17 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
loot->clear();
}
- if(!creature->lootForBody)
+ if (!creature->lootForBody)
{
creature->lootForBody = true;
loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->lootid)
- loot->FillLoot(lootid, LootTemplates_Creature, recipient);
+ loot->FillLoot(lootid, LootTemplates_Creature, recipient, false);
loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold,creature->GetCreatureInfo()->maxgold);
- if(Group* group = recipient->GetGroup())
+ if (Group* group = recipient->GetGroup())
{
group->UpdateLooterGuid(creature,true);
@@ -7510,20 +7517,20 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
if (loot_type == LOOT_SKINNING)
{
loot->clear();
- loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this);
+ loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this, false);
}
// set group rights only for loot_type != LOOT_SKINNING
else
{
if(Group* group = GetGroup())
{
- if( group == recipient->GetGroup() )
+ if (group == recipient->GetGroup())
{
- if(group->GetLootMethod() == FREE_FOR_ALL)
+ if (group->GetLootMethod() == FREE_FOR_ALL)
permission = ALL_PERMISSION;
- else if(group->GetLooterGuid() == GetGUID())
+ else if (group->GetLooterGuid() == GetGUID())
{
- if(group->GetLootMethod() == MASTER_LOOT)
+ if (group->GetLootMethod() == MASTER_LOOT)
permission = MASTER_PERMISSION;
else
permission = ALL_PERMISSION;
@@ -7534,7 +7541,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
else
permission = NONE_PERMISSION;
}
- else if(recipient == this)
+ else if (recipient == this)
permission = ALL_PERMISSION;
else
permission = NONE_PERMISSION;
@@ -7544,51 +7551,22 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
SetLootGUID(guid);
- QuestItemList *q_list = 0;
- if (permission != NONE_PERMISSION)
+ // LOOT_INSIGNIA and LOOT_FISHINGHOLE unsupported by client
+ switch(loot_type)
{
- QuestItemMap const& lootPlayerQuestItems = loot->GetPlayerQuestItems();
- QuestItemMap::const_iterator itr = lootPlayerQuestItems.find(GetGUIDLow());
- if (itr == lootPlayerQuestItems.end())
- q_list = loot->FillQuestLoot(this);
- else
- q_list = itr->second;
- }
-
- QuestItemList *ffa_list = 0;
- if (permission != NONE_PERMISSION)
- {
- QuestItemMap const& lootPlayerFFAItems = loot->GetPlayerFFAItems();
- QuestItemMap::const_iterator itr = lootPlayerFFAItems.find(GetGUIDLow());
- if (itr == lootPlayerFFAItems.end())
- ffa_list = loot->FillFFALoot(this);
- else
- ffa_list = itr->second;
- }
-
- QuestItemList *conditional_list = 0;
- if (permission != NONE_PERMISSION)
- {
- QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = loot->GetPlayerNonQuestNonFFAConditionalItems();
- QuestItemMap::const_iterator itr = lootPlayerNonQuestNonFFAConditionalItems.find(GetGUIDLow());
- if (itr == lootPlayerNonQuestNonFFAConditionalItems.end())
- conditional_list = loot->FillNonQuestNonFFAConditionalLoot(this);
- else
- conditional_list = itr->second;
+ case LOOT_INSIGNIA: loot_type = LOOT_SKINNING; break;
+ case LOOT_FISHINGHOLE: loot_type = LOOT_FISHING; break;
+ default: break;
}
- // LOOT_PICKPOCKETING, LOOT_PROSPECTING, LOOT_DISENCHANTING and LOOT_INSIGNIA unsupported by client, sending LOOT_SKINNING instead
- if(loot_type == LOOT_PICKPOCKETING || loot_type == LOOT_DISENCHANTING || loot_type == LOOT_PROSPECTING || loot_type == LOOT_INSIGNIA)
- loot_type = LOOT_SKINNING;
-
- if(loot_type == LOOT_FISHINGHOLE)
- loot_type = LOOT_FISHING;
+ // need know merged fishing/corpse loot type for achievements
+ loot->loot_type = loot_type;
WorldPacket data(SMSG_LOOT_RESPONSE, (9+50)); // we guess size
data << uint64(guid);
data << uint8(loot_type);
- data << LootView(*loot, q_list, ffa_list, conditional_list, this, permission);
+ data << LootView(*loot, this, permission);
SendDirectMessage(&data);
@@ -7596,7 +7574,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
if (permission != NONE_PERMISSION)
loot->AddLooter(GetGUID());
- if ( loot_type == LOOT_CORPSE && !IS_ITEM_GUID(guid) )
+ if (loot_type == LOOT_CORPSE && !IS_ITEM_GUID(guid))
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING);
}
@@ -7621,20 +7599,16 @@ void Player::SendUpdateWorldState(uint32 Field, uint32 Value)
GetSession()->SendPacket(&data);
}
-void Player::SendInitWorldStates(bool forceZone, uint32 forceZoneId)
+void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
{
// data depends on zoneid/mapid...
BattleGround* bg = GetBattleGround();
uint16 NumberOfFields = 0;
uint32 mapid = GetMapId();
- uint32 zoneid;
- if(forceZone)
- zoneid = forceZoneId;
- else
- zoneid = GetZoneId();
OutdoorPvP * pvp = sOutdoorPvPMgr.GetOutdoorPvPToZoneId(zoneid);
- uint32 areaid = GetAreaId();
+
sLog.outDebug("Sending SMSG_INIT_WORLD_STATES to Map:%u, Zone: %u", mapid, zoneid);
+
// may be exist better way to do this...
switch(zoneid)
{
@@ -7655,46 +7629,46 @@ void Player::SendInitWorldStates(bool forceZone, uint32 forceZoneId)
case 1537:
case 2257:
case 2918:
- NumberOfFields = 6;
+ NumberOfFields = 8;
break;
case 139:
- NumberOfFields = 39;
+ NumberOfFields = 41;
break;
case 1377:
- NumberOfFields = 13;
+ NumberOfFields = 15;
break;
case 2597:
- NumberOfFields = 81;
+ NumberOfFields = 83;
break;
case 3277:
- NumberOfFields = 14;
+ NumberOfFields = 16;
break;
case 3358:
case 3820:
- NumberOfFields = 38;
+ NumberOfFields = 40;
break;
case 3483:
- NumberOfFields = 25;
+ NumberOfFields = 27;
break;
case 3518:
- NumberOfFields = 37;
+ NumberOfFields = 39;
break;
case 3519:
- NumberOfFields = 36;
+ NumberOfFields = 38;
break;
case 3521:
- NumberOfFields = 35;
+ NumberOfFields = 37;
break;
case 3698:
case 3702:
case 3968:
- NumberOfFields = 9;
+ NumberOfFields = 11;
break;
case 3703:
- NumberOfFields = 9;
+ NumberOfFields = 11;
break;
default:
- NumberOfFields = 10;
+ NumberOfFields = 12;
break;
}
@@ -7709,6 +7683,10 @@ void Player::SendInitWorldStates(bool forceZone, uint32 forceZoneId)
data << uint32(0x8d5) << uint32(0x0); // 4
data << uint32(0x8d4) << uint32(0x0); // 5
data << uint32(0x8d3) << uint32(0x0); // 6
+ // 7 1 - Arena season in progress, 0 - end of season
+ data << uint32(0xC77) << uint32(sWorld.getConfig(CONFIG_ARENA_SEASON_IN_PROGRESS));
+ // 8 Arena season id
+ data << uint32(0xF3D) << uint32(sWorld.getConfig(CONFIG_ARENA_SEASON_ID));
if(mapid == 530) // Outland
{
data << uint32(0x9bf) << uint32(0x0); // 7
@@ -8302,7 +8280,8 @@ uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap
// (this will be replace mainhand weapon at auto equip instead unwonted "you don't known dual wielding" ...
if(CanDualWield())
slots[1] = EQUIPMENT_SLOT_OFFHAND;
- };break;
+ break;
+ };
case INVTYPE_SHIELD:
slots[0] = EQUIPMENT_SLOT_OFFHAND;
break;
@@ -8311,6 +8290,8 @@ uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap
break;
case INVTYPE_2HWEAPON:
slots[0] = EQUIPMENT_SLOT_MAINHAND;
+ if (CanDualWield() && CanTitanGrip())
+ slots[1] = EQUIPMENT_SLOT_OFFHAND;
break;
case INVTYPE_TABARD:
slots[0] = EQUIPMENT_SLOT_TABARD;
@@ -8331,10 +8312,10 @@ uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap
slots[0] = EQUIPMENT_SLOT_RANGED;
break;
case INVTYPE_BAG:
- slots[0] = INVENTORY_SLOT_BAG_1;
- slots[1] = INVENTORY_SLOT_BAG_2;
- slots[2] = INVENTORY_SLOT_BAG_3;
- slots[3] = INVENTORY_SLOT_BAG_4;
+ slots[0] = INVENTORY_SLOT_BAG_START + 0;
+ slots[1] = INVENTORY_SLOT_BAG_START + 1;
+ slots[2] = INVENTORY_SLOT_BAG_START + 2;
+ slots[3] = INVENTORY_SLOT_BAG_START + 3;
break;
case INVTYPE_RELIC:
{
@@ -8356,6 +8337,10 @@ uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap
if (pClass == CLASS_WARLOCK)
slots[0] = EQUIPMENT_SLOT_RANGED;
break;
+ case ITEM_SUBCLASS_ARMOR_SIGIL:
+ if (pClass == CLASS_DEATH_KNIGHT)
+ slots[0] = EQUIPMENT_SLOT_RANGED;
+ break;
}
break;
}
@@ -8381,14 +8366,8 @@ uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap
{
if ( slots[i] != NULL_SLOT && !GetItemByPos( INVENTORY_SLOT_BAG_0, slots[i] ) )
{
- // in case 2hand equipped weapon offhand slot empty but not free
- if(slots[i]==EQUIPMENT_SLOT_OFFHAND)
- {
- Item* mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND );
- if(!mainItem || mainItem->GetProto()->InventoryType != INVTYPE_2HWEAPON)
- return slots[i];
- }
- else
+ // in case 2hand equipped weapon (without titan grip) offhand slot empty but not free
+ if(slots[i]!=EQUIPMENT_SLOT_OFFHAND || !IsTwoHandUsed())
return slots[i];
}
}
@@ -8438,7 +8417,7 @@ uint8 Player::CanUnequipItems( uint32 item, uint32 count ) const
return EQUIP_ERR_OK;
}
}
- for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
+ for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->GetEntry() == item )
@@ -8480,7 +8459,7 @@ uint32 Player::GetItemCount( uint32 item, bool inBankAlso, Item* skipItem ) cons
if( pItem && pItem != skipItem && pItem->GetEntry() == item )
count += pItem->GetCount();
}
- for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
+ for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem != skipItem && pItem->GetEntry() == item )
@@ -8540,7 +8519,7 @@ Item* Player::GetItemByGuid( uint64 guid ) const
if( pItem && pItem->GetGUID() == guid )
return pItem;
}
- for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
+ for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->GetGUID() == guid )
@@ -8586,7 +8565,7 @@ Item* Player::GetItemByPos( uint16 pos ) const
Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const
{
- if( bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END || slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END ) )
+ if( bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END || slot >= KEYRING_SLOT_START && slot < QUESTBAG_SLOT_END ) )
return m_items[slot];
else if(bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END
|| bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END )
@@ -8609,14 +8588,14 @@ Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable) cons
default: return NULL;
}
- Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
+ Item* item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, slot);
if (!item || item->GetProto()->Class != ITEM_CLASS_WEAPON)
return NULL;
if(!useable)
return item;
- if( item->IsBroken() || !IsUseEquipedWeapon(attackType==BASE_ATTACK) )
+ if( item->IsBroken() || IsInFeralForm())
return NULL;
return item;
@@ -8624,7 +8603,7 @@ Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable) cons
Item* Player::GetShield(bool useable) const
{
- Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ Item* item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (!item || item->GetProto()->Class != ITEM_CLASS_ARMOR)
return NULL;
@@ -8637,7 +8616,7 @@ Item* Player::GetShield(bool useable) const
return item;
}
-uint32 Player::GetAttackBySlot( uint8 slot )
+uint8 Player::GetAttackBySlot( uint8 slot )
{
switch(slot)
{
@@ -8648,14 +8627,6 @@ uint32 Player::GetAttackBySlot( uint8 slot )
}
}
-bool Player::HasBankBagSlot( uint8 slot ) const
-{
- uint32 maxslot = GetByteValue(PLAYER_BYTES_2, 2) + BANK_SLOT_BAG_START;
- if( slot < maxslot )
- return true;
- return false;
-}
-
bool Player::IsInventoryPos( uint8 bag, uint8 slot )
{
if( bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT )
@@ -8664,7 +8635,7 @@ bool Player::IsInventoryPos( uint8 bag, uint8 slot )
return true;
if( bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END )
return true;
- if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END ) )
+ if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= KEYRING_SLOT_START && slot < QUESTBAG_SLOT_END ) )
return true;
return false;
}
@@ -8785,7 +8756,7 @@ bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const
return true;
}
}
- for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
+ for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && pItem->GetEntry() == item )
@@ -8845,31 +8816,76 @@ bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const
return false;
}
-Item* Player::GetItemOrItemWithGemEquipped( uint32 item ) const
+bool Player::HasItemOrGemWithIdEquipped( uint32 item, uint32 count, uint8 except_slot ) const
{
- Item *pItem;
- for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
+ uint32 tempcount = 0;
+ for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
{
- pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->GetEntry() == item )
- return pItem;
+ if(i==int(except_slot))
+ continue;
+
+ Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+ if( pItem && pItem->GetEntry() == item)
+ {
+ tempcount += pItem->GetCount();
+ if( tempcount >= count )
+ return true;
+ }
}
ItemPrototype const *pProto = objmgr.GetItemPrototype(item);
if (pProto && pProto->GemProperties)
{
- for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
+ for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
{
- pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->GetProto()->Socket[0].Color )
+ if(i==int(except_slot))
+ continue;
+
+ Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+ if( pItem && pItem->GetProto()->Socket[0].Color)
{
- if (pItem->GetGemCountWithID(item) > 0 )
- return pItem;
+ tempcount += pItem->GetGemCountWithID(item);
+ if( tempcount >= count )
+ return true;
}
}
}
- return NULL;
+ return false;
+}
+
+bool Player::HasItemOrGemWithLimitCategoryEquipped( uint32 limitCategory, uint32 count, uint8 except_slot ) const
+{
+ uint32 tempcount = 0;
+ for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
+ {
+ if(i==int(except_slot))
+ continue;
+
+ Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+ if (!pItem)
+ continue;
+
+ ItemPrototype const *pProto = pItem->GetProto();
+ if (!pProto)
+ continue;
+
+ if (pProto->ItemLimitCategory == limitCategory)
+ {
+ tempcount += pItem->GetCount();
+ if( tempcount >= count )
+ return true;
+ }
+
+ if( pProto->Socket[0].Color)
+ {
+ tempcount += pItem->GetGemCountWithLimitCategory(limitCategory);
+ if( tempcount >= count )
+ return true;
+ }
+ }
+
+ return false;
}
uint8 Player::_CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count ) const
@@ -8883,12 +8899,12 @@ uint8 Player::_CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem,
}
// no maximum
- if(pProto->MaxCount == 0)
+ if(pProto->MaxCount <= 0)
return EQUIP_ERR_OK;
uint32 curcount = GetItemCount(pProto->ItemId,true,pItem);
- if( curcount + count > pProto->MaxCount )
+ if (curcount + count > uint32(pProto->MaxCount))
{
if(no_space_count)
*no_space_count = count +curcount - pProto->MaxCount;
@@ -8903,13 +8919,13 @@ bool Player::HasItemTotemCategory( uint32 TotemCategory ) const
Item *pItem;
for(uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
{
- pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+ pItem = GetUseableItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory ))
return true;
}
- for(uint8 i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i)
+ for(uint8 i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; ++i)
{
- pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+ pItem = GetUseableItemByPos( INVENTORY_SLOT_BAG_0, i );
if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory ))
return true;
}
@@ -8919,7 +8935,7 @@ bool Player::HasItemTotemCategory( uint32 TotemCategory ) const
{
for(uint32 j = 0; j < pBag->GetBagSize(); ++j)
{
- pItem = GetItemByPos( i, j );
+ pItem = GetUseableItemByPos( i, j );
if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory ))
return true;
}
@@ -8947,6 +8963,18 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
if(slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
+ // vanitypet case (not use, vanity pets stored as spells)
+ if(slot >= VANITYPET_SLOT_START && slot < VANITYPET_SLOT_END)
+ return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
+
+ // currencytoken case (disabled until proper implement)
+ if(slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS))
+ return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
+
+ // guestbag case (not use)
+ if(slot >= QUESTBAG_SLOT_START && slot < QUESTBAG_SLOT_END)
+ return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
+
// prevent cheating
if(slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
@@ -8966,7 +8994,7 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
}
// non empty stack with space
- need_space = pProto->Stackable;
+ need_space = pProto->GetMaxStackSize();
}
// non empty slot, check item type
else
@@ -8976,10 +9004,11 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
return EQUIP_ERR_ITEM_CANT_STACK;
// check free space
- if(pItem2->GetCount() >= pProto->Stackable)
+ if(pItem2->GetCount() >= pProto->GetMaxStackSize())
return EQUIP_ERR_ITEM_CANT_STACK;
- need_space = pProto->Stackable - pItem2->GetCount();
+ // free stack space or infinity
+ need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
}
if(need_space > count)
@@ -9033,9 +9062,9 @@ uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototy
if( pItem2 )
{
- if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->Stackable )
+ if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
{
- uint32 need_space = pProto->Stackable - pItem2->GetCount();
+ uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
if(need_space > count)
need_space = count;
@@ -9052,7 +9081,7 @@ uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototy
}
else
{
- uint32 need_space = pProto->Stackable;
+ uint32 need_space = pProto->GetMaxStackSize();
if(need_space > count)
need_space = count;
@@ -9090,9 +9119,9 @@ uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end,
if( pItem2 )
{
- if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->Stackable )
+ if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
{
- uint32 need_space = pProto->Stackable - pItem2->GetCount();
+ uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
if(need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space);
@@ -9108,7 +9137,7 @@ uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end,
}
else
{
- uint32 need_space = pProto->Stackable;
+ uint32 need_space = pProto->GetMaxStackSize();
if(need_space > count)
need_space = count;
@@ -9187,11 +9216,11 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
if( bag != NULL_BAG )
{
// search stack in bag for merge to
- if( pProto->Stackable > 1 )
+ if( pProto->Stackable != 1 )
{
if( bag == INVENTORY_SLOT_BAG_0 ) // inventory
{
- res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_END,dest,pProto,count,true,pItem,bag,slot);
+ res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,QUESTBAG_SLOT_END,dest,pProto,count,true,pItem,bag,slot);
if(res!=EQUIP_ERR_OK)
{
if(no_space_count)
@@ -9277,6 +9306,44 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
+
+ res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
+ if(res!=EQUIP_ERR_OK)
+ {
+ if(no_space_count)
+ *no_space_count = count + no_similar_count;
+ return res;
+ }
+
+ if(count==0)
+ {
+ if(no_similar_count==0)
+ return EQUIP_ERR_OK;
+
+ if(no_space_count)
+ *no_space_count = count + no_similar_count;
+ return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
+ }
+ }
+ else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
+ {
+ res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
+ if(res!=EQUIP_ERR_OK)
+ {
+ if(no_space_count)
+ *no_space_count = count + no_similar_count;
+ return res;
+ }
+
+ if(count==0)
+ {
+ if(no_similar_count==0)
+ return EQUIP_ERR_OK;
+
+ if(no_space_count)
+ *no_space_count = count + no_similar_count;
+ return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
+ }
}
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot);
@@ -9325,9 +9392,9 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// not specific bag or have space for partly store only in specific bag
// search stack for merge to
- if( pProto->Stackable > 1 )
+ if( pProto->Stackable != 1 )
{
- res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_END,dest,pProto,count,true,pItem,bag,slot);
+ res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,QUESTBAG_SLOT_END,dest,pProto,count,true,pItem,bag,slot);
if(res!=EQUIP_ERR_OK)
{
if(no_space_count)
@@ -9425,6 +9492,26 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
+ else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
+ {
+ res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
+ if(res!=EQUIP_ERR_OK)
+ {
+ if(no_space_count)
+ *no_space_count = count + no_similar_count;
+ return res;
+ }
+
+ if(count==0)
+ {
+ if(no_similar_count==0)
+ return EQUIP_ERR_OK;
+
+ if(no_space_count)
+ *no_space_count = count + no_similar_count;
+ return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
+ }
+ }
for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
@@ -9495,10 +9582,12 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
int inv_slot_items[INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START];
int inv_bags[INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE];
int inv_keys[KEYRING_SLOT_END-KEYRING_SLOT_START];
+ int inv_tokens[CURRENCYTOKEN_SLOT_END-CURRENCYTOKEN_SLOT_START];
memset(inv_slot_items,0,sizeof(int)*(INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START));
memset(inv_bags,0,sizeof(int)*(INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START)*MAX_BAG_SIZE);
memset(inv_keys,0,sizeof(int)*(KEYRING_SLOT_END-KEYRING_SLOT_START));
+ memset(inv_tokens,0,sizeof(int)*(CURRENCYTOKEN_SLOT_END-CURRENCYTOKEN_SLOT_START));
for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
{
@@ -9520,6 +9609,16 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
}
}
+ for(int i = CURRENCYTOKEN_SLOT_START; i < CURRENCYTOKEN_SLOT_END; i++)
+ {
+ pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
+
+ if (pItem2 && !pItem2->IsInTrade())
+ {
+ inv_tokens[i-CURRENCYTOKEN_SLOT_START] = pItem2->GetCount();
+ }
+ }
+
for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
@@ -9563,14 +9662,14 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
return res;
// search stack for merge to
- if( pProto->Stackable > 1 )
+ if( pProto->Stackable != 1 )
{
bool b_found = false;
for(int t = KEYRING_SLOT_START; t < KEYRING_SLOT_END; t++)
{
pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t );
- if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_keys[t-KEYRING_SLOT_START] + pItem->GetCount() <= pProto->Stackable )
+ if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_keys[t-KEYRING_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize())
{
inv_keys[t-KEYRING_SLOT_START] += pItem->GetCount();
b_found = true;
@@ -9579,10 +9678,22 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
}
if (b_found) continue;
+ for(int t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; t++)
+ {
+ pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t );
+ if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_tokens[t-CURRENCYTOKEN_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize())
+ {
+ inv_tokens[t-CURRENCYTOKEN_SLOT_START] += pItem->GetCount();
+ b_found = true;
+ break;
+ }
+ }
+ if (b_found) continue;
+
for(int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; t++)
{
pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t );
- if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_slot_items[t-INVENTORY_SLOT_ITEM_START] + pItem->GetCount() <= pProto->Stackable )
+ if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_slot_items[t-INVENTORY_SLOT_ITEM_START] + pItem->GetCount() <= pProto->GetMaxStackSize())
{
inv_slot_items[t-INVENTORY_SLOT_ITEM_START] += pItem->GetCount();
b_found = true;
@@ -9594,12 +9705,12 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++)
{
pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t );
- if( pBag )
+ if( pBag && ItemCanGoIntoBag(pItem->GetProto(), pBag->GetProto()))
{
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
{
pItem2 = GetItemByPos( t, j );
- if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_bags[t-INVENTORY_SLOT_BAG_START][j] + pItem->GetCount() <= pProto->Stackable )
+ if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_bags[t-INVENTORY_SLOT_BAG_START][j] + pItem->GetCount() <= pProto->GetMaxStackSize())
{
inv_bags[t-INVENTORY_SLOT_BAG_START][j] += pItem->GetCount();
b_found = true;
@@ -9631,6 +9742,21 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
if (b_found) continue;
+ if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
+ {
+ for(uint32 t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; ++t)
+ {
+ if( inv_tokens[t-CURRENCYTOKEN_SLOT_START] == 0 )
+ {
+ inv_tokens[t-CURRENCYTOKEN_SLOT_START] = 1;
+ b_found = true;
+ break;
+ }
+ }
+ }
+
+ if (b_found) continue;
+
for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++)
{
pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t );
@@ -9726,11 +9852,6 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
ItemPrototype const *pProto = pItem->GetProto();
if( pProto )
{
- // May be here should be more stronger checks; STUNNED checked
- // ROOT, CONFUSED, DISTRACTED, FLEEING this needs to be checked.
- if (not_loading && hasUnitState(UNIT_STAT_STUNNED))
- return EQUIP_ERR_YOU_ARE_STUNNED;
-
if(pItem->IsBindedNotWith(GetGUID()))
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
@@ -9739,78 +9860,67 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
if(res != EQUIP_ERR_OK)
return res;
- // do not allow equipping gear except weapons, offhands, projectiles, relics in
- // - combat
- // - in-progress arenas
- if( !pProto->CanChangeEquipStateInCombat() )
+ // check this only in game
+ if(not_loading)
{
- if( isInCombat() )
- return EQUIP_ERR_NOT_IN_COMBAT;
+ // May be here should be more stronger checks; STUNNED checked
+ // ROOT, CONFUSED, DISTRACTED, FLEEING this needs to be checked.
+ if (hasUnitState(UNIT_STAT_STUNNED))
+ return EQUIP_ERR_YOU_ARE_STUNNED;
+
+ // do not allow equipping gear except weapons, offhands, projectiles, relics in
+ // - combat
+ // - in-progress arenas
+ if( !pProto->CanChangeEquipStateInCombat() )
+ {
+ if( isInCombat() )
+ return EQUIP_ERR_NOT_IN_COMBAT;
- if(BattleGround* bg = GetBattleGround())
- if( bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS )
- return EQUIP_ERR_NOT_DURING_ARENA_MATCH;
- }
+ if(BattleGround* bg = GetBattleGround())
+ if( bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS )
+ return EQUIP_ERR_NOT_DURING_ARENA_MATCH;
+ }
- if(isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer != 0)
- return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err
+ if(isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer != 0)
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err
- if(IsNonMeleeSpellCasted(false))
- return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+ if(IsNonMeleeSpellCasted(false))
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+ }
+
+ ScalingStatDistributionEntry const *ssd = pProto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(pProto->ScalingStatDistribution) : 0;
+ if (ssd && ssd->MaxLevel < getLevel())
+ return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
uint8 eslot = FindEquipSlot( pProto, slot, swap );
- if( eslot == NULL_SLOT )
+ if (eslot == NULL_SLOT)
return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
- uint8 msg = CanUseItem( pItem , not_loading );
- if( msg != EQUIP_ERR_OK )
+ uint8 msg = CanUseItem(pItem , not_loading);
+ if (msg != EQUIP_ERR_OK)
return msg;
- if( !swap && GetItemByPos( INVENTORY_SLOT_BAG_0, eslot ) )
+ if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot))
return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE;
- // check unique-equipped on item
- if (pProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
- {
- // there is an equip limit on this item
- Item* tItem = GetItemOrItemWithGemEquipped(pProto->ItemId);
- if (tItem && (!swap || tItem->GetSlot() != eslot ) )
- return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
- }
-
- // check unique-equipped on gems
- for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
- {
- uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
- if(!enchant_id)
- continue;
- SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
- if(!enchantEntry)
- continue;
-
- ItemPrototype const* pGem = objmgr.GetItemPrototype(enchantEntry->GemID);
- if(pGem && (pGem->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED))
- {
- Item* tItem = GetItemOrItemWithGemEquipped(enchantEntry->GemID);
- if(tItem && (!swap || tItem->GetSlot() != eslot ))
- return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
- }
- }
+ // if swap ignore item (equipped also)
+ if (uint8 res2 = CanEquipUniqueItem(pItem, swap ? eslot : NULL_SLOT))
+ return res2;
// check unique-equipped special item classes
if (pProto->Class == ITEM_CLASS_QUIVER)
{
for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
{
- if( Item* pBag = GetItemByPos( INVENTORY_SLOT_BAG_0, i ) )
+ if (Item* pBag = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
- if( ItemPrototype const* pBagProto = pBag->GetProto() )
+ if (pBag != pItem)
{
- if( pBagProto->Class==pProto->Class && (!swap || pBag->GetSlot() != eslot ) )
+ if (ItemPrototype const* pBagProto = pBag->GetProto())
{
- if(pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH)
- return EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH;
- else
- return EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER;
+ if (pBagProto->Class==pProto->Class && (!swap || pBag->GetSlot() != eslot))
+ return (pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH)
+ ? EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH
+ : EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER;
}
}
}
@@ -9819,44 +9929,51 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
uint32 type = pProto->InventoryType;
- if(eslot == EQUIPMENT_SLOT_OFFHAND)
+ if (eslot == EQUIPMENT_SLOT_OFFHAND)
{
- if( type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND )
+ if (type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND)
{
- if(!CanDualWield())
+ if (!CanDualWield())
return EQUIP_ERR_CANT_DUAL_WIELD;
}
-
- Item *mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND );
- if(mainItem)
+ else if (type == INVTYPE_2HWEAPON)
{
- if(mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON)
- return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED;
+ if (!CanDualWield() || !CanTitanGrip())
+ return EQUIP_ERR_CANT_DUAL_WIELD;
}
+
+ if (IsTwoHandUsed())
+ return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED;
}
// equip two-hand weapon case (with possible unequip 2 items)
- if( type == INVTYPE_2HWEAPON )
+ if (type == INVTYPE_2HWEAPON)
{
- if(eslot != EQUIPMENT_SLOT_MAINHAND)
+ if (eslot == EQUIPMENT_SLOT_OFFHAND)
+ {
+ if (!CanTitanGrip())
+ return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
+ }
+ else if (eslot != EQUIPMENT_SLOT_MAINHAND)
return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
- // offhand item must can be stored in inventory for offhand item and it also must be unequipped
- Item *offItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND );
- ItemPosCountVec off_dest;
- if( offItem && (!not_loading ||
- CanUnequipItem(uint16(INVENTORY_SLOT_BAG_0) << 8 | EQUIPMENT_SLOT_OFFHAND,false) != EQUIP_ERR_OK ||
- CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ) != EQUIP_ERR_OK ) )
- return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_INVENTORY_FULL;
+ if (!CanTitanGrip())
+ {
+ // offhand item must can be stored in inventory for offhand item and it also must be unequipped
+ Item *offItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND );
+ ItemPosCountVec off_dest;
+ if (offItem && (!not_loading ||
+ CanUnequipItem(uint16(INVENTORY_SLOT_BAG_0) << 8 | EQUIPMENT_SLOT_OFFHAND,false) != EQUIP_ERR_OK ||
+ CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ) != EQUIP_ERR_OK ))
+ return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_INVENTORY_FULL;
+ }
}
dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot);
return EQUIP_ERR_OK;
}
}
- if( !swap )
- return EQUIP_ERR_ITEM_NOT_FOUND;
- else
- return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
+
+ return !swap ? EQUIP_ERR_ITEM_NOT_FOUND : EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
}
uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const
@@ -9898,57 +10015,44 @@ uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const
uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap, bool not_loading ) const
{
- if( !pItem )
+ if (!pItem)
return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND;
uint32 count = pItem->GetCount();
sLog.outDebug( "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
ItemPrototype const *pProto = pItem->GetProto();
- if( !pProto )
+ if (!pProto)
return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND;
- if( pItem->IsBindedNotWith(GetGUID()) )
+ if (pItem->IsBindedNotWith(GetGUID()))
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
// check count of items (skip for auto move for same player from bank)
uint8 res = CanTakeMoreSimilarItems(pItem);
- if(res != EQUIP_ERR_OK)
+ if (res != EQUIP_ERR_OK)
return res;
// in specific slot
- if( bag != NULL_BAG && slot != NULL_SLOT )
+ if (bag != NULL_BAG && slot != NULL_SLOT)
{
- if( pProto->InventoryType == INVTYPE_BAG )
- {
- Bag *pBag = (Bag*)pItem;
- if( pBag )
- {
- if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END )
- {
- if( !HasBankBagSlot( slot ) )
- return EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT;
- if( uint8 cantuse = CanUseItem( pItem, not_loading ) != EQUIP_ERR_OK )
- return cantuse;
- }
- else
- {
- if( !pBag->IsEmpty() )
- return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
- }
- }
- }
- else
+ if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)
{
- if( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END )
+ if (!pItem->IsBag())
return EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT;
+
+ if (slot - BANK_SLOT_BAG_START >= GetBankBagSlotCount())
+ return EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT;
+
+ if (uint8 cantuse = CanUseItem( pItem, not_loading ) != EQUIP_ERR_OK)
+ return cantuse;
}
res = _CanStoreItem_InSpecificSlot(bag,slot,dest,pProto,count,swap,pItem);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
return res;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
@@ -9965,7 +10069,7 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p
}
// search stack in bag for merge to
- if( pProto->Stackable > 1 )
+ if( pProto->Stackable != 1 )
{
if( bag == INVENTORY_SLOT_BAG_0 )
{
@@ -10017,7 +10121,7 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p
// not specific bag or have space for partly store only in specific bag
// search stack for merge to
- if( pProto->Stackable > 1 )
+ if( pProto->Stackable != 1 )
{
// in slots
res = _CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START,BANK_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot);
@@ -10088,38 +10192,49 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p
uint8 Player::CanUseItem( Item *pItem, bool not_loading ) const
{
- if( pItem )
+ if (pItem)
{
sLog.outDebug( "STORAGE: CanUseItem item = %u", pItem->GetEntry());
- if( !isAlive() && not_loading )
+
+ if (!isAlive() && not_loading)
return EQUIP_ERR_YOU_ARE_DEAD;
- //if( isStunned() )
+
+ //if (isStunned())
// return EQUIP_ERR_YOU_ARE_STUNNED;
+
ItemPrototype const *pProto = pItem->GetProto();
- if( pProto )
+ if (pProto)
{
- if( pItem->IsBindedNotWith(GetGUID()) )
+ if (pItem->IsBindedNotWith(GetGUID()))
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
- if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 )
+
+ if ((pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0)
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
- if( pItem->GetSkill() != 0 )
+
+ if (pItem->GetSkill() != 0)
{
- if( GetSkillValue( pItem->GetSkill() ) == 0 )
+ if (GetSkillValue( pItem->GetSkill() ) == 0)
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
}
- if( pProto->RequiredSkill != 0 )
+
+ if (pProto->RequiredSkill != 0)
{
- if( GetSkillValue( pProto->RequiredSkill ) == 0 )
+ if (GetSkillValue( pProto->RequiredSkill ) == 0)
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
- else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank )
+
+ if (GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank)
return EQUIP_ERR_ERR_CANT_EQUIP_SKILL;
}
- if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
+
+ if (pProto->RequiredSpell != 0 && !HasSpell(pProto->RequiredSpell))
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
- if( pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank )
+
+ if (pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
return EQUIP_ERR_CANT_EQUIP_REPUTATION;
- if( getLevel() < pProto->RequiredLevel )
+
+ if (getLevel() < pProto->RequiredLevel)
return EQUIP_ERR_CANT_EQUIP_LEVEL_I;
+
return EQUIP_ERR_OK;
}
}
@@ -10173,7 +10288,7 @@ uint8 Player::CanUseAmmo( uint32 item ) const
}
if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
- /*if( GetReputation() < pProto->RequiredReputation )
+ /*if( GetReputationMgr().GetReputation() < pProto->RequiredReputation )
return EQUIP_ERR_CANT_EQUIP_REPUTATION;
*/
if( getLevel() < pProto->RequiredLevel )
@@ -10247,7 +10362,7 @@ Item* Player::StoreItem( ItemPosCountVec const& dest, Item* pItem, bool update )
return NULL;
Item* lastItem = pItem;
-
+ uint32 entry = pItem->GetEntry();
for(ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); )
{
uint16 pos = itr->pos;
@@ -10263,7 +10378,7 @@ Item* Player::StoreItem( ItemPosCountVec const& dest, Item* pItem, bool update )
lastItem = _StoreItem(pos,pItem,count,true,update);
}
-
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, entry);
return lastItem;
}
@@ -10280,22 +10395,22 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo
Item *pItem2 = GetItemByPos( bag, slot );
- if( !pItem2 )
+ if (!pItem2)
{
- if(clone)
+ if (clone)
pItem = pItem->CloneItem(count,this);
else
pItem->SetCount(count);
- if(!pItem)
+ if (!pItem)
return NULL;
- if( pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP ||
+ if (pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP ||
pItem->GetProto()->Bonding == BIND_QUEST_ITEM ||
- pItem->GetProto()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos) )
+ (pItem->GetProto()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos)))
pItem->SetBinding( true );
- if( bag == INVENTORY_SLOT_BAG_0 )
+ if (bag == INVENTORY_SLOT_BAG_0)
{
m_items[slot] = pItem;
SetUInt64Value( (uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2) ), pItem->GetGUID() );
@@ -10305,7 +10420,11 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo
pItem->SetSlot( slot );
pItem->SetContainer( NULL );
- if( IsInWorld() && update )
+ // need update known currency
+ if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END)
+ UpdateKnownCurrencies(pItem->GetEntry(),true);
+
+ if (IsInWorld() && update)
{
pItem->AddToWorld();
pItem->SendUpdateToPlayer( this );
@@ -10313,20 +10432,16 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo
pItem->SetState(ITEM_CHANGED, this);
}
- else
+ else if (Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ))
{
- Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
- if( pBag )
+ pBag->StoreItem( slot, pItem, update );
+ if( IsInWorld() && update )
{
- pBag->StoreItem( slot, pItem, update );
- if( IsInWorld() && update )
- {
- pItem->AddToWorld();
- pItem->SendUpdateToPlayer( this );
- }
- pItem->SetState(ITEM_CHANGED, this);
- pBag->SetState(ITEM_CHANGED, this);
+ pItem->AddToWorld();
+ pItem->SendUpdateToPlayer( this );
}
+ pItem->SetState(ITEM_CHANGED, this);
+ pBag->SetState(ITEM_CHANGED, this);
}
AddEnchantmentDurations(pItem);
@@ -10336,19 +10451,19 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo
}
else
{
- if( pItem2->GetProto()->Bonding == BIND_WHEN_PICKED_UP ||
+ if (pItem2->GetProto()->Bonding == BIND_WHEN_PICKED_UP ||
pItem2->GetProto()->Bonding == BIND_QUEST_ITEM ||
- pItem2->GetProto()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos) )
+ (pItem2->GetProto()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos)))
pItem2->SetBinding( true );
pItem2->SetCount( pItem2->GetCount() + count );
- if( IsInWorld() && update )
+ if (IsInWorld() && update)
pItem2->SendUpdateToPlayer( this );
- if(!clone)
+ if (!clone)
{
// delete item (it not in any slot currently)
- if( IsInWorld() && update )
+ if (IsInWorld() && update)
{
pItem->RemoveFromWorld();
pItem->DestroyForPlayer( this );
@@ -10360,6 +10475,7 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo
pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
pItem->SetState(ITEM_REMOVED, this);
}
+
// AddItemDurations(pItem2); - pItem2 already have duration listed for player
AddEnchantmentDurations(pItem2);
@@ -10371,108 +10487,107 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo
Item* Player::EquipNewItem( uint16 pos, uint32 item, bool update )
{
- Item *pItem = Item::CreateItem( item, 1, this );
- if( pItem )
+ if (Item *pItem = Item::CreateItem( item, 1, this ))
{
ItemAddedQuestCheck( item, 1 );
- Item * retItem = EquipItem( pos, pItem, update );
-
- return retItem;
+ return EquipItem( pos, pItem, update );
}
+
return NULL;
}
Item* Player::EquipItem( uint16 pos, Item *pItem, bool update )
{
- if( pItem )
- {
- AddEnchantmentDurations(pItem);
- AddItemDurations(pItem);
- uint8 bag = pos >> 8;
- uint8 slot = pos & 255;
+ AddEnchantmentDurations(pItem);
+ AddItemDurations(pItem);
- Item *pItem2 = GetItemByPos( bag, slot );
+ uint8 bag = pos >> 8;
+ uint8 slot = pos & 255;
- if( !pItem2 )
- {
- VisualizeItem( slot, pItem);
+ Item *pItem2 = GetItemByPos( bag, slot );
- if(isAlive())
- {
- ItemPrototype const *pProto = pItem->GetProto();
+ if( !pItem2 )
+ {
+ VisualizeItem( slot, pItem);
- // item set bonuses applied only at equip and removed at unequip, and still active for broken items
- if(pProto && pProto->ItemSet)
- AddItemsSetItem(this,pItem);
+ if(isAlive())
+ {
+ ItemPrototype const *pProto = pItem->GetProto();
- _ApplyItemMods(pItem, slot, true);
+ // item set bonuses applied only at equip and removed at unequip, and still active for broken items
+ if(pProto && pProto->ItemSet)
+ AddItemsSetItem(this,pItem);
- if(pProto && isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer == 0)
- {
- uint32 cooldownSpell = SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_5s;
+ _ApplyItemMods(pItem, slot, true);
- if (getClass() == CLASS_ROGUE)
- cooldownSpell = SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_0s;
+ if(pProto && isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer == 0)
+ {
+ uint32 cooldownSpell = SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_5s;
- SpellEntry const* spellProto = sSpellStore.LookupEntry(cooldownSpell);
+ if (getClass() == CLASS_ROGUE)
+ cooldownSpell = SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_0s;
- if (!spellProto)
- sLog.outError("Weapon switch cooldown spell %u couldn't be found in Spell.dbc", cooldownSpell);
- else
- {
- m_weaponChangeTimer = spellProto->StartRecoveryTime;
-
- WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4);
- data << uint64(GetGUID());
- data << uint8(1);
- data << uint32(cooldownSpell);
- data << uint32(0);
- GetSession()->SendPacket(&data);
- }
+ SpellEntry const* spellProto = sSpellStore.LookupEntry(cooldownSpell);
+
+ if (!spellProto)
+ sLog.outError("Weapon switch cooldown spell %u couldn't be found in Spell.dbc", cooldownSpell);
+ else
+ {
+ m_weaponChangeTimer = spellProto->StartRecoveryTime;
+
+ WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4);
+ data << uint64(GetGUID());
+ data << uint8(1);
+ data << uint32(cooldownSpell);
+ data << uint32(0);
+ GetSession()->SendPacket(&data);
}
}
+ }
- if( IsInWorld() && update )
- {
- pItem->AddToWorld();
- pItem->SendUpdateToPlayer( this );
- }
+ if( IsInWorld() && update )
+ {
+ pItem->AddToWorld();
+ pItem->SendUpdateToPlayer( this );
+ }
- ApplyEquipCooldown(pItem);
+ ApplyEquipCooldown(pItem);
- if( slot == EQUIPMENT_SLOT_MAINHAND )
- UpdateExpertise(BASE_ATTACK);
- else if( slot == EQUIPMENT_SLOT_OFFHAND )
- UpdateExpertise(OFF_ATTACK);
- }
- else
- {
- pItem2->SetCount( pItem2->GetCount() + pItem->GetCount() );
- if( IsInWorld() && update )
- pItem2->SendUpdateToPlayer( this );
+ if( slot == EQUIPMENT_SLOT_MAINHAND )
+ UpdateExpertise(BASE_ATTACK);
+ else if( slot == EQUIPMENT_SLOT_OFFHAND )
+ UpdateExpertise(OFF_ATTACK);
+ }
+ else
+ {
+ pItem2->SetCount( pItem2->GetCount() + pItem->GetCount() );
+ if( IsInWorld() && update )
+ pItem2->SendUpdateToPlayer( this );
- // delete item (it not in any slot currently)
- //pItem->DeleteFromDB();
- if( IsInWorld() && update )
- {
- pItem->RemoveFromWorld();
- pItem->DestroyForPlayer( this );
- }
+ // delete item (it not in any slot currently)
+ //pItem->DeleteFromDB();
+ if( IsInWorld() && update )
+ {
+ pItem->RemoveFromWorld();
+ pItem->DestroyForPlayer( this );
+ }
- RemoveEnchantmentDurations(pItem);
- RemoveItemDurations(pItem);
+ RemoveEnchantmentDurations(pItem);
+ RemoveItemDurations(pItem);
- pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
- pItem->SetState(ITEM_REMOVED, this);
- pItem2->SetState(ITEM_CHANGED, this);
+ pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
+ pItem->SetState(ITEM_REMOVED, this);
+ pItem2->SetState(ITEM_CHANGED, this);
- ApplyEquipCooldown(pItem2);
+ ApplyEquipCooldown(pItem2);
- return pItem2;
- }
+ return pItem2;
}
+ // only for full equip instead adding to stack
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
+
return pItem;
}
@@ -10587,23 +10702,32 @@ void Player::RemoveItem( uint8 bag, uint8 slot, bool update )
// remove item dependent auras and casts (only weapon and armor slots)
if(slot < EQUIPMENT_SLOT_END)
+ {
RemoveItemDependentAurasAndCasts(pItem);
- // remove held enchantments
- if ( slot == EQUIPMENT_SLOT_MAINHAND )
- {
- if (pItem->GetItemSuffixFactor())
- {
- pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_3);
- pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_4);
- }
- else
+ // remove held enchantments, update expertise
+ if ( slot == EQUIPMENT_SLOT_MAINHAND )
{
- pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_0);
- pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_1);
+ if (pItem->GetItemSuffixFactor())
+ {
+ pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_3);
+ pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_4);
+ }
+ else
+ {
+ pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_0);
+ pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_1);
+ }
+
+ UpdateExpertise(BASE_ATTACK);
}
+ else if( slot == EQUIPMENT_SLOT_OFFHAND )
+ UpdateExpertise(OFF_ATTACK);
}
}
+ // need update known currency
+ else if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END)
+ UpdateKnownCurrencies(pItem->GetEntry(),false);
m_items[slot] = NULL;
SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0);
@@ -10622,11 +10746,6 @@ void Player::RemoveItem( uint8 bag, uint8 slot, bool update )
pItem->SetSlot( NULL_SLOT );
if( IsInWorld() && update )
pItem->SendUpdateToPlayer( this );
-
- if( slot == EQUIPMENT_SLOT_MAINHAND )
- UpdateExpertise(BASE_ATTACK);
- else if( slot == EQUIPMENT_SLOT_OFFHAND )
- UpdateExpertise(OFF_ATTACK);
}
}
@@ -10711,9 +10830,18 @@ void Player::DestroyItem( uint8 bag, uint8 slot, bool update )
// remove item dependent auras and casts (only weapon and armor slots)
RemoveItemDependentAurasAndCasts(pItem);
+ // update expertise
+ if ( slot == EQUIPMENT_SLOT_MAINHAND )
+ UpdateExpertise(BASE_ATTACK);
+ else if( slot == EQUIPMENT_SLOT_OFFHAND )
+ UpdateExpertise(OFF_ATTACK);
+
// equipment visual show
SetVisibleItemSlot(slot,NULL);
}
+ // need update known currency
+ else if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END)
+ UpdateKnownCurrencies(pItem->GetEntry(),false);
m_items[slot] = NULL;
}
@@ -10736,60 +10864,61 @@ void Player::DestroyItem( uint8 bag, uint8 slot, bool update )
void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check)
{
sLog.outDebug( "STORAGE: DestroyItemCount item = %u, count = %u", item, count);
- Item *pItem;
- ItemPrototype const *pProto;
uint32 remcount = 0;
// in inventory
for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
{
- pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->GetEntry() == item )
+ if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
{
- if( pItem->GetCount() + remcount <= count )
+ if (pItem->GetEntry() == item)
{
- // all items in inventory can unequipped
- remcount += pItem->GetCount();
- DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
+ if (pItem->GetCount() + remcount <= count)
+ {
+ // all items in inventory can unequipped
+ remcount += pItem->GetCount();
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
- if(remcount >=count)
+ if (remcount >=count)
+ return;
+ }
+ else
+ {
+ ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
+ pItem->SetCount( pItem->GetCount() - count + remcount );
+ if (IsInWorld() & update)
+ pItem->SendUpdateToPlayer( this );
+ pItem->SetState(ITEM_CHANGED, this);
return;
- }
- else
- {
- pProto = pItem->GetProto();
- ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
- pItem->SetCount( pItem->GetCount() - count + remcount );
- if( IsInWorld() & update )
- pItem->SendUpdateToPlayer( this );
- pItem->SetState(ITEM_CHANGED, this);
- return;
+ }
}
}
}
- for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
+
+ for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
{
- pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->GetEntry() == item )
+ if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
{
- if( pItem->GetCount() + remcount <= count )
+ if (pItem->GetEntry() == item)
{
- // all keys can be unequipped
- remcount += pItem->GetCount();
- DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
+ if (pItem->GetCount() + remcount <= count)
+ {
+ // all keys can be unequipped
+ remcount += pItem->GetCount();
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
- if(remcount >=count)
+ if (remcount >=count)
+ return;
+ }
+ else
+ {
+ ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
+ pItem->SetCount( pItem->GetCount() - count + remcount );
+ if (IsInWorld() & update)
+ pItem->SendUpdateToPlayer( this );
+ pItem->SetState(ITEM_CHANGED, this);
return;
- }
- else
- {
- pProto = pItem->GetProto();
- ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
- pItem->SetCount( pItem->GetCount() - count + remcount );
- if( IsInWorld() & update )
- pItem->SendUpdateToPlayer( this );
- pItem->SetState(ITEM_CHANGED, this);
- return;
+ }
}
}
}
@@ -10801,27 +10930,28 @@ void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool uneq
{
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
{
- pItem = pBag->GetItemByPos(j);
- if( pItem && pItem->GetEntry() == item )
+ if(Item* pItem = pBag->GetItemByPos(j))
{
- // all items in bags can be unequipped
- if( pItem->GetCount() + remcount <= count )
+ if (pItem->GetEntry() == item)
{
- remcount += pItem->GetCount();
- DestroyItem( i, j, update );
+ // all items in bags can be unequipped
+ if (pItem->GetCount() + remcount <= count)
+ {
+ remcount += pItem->GetCount();
+ DestroyItem( i, j, update );
- if(remcount >=count)
+ if (remcount >=count)
+ return;
+ }
+ else
+ {
+ ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
+ pItem->SetCount( pItem->GetCount() - count + remcount );
+ if (IsInWorld() && update)
+ pItem->SendUpdateToPlayer( this );
+ pItem->SetState(ITEM_CHANGED, this);
return;
- }
- else
- {
- pProto = pItem->GetProto();
- ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
- pItem->SetCount( pItem->GetCount() - count + remcount );
- if( IsInWorld() && update )
- pItem->SendUpdateToPlayer( this );
- pItem->SetState(ITEM_CHANGED, this);
- return;
+ }
}
}
}
@@ -10831,29 +10961,30 @@ void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool uneq
// in equipment and bag list
for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
{
- pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->GetEntry() == item )
+ if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
{
- if( pItem->GetCount() + remcount <= count )
+ if (pItem && pItem->GetEntry() == item)
{
- if(!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i,false) == EQUIP_ERR_OK )
+ if (pItem->GetCount() + remcount <= count)
{
- remcount += pItem->GetCount();
- DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
+ if (!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i,false) == EQUIP_ERR_OK )
+ {
+ remcount += pItem->GetCount();
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
- if(remcount >=count)
- return;
+ if (remcount >=count)
+ return;
+ }
+ }
+ else
+ {
+ ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
+ pItem->SetCount( pItem->GetCount() - count + remcount );
+ if (IsInWorld() & update)
+ pItem->SendUpdateToPlayer( this );
+ pItem->SetState(ITEM_CHANGED, this);
+ return;
}
- }
- else
- {
- pProto = pItem->GetProto();
- ItemRemovedQuestCheck( pItem->GetEntry(), count - remcount );
- pItem->SetCount( pItem->GetCount() - count + remcount );
- if( IsInWorld() & update )
- pItem->SendUpdateToPlayer( this );
- pItem->SetState(ITEM_CHANGED, this);
- return;
}
}
}
@@ -10865,40 +10996,28 @@ void Player::DestroyZoneLimitedItem( bool update, uint32 new_zone )
// in inventory
for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
- {
- Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) )
- DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
- }
- for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
- {
- Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) )
- DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
- }
+ if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
+ if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone))
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
+
+ for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++)
+ if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
+ if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone))
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
// in inventory bags
for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
- {
- Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pBag )
- {
+ if (Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
- {
- Item* pItem = pBag->GetItemByPos(j);
- if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) )
- DestroyItem( i, j, update);
- }
- }
- }
+ if (Item* pItem = pBag->GetItemByPos(j))
+ if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone))
+ DestroyItem( i, j, update);
// in equipment and bag list
for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
- {
- Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) )
- DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
- }
+ if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
+ if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone))
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
void Player::DestroyConjuredItems( bool update )
@@ -10909,40 +11028,23 @@ void Player::DestroyConjuredItems( bool update )
// in inventory
for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
- {
- Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->GetProto() &&
- (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
- (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
- DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
- }
+ if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
+ if (pItem->IsConjuredConsumable())
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
// in inventory bags
for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
- {
- Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pBag )
- {
+ if (Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
- {
- Item* pItem = pBag->GetItemByPos(j);
- if( pItem && pItem->GetProto() &&
- (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
- (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
- DestroyItem( i, j, update);
- }
- }
- }
+ if (Item* pItem = pBag->GetItemByPos(j))
+ if (pItem->IsConjuredConsumable())
+ DestroyItem( i, j, update);
// in equipment and bag list
for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
- {
- Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
- if( pItem && pItem->GetProto() &&
- (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) &&
- (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )
- DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
- }
+ if (Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
+ if (pItem->IsConjuredConsumable())
+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);
}
void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update )
@@ -11098,6 +11200,8 @@ void Player::SwapItem( uint16 src, uint16 dst )
return;
}
+ // SRC checks
+
if(pSrcItem->m_lootGenerated) // prevent swap looting item
{
//best error message found for attempting to swap while looting
@@ -11108,8 +11212,8 @@ void Player::SwapItem( uint16 src, uint16 dst )
// check unequip potability for equipped items and bank bags
if(IsEquipmentPos ( src ) || IsBagPos ( src ))
{
- // bags can be swapped with empty bag slots
- uint8 msg = CanUnequipItem( src, !IsBagPos ( src ) || IsBagPos ( dst ));
+ // bags can be swapped with empty bag slots, or with empty bag (items move possibility checked later)
+ uint8 msg = CanUnequipItem( src, !IsBagPos ( src ) || IsBagPos ( dst ) || pDstItem && pDstItem->IsBag() && ((Bag*)pDstItem)->IsEmpty());
if(msg != EQUIP_ERR_OK)
{
SendEquipError( msg, pSrcItem, pDstItem );
@@ -11124,6 +11228,34 @@ void Player::SwapItem( uint16 src, uint16 dst )
return;
}
+ // DST checks
+
+ if (pDstItem)
+ {
+ if(pDstItem->m_lootGenerated) // prevent swap looting item
+ {
+ //best error message found for attempting to swap while looting
+ SendEquipError( EQUIP_ERR_CANT_DO_RIGHT_NOW, pDstItem, NULL );
+ return;
+ }
+
+ // check unequip potability for equipped items and bank bags
+ if(IsEquipmentPos ( dst ) || IsBagPos ( dst ))
+ {
+ // bags can be swapped with empty bag slots, or with empty bag (items move possibility checked later)
+ uint8 msg = CanUnequipItem( dst, !IsBagPos ( dst ) || IsBagPos ( src ) || pSrcItem->IsBag() && ((Bag*)pSrcItem)->IsEmpty());
+ if(msg != EQUIP_ERR_OK)
+ {
+ SendEquipError( msg, pSrcItem, pDstItem );
+ return;
+ }
+ }
+ }
+
+ // NOW this is or item move (swap with empty), or swap with another item (including bags in bag possitions)
+ // or swap empty bag with another empty or not empty bag (with items exchange)
+
+ // Move case
if( !pDstItem )
{
if( IsInventoryPos( dst ) )
@@ -11166,140 +11298,187 @@ void Player::SwapItem( uint16 src, uint16 dst )
EquipItem( dest, pSrcItem, true);
AutoUnequipOffhandIfNeed();
}
+
+ return;
}
- else // if (!pDstItem)
+
+ // attempt merge to / fill target item
+ if(!pSrcItem->IsBag() && !pDstItem->IsBag())
{
- if(pDstItem->m_lootGenerated) // prevent swap looting item
- {
- //best error message found for attempting to swap while looting
- SendEquipError( EQUIP_ERR_CANT_DO_RIGHT_NOW, pDstItem, NULL );
+ uint8 msg;
+ ItemPosCountVec sDest;
+ uint16 eDest;
+ if( IsInventoryPos( dst ) )
+ msg = CanStoreItem( dstbag, dstslot, sDest, pSrcItem, false );
+ else if( IsBankPos ( dst ) )
+ msg = CanBankItem( dstbag, dstslot, sDest, pSrcItem, false );
+ else if( IsEquipmentPos ( dst ) )
+ msg = CanEquipItem( dstslot, eDest, pSrcItem, false );
+ else
return;
- }
- // check unequip potability for equipped items and bank bags
- if(IsEquipmentPos ( dst ) || IsBagPos ( dst ))
+ // can be merge/fill
+ if(msg == EQUIP_ERR_OK)
{
- // bags can be swapped with empty bag slots
- uint8 msg = CanUnequipItem( dst, !IsBagPos ( dst ) || IsBagPos ( src ) );
- if(msg != EQUIP_ERR_OK)
+ if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->GetMaxStackSize())
{
- SendEquipError( msg, pSrcItem, pDstItem );
- return;
- }
- }
+ RemoveItem(srcbag, srcslot, true);
- // attempt merge to / fill target item
- {
- uint8 msg;
- ItemPosCountVec sDest;
- uint16 eDest;
- if( IsInventoryPos( dst ) )
- msg = CanStoreItem( dstbag, dstslot, sDest, pSrcItem, false );
- else if( IsBankPos ( dst ) )
- msg = CanBankItem( dstbag, dstslot, sDest, pSrcItem, false );
- else if( IsEquipmentPos ( dst ) )
- msg = CanEquipItem( dstslot, eDest, pSrcItem, false );
- else
- return;
-
- // can be merge/fill
- if(msg == EQUIP_ERR_OK)
- {
- if( pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetProto()->Stackable )
+ if( IsInventoryPos( dst ) )
+ StoreItem( sDest, pSrcItem, true);
+ else if( IsBankPos ( dst ) )
+ BankItem( sDest, pSrcItem, true);
+ else if( IsEquipmentPos ( dst ) )
{
- RemoveItem(srcbag, srcslot, true);
-
- if( IsInventoryPos( dst ) )
- StoreItem( sDest, pSrcItem, true);
- else if( IsBankPos ( dst ) )
- BankItem( sDest, pSrcItem, true);
- else if( IsEquipmentPos ( dst ) )
- {
- EquipItem( eDest, pSrcItem, true);
- AutoUnequipOffhandIfNeed();
- }
+ EquipItem( eDest, pSrcItem, true);
+ AutoUnequipOffhandIfNeed();
}
- else
+ }
+ else
+ {
+ pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->GetMaxStackSize());
+ pDstItem->SetCount( pSrcItem->GetProto()->GetMaxStackSize());
+ pSrcItem->SetState(ITEM_CHANGED, this);
+ pDstItem->SetState(ITEM_CHANGED, this);
+ if( IsInWorld() )
{
- pSrcItem->SetCount( pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetProto()->Stackable );
- pDstItem->SetCount( pSrcItem->GetProto()->Stackable );
- pSrcItem->SetState(ITEM_CHANGED, this);
- pDstItem->SetState(ITEM_CHANGED, this);
- if( IsInWorld() )
- {
- pSrcItem->SendUpdateToPlayer( this );
- pDstItem->SendUpdateToPlayer( this );
- }
+ pSrcItem->SendUpdateToPlayer( this );
+ pDstItem->SendUpdateToPlayer( this );
}
- return;
}
+ return;
}
+ }
- // impossible merge/fill, do real swap
- uint8 msg;
+ // impossible merge/fill, do real swap
+ uint8 msg;
- // check src->dest move possibility
- ItemPosCountVec sDest;
- uint16 eDest;
- if( IsInventoryPos( dst ) )
- msg = CanStoreItem( dstbag, dstslot, sDest, pSrcItem, true );
- else if( IsBankPos( dst ) )
- msg = CanBankItem( dstbag, dstslot, sDest, pSrcItem, true );
- else if( IsEquipmentPos( dst ) )
- {
- msg = CanEquipItem( dstslot, eDest, pSrcItem, true );
- if( msg == EQUIP_ERR_OK )
- msg = CanUnequipItem( eDest, true );
- }
+ // check src->dest move possibility
+ ItemPosCountVec sDest;
+ uint16 eDest = 0;
+ if( IsInventoryPos( dst ) )
+ msg = CanStoreItem( dstbag, dstslot, sDest, pSrcItem, true );
+ else if( IsBankPos( dst ) )
+ msg = CanBankItem( dstbag, dstslot, sDest, pSrcItem, true );
+ else if( IsEquipmentPos( dst ) )
+ {
+ msg = CanEquipItem( dstslot, eDest, pSrcItem, true );
+ if( msg == EQUIP_ERR_OK )
+ msg = CanUnequipItem( eDest, true );
+ }
- if( msg != EQUIP_ERR_OK )
+ if( msg != EQUIP_ERR_OK )
+ {
+ SendEquipError( msg, pSrcItem, pDstItem );
+ return;
+ }
+
+ // check dest->src move possibility
+ ItemPosCountVec sDest2;
+ uint16 eDest2 = 0;
+ if( IsInventoryPos( src ) )
+ msg = CanStoreItem( srcbag, srcslot, sDest2, pDstItem, true );
+ else if( IsBankPos( src ) )
+ msg = CanBankItem( srcbag, srcslot, sDest2, pDstItem, true );
+ else if( IsEquipmentPos( src ) )
+ {
+ msg = CanEquipItem( srcslot, eDest2, pDstItem, true);
+ if( msg == EQUIP_ERR_OK )
+ msg = CanUnequipItem( eDest2, true);
+ }
+
+ if( msg != EQUIP_ERR_OK )
+ {
+ SendEquipError( msg, pDstItem, pSrcItem );
+ return;
+ }
+
+ // Check bag swap with item exchange (one from empty in not bag possition (equipped (not possible in fact) or store)
+ if(pSrcItem->IsBag() && pDstItem->IsBag())
+ {
+ Bag* emptyBag = NULL;
+ Bag* fullBag = NULL;
+ if(((Bag*)pSrcItem)->IsEmpty() && !IsBagPos(src))
{
- SendEquipError( msg, pSrcItem, pDstItem );
- return;
+ emptyBag = (Bag*)pSrcItem;
+ fullBag = (Bag*)pDstItem;
}
-
- // check dest->src move possibility
- ItemPosCountVec sDest2;
- uint16 eDest2;
- if( IsInventoryPos( src ) )
- msg = CanStoreItem( srcbag, srcslot, sDest2, pDstItem, true );
- else if( IsBankPos( src ) )
- msg = CanBankItem( srcbag, srcslot, sDest2, pDstItem, true );
- else if( IsEquipmentPos( src ) )
+ else if(((Bag*)pDstItem)->IsEmpty() && !IsBagPos(dst))
{
- msg = CanEquipItem( srcslot, eDest2, pDstItem, true);
- if( msg == EQUIP_ERR_OK )
- msg = CanUnequipItem( eDest2, true);
+ emptyBag = (Bag*)pDstItem;
+ fullBag = (Bag*)pSrcItem;
}
- if( msg != EQUIP_ERR_OK )
+ // bag swap (with items exchange) case
+ if(emptyBag && fullBag)
{
- SendEquipError( msg, pDstItem, pSrcItem );
- return;
- }
+ ItemPrototype const* emotyProto = emptyBag->GetProto();
- // now do moves, remove...
- RemoveItem(dstbag, dstslot, false);
- RemoveItem(srcbag, srcslot, false);
+ uint32 count = 0;
- // add to dest
- if( IsInventoryPos( dst ) )
- StoreItem(sDest, pSrcItem, true);
- else if( IsBankPos( dst ) )
- BankItem(sDest, pSrcItem, true);
- else if( IsEquipmentPos( dst ) )
- EquipItem(eDest, pSrcItem, true);
-
- // add to src
- if( IsInventoryPos( src ) )
- StoreItem(sDest2, pDstItem, true);
- else if( IsBankPos( src ) )
- BankItem(sDest2, pDstItem, true);
- else if( IsEquipmentPos( src ) )
- EquipItem(eDest2, pDstItem, true);
+ for(int i=0; i < fullBag->GetBagSize(); ++i)
+ {
+ Item *bagItem = fullBag->GetItemByPos(i);
+ if (!bagItem)
+ continue;
- AutoUnequipOffhandIfNeed();
+ ItemPrototype const* bagItemProto = bagItem->GetProto();
+ if (!bagItemProto || !ItemCanGoIntoBag(bagItemProto, emotyProto))
+ {
+ // one from items not go to empry target bag
+ SendEquipError( EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem );
+ return;
+ }
+
+ ++count;
+ }
+
+
+ if (count > emptyBag->GetBagSize())
+ {
+ // too small targeted bag
+ SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pSrcItem, pDstItem );
+ return;
+ }
+
+ // Items swap
+ count = 0; // will pos in new bag
+ for(int i=0; i< fullBag->GetBagSize(); ++i)
+ {
+ Item *bagItem = fullBag->GetItemByPos(i);
+ if (!bagItem)
+ continue;
+
+ fullBag->RemoveItem(i, true);
+ emptyBag->StoreItem(count, bagItem, true);
+ bagItem->SetState(ITEM_CHANGED, this);
+
+ ++count;
+ }
+ }
}
+
+ // now do moves, remove...
+ RemoveItem(dstbag, dstslot, false);
+ RemoveItem(srcbag, srcslot, false);
+
+ // add to dest
+ if( IsInventoryPos( dst ) )
+ StoreItem(sDest, pSrcItem, true);
+ else if( IsBankPos( dst ) )
+ BankItem(sDest, pSrcItem, true);
+ else if( IsEquipmentPos( dst ) )
+ EquipItem(eDest, pSrcItem, true);
+
+ // add to src
+ if( IsInventoryPos( src ) )
+ StoreItem(sDest2, pDstItem, true);
+ else if( IsBankPos( src ) )
+ BankItem(sDest2, pDstItem, true);
+ else if( IsEquipmentPos( src ) )
+ EquipItem(eDest2, pDstItem, true);
+
+ AutoUnequipOffhandIfNeed();
}
void Player::AddItemToBuyBackSlot( Item *pItem )
@@ -11539,7 +11718,7 @@ void Player::RemoveEnchantmentDurations(Item *item)
}
}
-void Player::RemoveAllEnchantments(EnchantmentSlot slot)
+void Player::RemoveArenaEnchantments(EnchantmentSlot slot)
{
// remove enchantments from equipped items first to clean up the m_enchantDuration list
for(EnchantDurationList::iterator itr = m_enchantDuration.begin(),next;itr != m_enchantDuration.end();itr=next)
@@ -11549,6 +11728,12 @@ void Player::RemoveAllEnchantments(EnchantmentSlot slot)
{
if(itr->item && itr->item->GetEnchantmentId(slot))
{
+ // Poisons and DK runes are enchants which are allowed on arenas
+ if (spellmgr.IsArenaAllowedEnchancment(itr->item->GetEnchantmentId(slot)))
+ {
+ ++next;
+ continue;
+ }
// remove from stats
ApplyEnchantment(itr->item,slot,false,false);
// remove visual
@@ -11640,261 +11825,312 @@ void Player::ApplyEnchantment(Item *item,EnchantmentSlot slot,bool apply, bool a
if(!ignore_condition && pEnchant->EnchantmentCondition && !((Player*)this)->EnchantmentFitsRequirements(pEnchant->EnchantmentCondition, -1))
return;
- for (int s=0; s<3; s++)
+ if (!item->IsBroken())
{
- uint32 enchant_display_type = pEnchant->type[s];
- uint32 enchant_amount = pEnchant->amount[s];
- uint32 enchant_spell_id = pEnchant->spellid[s];
-
- switch(enchant_display_type)
+ for (int s=0; s<3; s++)
{
- case ITEM_ENCHANTMENT_TYPE_NONE:
- break;
- case ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL:
- // processed in Player::CastItemCombatSpell
- break;
- case ITEM_ENCHANTMENT_TYPE_DAMAGE:
- if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
- HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(enchant_amount), apply);
- else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND)
- HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(enchant_amount), apply);
- else if (item->GetSlot() == EQUIPMENT_SLOT_RANGED)
- HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
- break;
- case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL:
- if(enchant_spell_id)
- {
- if(apply)
+ uint32 enchant_display_type = pEnchant->type[s];
+ uint32 enchant_amount = pEnchant->amount[s];
+ uint32 enchant_spell_id = pEnchant->spellid[s];
+
+ switch(enchant_display_type)
+ {
+ case ITEM_ENCHANTMENT_TYPE_NONE:
+ break;
+ case ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL:
+ // processed in Player::CastItemCombatSpell
+ break;
+ case ITEM_ENCHANTMENT_TYPE_DAMAGE:
+ if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
+ HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(enchant_amount), apply);
+ else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND)
+ HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(enchant_amount), apply);
+ else if (item->GetSlot() == EQUIPMENT_SLOT_RANGED)
+ HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
+ break;
+ case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL:
+ if(enchant_spell_id)
{
- int32 basepoints = 0;
- // Random Property Exist - try found basepoints for spell (basepoints depends from item suffix factor)
- if (item->GetItemRandomPropertyId())
+ if(apply)
{
- ItemRandomSuffixEntry const *item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId()));
- if (item_rand)
+ int32 basepoints = 0;
+ // Random Property Exist - try found basepoints for spell (basepoints depends from item suffix factor)
+ if (item->GetItemRandomPropertyId())
{
- // Search enchant_amount
- for (int k=0; k<3; k++)
+ ItemRandomSuffixEntry const *item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId()));
+ if (item_rand)
{
- if(item_rand->enchant_id[k] == enchant_id)
+ // Search enchant_amount
+ for (int k=0; k<3; k++)
{
- basepoints = int32((item_rand->prefix[k]*item->GetItemSuffixFactor()) / 10000 );
- break;
+ if(item_rand->enchant_id[k] == enchant_id)
+ {
+ basepoints = int32((item_rand->prefix[k]*item->GetItemSuffixFactor()) / 10000 );
+ break;
+ }
}
}
}
+ // Cast custom spell vs all equal basepoints getted from enchant_amount
+ if (basepoints)
+ CastCustomSpell(this,enchant_spell_id,&basepoints,&basepoints,&basepoints,true,item);
+ else
+ CastSpell(this,enchant_spell_id,true,item);
}
- // Cast custom spell vs all equal basepoints getted from enchant_amount
- if (basepoints)
- CastCustomSpell(this,enchant_spell_id,&basepoints,&basepoints,&basepoints,true,item);
else
- CastSpell(this,enchant_spell_id,true,item);
+ RemoveAurasDueToItemSpell(item,enchant_spell_id);
}
- else
- RemoveAurasDueToItemSpell(item,enchant_spell_id);
- }
- break;
- case ITEM_ENCHANTMENT_TYPE_RESISTANCE:
- if (!enchant_amount)
- {
- ItemRandomSuffixEntry const *item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId()));
- if(item_rand)
+ break;
+ case ITEM_ENCHANTMENT_TYPE_RESISTANCE:
+ if (!enchant_amount)
{
- for (int k=0; k<3; k++)
+ ItemRandomSuffixEntry const *item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId()));
+ if(item_rand)
{
- if(item_rand->enchant_id[k] == enchant_id)
+ for (int k=0; k<3; k++)
{
- enchant_amount = uint32((item_rand->prefix[k]*item->GetItemSuffixFactor()) / 10000 );
- break;
+ if(item_rand->enchant_id[k] == enchant_id)
+ {
+ enchant_amount = uint32((item_rand->prefix[k]*item->GetItemSuffixFactor()) / 10000 );
+ break;
+ }
}
}
}
- }
- HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply);
- break;
- case ITEM_ENCHANTMENT_TYPE_STAT:
- {
- if (!enchant_amount)
+ HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply);
+ break;
+ case ITEM_ENCHANTMENT_TYPE_STAT:
{
- ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId()));
- if(item_rand_suffix)
+ if (!enchant_amount)
{
- for (int k=0; k<3; k++)
+ ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId()));
+ if(item_rand_suffix)
{
- if(item_rand_suffix->enchant_id[k] == enchant_id)
+ for (int k=0; k<3; k++)
{
- enchant_amount = uint32((item_rand_suffix->prefix[k]*item->GetItemSuffixFactor()) / 10000 );
- break;
+ if(item_rand_suffix->enchant_id[k] == enchant_id)
+ {
+ enchant_amount = uint32((item_rand_suffix->prefix[k]*item->GetItemSuffixFactor()) / 10000 );
+ break;
+ }
}
}
}
- }
- sLog.outDebug("Adding %u to stat nb %u",enchant_amount,enchant_spell_id);
- switch (enchant_spell_id)
- {
- case ITEM_MOD_AGILITY:
- sLog.outDebug("+ %u AGILITY",enchant_amount);
- HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply);
- ApplyStatBuffMod(STAT_AGILITY, enchant_amount, apply);
- break;
- case ITEM_MOD_STRENGTH:
- sLog.outDebug("+ %u STRENGTH",enchant_amount);
- HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply);
- ApplyStatBuffMod(STAT_STRENGTH, enchant_amount, apply);
- break;
- case ITEM_MOD_INTELLECT:
- sLog.outDebug("+ %u INTELLECT",enchant_amount);
- HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply);
- ApplyStatBuffMod(STAT_INTELLECT, enchant_amount, apply);
- break;
- case ITEM_MOD_SPIRIT:
- sLog.outDebug("+ %u SPIRIT",enchant_amount);
- HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply);
- ApplyStatBuffMod(STAT_SPIRIT, enchant_amount, apply);
- break;
- case ITEM_MOD_STAMINA:
- sLog.outDebug("+ %u STAMINA",enchant_amount);
- HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply);
- ApplyStatBuffMod(STAT_STAMINA, enchant_amount, apply);
- break;
- case ITEM_MOD_DEFENSE_SKILL_RATING:
- ((Player*)this)->ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply);
- sLog.outDebug("+ %u DEFENCE", enchant_amount);
- break;
- case ITEM_MOD_DODGE_RATING:
- ((Player*)this)->ApplyRatingMod(CR_DODGE, enchant_amount, apply);
- sLog.outDebug("+ %u DODGE", enchant_amount);
- break;
- case ITEM_MOD_PARRY_RATING:
- ((Player*)this)->ApplyRatingMod(CR_PARRY, enchant_amount, apply);
- sLog.outDebug("+ %u PARRY", enchant_amount);
- break;
- case ITEM_MOD_BLOCK_RATING:
- ((Player*)this)->ApplyRatingMod(CR_BLOCK, enchant_amount, apply);
- sLog.outDebug("+ %u SHIELD_BLOCK", enchant_amount);
- break;
- case ITEM_MOD_HIT_MELEE_RATING:
- ((Player*)this)->ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply);
- sLog.outDebug("+ %u MELEE_HIT", enchant_amount);
- break;
- case ITEM_MOD_HIT_RANGED_RATING:
- ((Player*)this)->ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply);
- sLog.outDebug("+ %u RANGED_HIT", enchant_amount);
- break;
- case ITEM_MOD_HIT_SPELL_RATING:
- ((Player*)this)->ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply);
- sLog.outDebug("+ %u SPELL_HIT", enchant_amount);
- break;
- case ITEM_MOD_CRIT_MELEE_RATING:
- ((Player*)this)->ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply);
- sLog.outDebug("+ %u MELEE_CRIT", enchant_amount);
- break;
- case ITEM_MOD_CRIT_RANGED_RATING:
- ((Player*)this)->ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply);
- sLog.outDebug("+ %u RANGED_CRIT", enchant_amount);
- break;
- case ITEM_MOD_CRIT_SPELL_RATING:
- ((Player*)this)->ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply);
- sLog.outDebug("+ %u SPELL_CRIT", enchant_amount);
- break;
-// Values from ITEM_STAT_MELEE_HA_RATING to ITEM_MOD_HASTE_RANGED_RATING are never used
-// in Enchantments
-// case ITEM_MOD_HIT_TAKEN_MELEE_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply);
-// break;
-// case ITEM_MOD_HIT_TAKEN_RANGED_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply);
-// break;
-// case ITEM_MOD_HIT_TAKEN_SPELL_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply);
-// break;
-// case ITEM_MOD_CRIT_TAKEN_MELEE_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply);
-// break;
-// case ITEM_MOD_CRIT_TAKEN_RANGED_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply);
-// break;
-// case ITEM_MOD_CRIT_TAKEN_SPELL_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply);
-// break;
-// case ITEM_MOD_HASTE_MELEE_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply);
-// break;
-// case ITEM_MOD_HASTE_RANGED_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply);
-// break;
- case ITEM_MOD_HASTE_SPELL_RATING:
- ((Player*)this)->ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply);
- break;
- case ITEM_MOD_HIT_RATING:
- ((Player*)this)->ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply);
- ((Player*)this)->ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply);
- ((Player*)this)->ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply);
- sLog.outDebug("+ %u HIT", enchant_amount);
- break;
- case ITEM_MOD_CRIT_RATING:
- ((Player*)this)->ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply);
- ((Player*)this)->ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply);
- ((Player*)this)->ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply);
- sLog.outDebug("+ %u CRITICAL", enchant_amount);
- break;
-// Values ITEM_MOD_HIT_TAKEN_RATING and ITEM_MOD_CRIT_TAKEN_RATING are never used in Enchantment
-// case ITEM_MOD_HIT_TAKEN_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply);
-// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply);
-// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply);
-// break;
-// case ITEM_MOD_CRIT_TAKEN_RATING:
-// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply);
-// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply);
-// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply);
-// break;
- case ITEM_MOD_RESILIENCE_RATING:
- ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply);
- ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply);
- ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply);
- sLog.outDebug("+ %u RESILIENCE", enchant_amount);
- break;
- case ITEM_MOD_HASTE_RATING:
- ((Player*)this)->ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply);
- ((Player*)this)->ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply);
- ((Player*)this)->ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply);
- sLog.outDebug("+ %u HASTE", enchant_amount);
- break;
- case ITEM_MOD_EXPERTISE_RATING:
- ((Player*)this)->ApplyRatingMod(CR_EXPERTISE, enchant_amount, apply);
- sLog.outDebug("+ %u EXPERTISE", enchant_amount);
- break;
- default:
- break;
- }
- break;
- }
- case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon
- {
- if(getClass() == CLASS_SHAMAN)
- {
- float addValue = 0.0f;
- if(item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
+ sLog.outDebug("Adding %u to stat nb %u",enchant_amount,enchant_spell_id);
+ switch (enchant_spell_id)
{
- addValue = float(enchant_amount * item->GetProto()->Delay/1000.0f);
- HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply);
+ case ITEM_MOD_MANA:
+ sLog.outDebug("+ %u MANA",enchant_amount);
+ HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply);
+ break;
+ case ITEM_MOD_HEALTH:
+ sLog.outDebug("+ %u HEALTH",enchant_amount);
+ HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply);
+ break;
+ case ITEM_MOD_AGILITY:
+ sLog.outDebug("+ %u AGILITY",enchant_amount);
+ HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply);
+ ApplyStatBuffMod(STAT_AGILITY, enchant_amount, apply);
+ break;
+ case ITEM_MOD_STRENGTH:
+ sLog.outDebug("+ %u STRENGTH",enchant_amount);
+ HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply);
+ ApplyStatBuffMod(STAT_STRENGTH, enchant_amount, apply);
+ break;
+ case ITEM_MOD_INTELLECT:
+ sLog.outDebug("+ %u INTELLECT",enchant_amount);
+ HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply);
+ ApplyStatBuffMod(STAT_INTELLECT, enchant_amount, apply);
+ break;
+ case ITEM_MOD_SPIRIT:
+ sLog.outDebug("+ %u SPIRIT",enchant_amount);
+ HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply);
+ ApplyStatBuffMod(STAT_SPIRIT, enchant_amount, apply);
+ break;
+ case ITEM_MOD_STAMINA:
+ sLog.outDebug("+ %u STAMINA",enchant_amount);
+ HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply);
+ ApplyStatBuffMod(STAT_STAMINA, enchant_amount, apply);
+ break;
+ case ITEM_MOD_DEFENSE_SKILL_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply);
+ sLog.outDebug("+ %u DEFENCE", enchant_amount);
+ break;
+ case ITEM_MOD_DODGE_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_DODGE, enchant_amount, apply);
+ sLog.outDebug("+ %u DODGE", enchant_amount);
+ break;
+ case ITEM_MOD_PARRY_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_PARRY, enchant_amount, apply);
+ sLog.outDebug("+ %u PARRY", enchant_amount);
+ break;
+ case ITEM_MOD_BLOCK_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_BLOCK, enchant_amount, apply);
+ sLog.outDebug("+ %u SHIELD_BLOCK", enchant_amount);
+ break;
+ case ITEM_MOD_HIT_MELEE_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply);
+ sLog.outDebug("+ %u MELEE_HIT", enchant_amount);
+ break;
+ case ITEM_MOD_HIT_RANGED_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply);
+ sLog.outDebug("+ %u RANGED_HIT", enchant_amount);
+ break;
+ case ITEM_MOD_HIT_SPELL_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply);
+ sLog.outDebug("+ %u SPELL_HIT", enchant_amount);
+ break;
+ case ITEM_MOD_CRIT_MELEE_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply);
+ sLog.outDebug("+ %u MELEE_CRIT", enchant_amount);
+ break;
+ case ITEM_MOD_CRIT_RANGED_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply);
+ sLog.outDebug("+ %u RANGED_CRIT", enchant_amount);
+ break;
+ case ITEM_MOD_CRIT_SPELL_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply);
+ sLog.outDebug("+ %u SPELL_CRIT", enchant_amount);
+ break;
+// Values from ITEM_STAT_MELEE_HA_RATING to ITEM_MOD_HASTE_RANGED_RATING are never used
+// in Enchantments
+// case ITEM_MOD_HIT_TAKEN_MELEE_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply);
+// break;
+// case ITEM_MOD_HIT_TAKEN_RANGED_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply);
+// break;
+// case ITEM_MOD_HIT_TAKEN_SPELL_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply);
+// break;
+// case ITEM_MOD_CRIT_TAKEN_MELEE_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply);
+// break;
+// case ITEM_MOD_CRIT_TAKEN_RANGED_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply);
+// break;
+// case ITEM_MOD_CRIT_TAKEN_SPELL_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply);
+// break;
+// case ITEM_MOD_HASTE_MELEE_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply);
+// break;
+// case ITEM_MOD_HASTE_RANGED_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply);
+// break;
+ case ITEM_MOD_HASTE_SPELL_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply);
+ break;
+ case ITEM_MOD_HIT_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply);
+ ((Player*)this)->ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply);
+ ((Player*)this)->ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply);
+ sLog.outDebug("+ %u HIT", enchant_amount);
+ break;
+ case ITEM_MOD_CRIT_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply);
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply);
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply);
+ sLog.outDebug("+ %u CRITICAL", enchant_amount);
+ break;
+// Values ITEM_MOD_HIT_TAKEN_RATING and ITEM_MOD_CRIT_TAKEN_RATING are never used in Enchantment
+// case ITEM_MOD_HIT_TAKEN_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply);
+// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply);
+// ((Player*)this)->ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply);
+// break;
+// case ITEM_MOD_CRIT_TAKEN_RATING:
+// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply);
+// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply);
+// ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply);
+// break;
+ case ITEM_MOD_RESILIENCE_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply);
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply);
+ ((Player*)this)->ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply);
+ sLog.outDebug("+ %u RESILIENCE", enchant_amount);
+ break;
+ case ITEM_MOD_HASTE_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply);
+ ((Player*)this)->ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply);
+ ((Player*)this)->ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply);
+ sLog.outDebug("+ %u HASTE", enchant_amount);
+ break;
+ case ITEM_MOD_EXPERTISE_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_EXPERTISE, enchant_amount, apply);
+ sLog.outDebug("+ %u EXPERTISE", enchant_amount);
+ break;
+ case ITEM_MOD_ATTACK_POWER:
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply);
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
+ sLog.outDebug("+ %u ATTACK_POWER", enchant_amount);
+ break;
+ case ITEM_MOD_RANGED_ATTACK_POWER:
+ HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
+ sLog.outDebug("+ %u RANGED_ATTACK_POWER", enchant_amount);
+ break;
+ case ITEM_MOD_FERAL_ATTACK_POWER:
+ ((Player*)this)->ApplyFeralAPBonus(enchant_amount, apply);
+ sLog.outDebug("+ %u FERAL_ATTACK_POWER", enchant_amount);
+ break;
+ case ITEM_MOD_SPELL_HEALING_DONE:
+ ((Player*)this)->ApplySpellHealingBonus(enchant_amount, apply);
+ sLog.outDebug("+ %u SPELL_HEALING_DONE", enchant_amount);
+ break;
+ case ITEM_MOD_SPELL_DAMAGE_DONE:
+ ((Player*)this)->ApplySpellDamageBonus(enchant_amount, apply);
+ sLog.outDebug("+ %u SPELL_DAMAGE_DONE", enchant_amount);
+ break;
+ case ITEM_MOD_MANA_REGENERATION:
+ ((Player*)this)->ApplyManaRegenBonus(enchant_amount, apply);
+ sLog.outDebug("+ %u MANA_REGENERATION", enchant_amount);
+ break;
+ case ITEM_MOD_ARMOR_PENETRATION_RATING:
+ ((Player*)this)->ApplyRatingMod(CR_ARMOR_PENETRATION, enchant_amount, apply);
+ sLog.outDebug("+ %u ARMOR PENETRATION", enchant_amount);
+ break;
+ case ITEM_MOD_SPELL_POWER:
+ ((Player*)this)->ApplySpellHealingBonus(enchant_amount, apply);
+ ((Player*)this)->ApplySpellDamageBonus(enchant_amount, apply);
+ sLog.outDebug("+ %u SPELL_POWER", enchant_amount);
+ break;
+ default:
+ break;
}
- else if(item->GetSlot() == EQUIPMENT_SLOT_OFFHAND )
+ break;
+ }
+ case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon
+ {
+ if(getClass() == CLASS_SHAMAN)
{
- addValue = float(enchant_amount * item->GetProto()->Delay/1000.0f);
- HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, addValue, apply);
+ float addValue = 0.0f;
+ if(item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
+ {
+ addValue = float(enchant_amount * item->GetProto()->Delay/1000.0f);
+ HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply);
+ }
+ else if(item->GetSlot() == EQUIPMENT_SLOT_OFFHAND )
+ {
+ addValue = float(enchant_amount * item->GetProto()->Delay/1000.0f);
+ HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, addValue, apply);
+ }
}
+ break;
}
- break;
- }
- default:
- sLog.outError("Unknown item enchantment display type: %d",enchant_display_type);
- break;
- } /*switch(enchant_display_type)*/
- } /*for*/
+ case ITEM_ENCHANTMENT_TYPE_USE_SPELL:
+ // processed in Player::CastItemUseSpell
+ break;
+ case ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET:
+ // nothing do..
+ break;
+ default:
+ sLog.outError("Unknown item enchantment (id = %d) display type: %d", enchant_id, enchant_display_type);
+ break;
+ } /*switch(enchant_display_type)*/
+ } /*for*/
+ }
// visualize enchantment at player and equipped items
if(slot < MAX_INSPECTED_ENCHANTMENT_SLOT)
@@ -11957,7 +12193,7 @@ void Player::SendNewItem(Item *item, uint32 count, bool received, bool created,
data << GetItemCount(item->GetEntry()); // count of items in inventory
if (broadcast && GetGroup())
- GetGroup()->BroadcastPacket(&data);
+ GetGroup()->BroadcastPacket(&data, true);
else
GetSession()->SendPacket(&data);
}
@@ -11971,7 +12207,9 @@ void Player::PrepareQuestMenu( uint64 guid )
Object *pObject;
QuestRelations* pObjectQR;
QuestRelations* pObjectQIR;
- Creature *pCreature = ObjectAccessor::GetCreature(*this, guid);
+
+ // pets also can have quests
+ Creature *pCreature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid);
if( pCreature )
{
pObject = (Object*)pCreature;
@@ -11980,7 +12218,7 @@ void Player::PrepareQuestMenu( uint64 guid )
}
else
{
- GameObject *pGameObject = ObjectAccessor::GetGameObject(*this, guid);
+ GameObject *pGameObject = GetMap()->GetGameObject(guid);
if( pGameObject )
{
pObject = (Object*)pGameObject;
@@ -12057,11 +12295,13 @@ void Player::SendPreparedQuest( uint64 guid )
qe._Delay = 0;
qe._Emote = 0;
std::string title = "";
- Creature *pCreature = ObjectAccessor::GetCreature(*this, guid);
+
+ // need pet case for some quests
+ Creature *pCreature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid);
if( pCreature )
{
uint32 textid = pCreature->GetNpcTextId();
- GossipText * gossiptext = objmgr.GetGossipText(textid);
+ GossipText const* gossiptext = objmgr.GetGossipText(textid);
if( !gossiptext )
{
qe._Delay = 0; //TEXTEMOTE_MESSAGE; //zyg: player emote
@@ -12121,7 +12361,7 @@ Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest )
QuestRelations* pObjectQR;
QuestRelations* pObjectQIR;
- Creature *pCreature = ObjectAccessor::GetCreature(*this, guid);
+ Creature *pCreature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid);
if( pCreature )
{
pObject = (Object*)pCreature;
@@ -12130,7 +12370,7 @@ Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest )
}
else
{
- GameObject *pGameObject = ObjectAccessor::GetGameObject(*this, guid);
+ GameObject *pGameObject = GetMap()->GetGameObject(guid);
if( pGameObject )
{
pObject = (Object*)pGameObject;
@@ -12184,14 +12424,14 @@ bool Player::CanAddQuest( Quest const *pQuest, bool msg )
{
uint32 count = pQuest->GetSrcItemCount();
ItemPosCountVec dest;
- uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count );
+ uint8 msg2 = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count );
// player already have max number (in most case 1) source item, no additional item needed and quest can be added.
- if( msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
+ if( msg2 == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
return true;
- else if( msg != EQUIP_ERR_OK )
+ else if( msg2 != EQUIP_ERR_OK )
{
- SendEquipError( msg, NULL, NULL );
+ SendEquipError( msg2, NULL, NULL );
return false;
}
}
@@ -12252,7 +12492,7 @@ bool Player::CanCompleteQuest( uint32 quest_id )
}
uint32 repFacId = qInfo->GetRepObjectiveFaction();
- if ( repFacId && GetReputation(repFacId) < qInfo->GetRepObjectiveValue() )
+ if ( repFacId && GetReputationMgr().GetReputation(repFacId) < qInfo->GetRepObjectiveValue() )
return false;
return true;
@@ -12365,8 +12605,6 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
// if not exist then created with set uState==NEW and rewarded=false
QuestStatusData& questStatusData = mQuestStatus[quest_id];
- if (questStatusData.uState != QUEST_NEW)
- questStatusData.uState = QUEST_CHANGED;
// check for repeatable quests status reset
questStatusData.m_status = QUEST_STATUS_INCOMPLETE;
@@ -12374,21 +12612,22 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
if ( pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER ) )
{
- for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
+ for(int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
questStatusData.m_itemcount[i] = 0;
}
if ( pQuest->HasFlag(QUEST_TRINITY_FLAGS_KILL_OR_CAST | QUEST_TRINITY_FLAGS_SPEAKTO) )
{
- for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
+ for(int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
questStatusData.m_creatureOrGOcount[i] = 0;
}
GiveQuestSourceItem( pQuest );
- AdjustQuestReqItemCount( pQuest );
+ AdjustQuestReqItemCount( pQuest, questStatusData );
if( pQuest->GetRepObjectiveFaction() )
- SetFactionVisibleForFactionId(pQuest->GetRepObjectiveFaction());
+ if(FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->GetRepObjectiveFaction()))
+ GetReputationMgr().SetVisible(factionEntry);
uint32 qtime = 0;
if( pQuest->HasFlag( QUEST_TRINITY_FLAGS_TIMED ) )
@@ -12397,10 +12636,10 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
// shared timed quest
if(questGiver && questGiver->GetTypeId()==TYPEID_PLAYER)
- limittime = ((Player*)questGiver)->getQuestStatusMap()[quest_id].m_timer / 1000;
+ limittime = ((Player*)questGiver)->getQuestStatusMap()[quest_id].m_timer / IN_MILISECONDS;
AddTimedQuest( quest_id );
- questStatusData.m_timer = limittime * 1000;
+ questStatusData.m_timer = limittime * IN_MILISECONDS;
qtime = static_cast<uint32>(time(NULL)) + limittime;
}
else
@@ -12408,11 +12647,27 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
SetQuestSlot(log_slot, quest_id, qtime);
+ if (questStatusData.uState != QUEST_NEW)
+ questStatusData.uState = QUEST_CHANGED;
+
//starting initial quest script
if(questGiver && pQuest->GetQuestStartScript()!=0)
sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this);
- UpdateForQuestsGO();
+ // Some spells applied at quest activation
+ SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,true);
+ if(saBounds.first != saBounds.second)
+ {
+ uint32 zone, area;
+ GetZoneAndAreaId(zone,area);
+
+ for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
+ if(itr->second->autocast && itr->second->IsFitToRequirements(this,zone,area))
+ if( !HasAura(itr->second->spellId) )
+ CastSpell(this,itr->second->spellId,true);
+ }
+
+ UpdateForQuestWorldObjects();
}
void Player::CompleteQuest( uint32 quest_id )
@@ -12509,10 +12764,20 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
GiveXP( XP , NULL );
else
- ModifyMoney( int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)) );
+ {
+ uint32 money = uint32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY));
+ ModifyMoney( money );
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, money);
+ }
// Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative
- ModifyMoney( pQuest->GetRewOrReqMoney() );
+ if(pQuest->GetRewOrReqMoney())
+ {
+ ModifyMoney( pQuest->GetRewOrReqMoney() );
+
+ if(pQuest->GetRewOrReqMoney() > 0)
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney());
+ }
// honor reward
if(pQuest->GetRewHonorableKills())
@@ -12525,6 +12790,12 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
SetTitle(titleEntry);
}
+ if(pQuest->GetBonusTalents())
+ {
+ m_questRewardTalentCount+=pQuest->GetBonusTalents();
+ InitTalentForLevel();
+ }
+
// Send reward mail
if(pQuest->GetRewMailTemplateId())
{
@@ -12556,12 +12827,13 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
Loot questMailLoot;
- questMailLoot.FillLoot(pQuest->GetQuestId(), LootTemplates_QuestMail, this);
+ questMailLoot.FillLoot(pQuest->GetQuestId(), LootTemplates_QuestMail, this,true);
// fill mail
MailItemsInfo mi; // item list preparing
- for(size_t i = 0; mi.size() < MAX_MAIL_ITEMS && i < questMailLoot.items.size(); ++i)
+ uint32 max_slot = questMailLoot.GetMaxSlotInLootFor(this);
+ for(uint32 i = 0; mi.size() < MAX_MAIL_ITEMS && i < max_slot; ++i)
{
if(LootItem* lootitem = questMailLoot.LootItemInSlot(i,this))
{
@@ -12573,23 +12845,14 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
}
}
- for(size_t i = 0; mi.size() < MAX_MAIL_ITEMS && i < questMailLoot.quest_items.size(); ++i)
- {
- if(LootItem* lootitem = questMailLoot.LootItemInSlot(i+questMailLoot.items.size(),this))
- {
- if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this))
- {
- item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
- mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
- }
- }
- }
-
WorldSession::SendMailTo(this, mailType, MAIL_STATIONERY_NORMAL, senderGuidOrEntry, GetGUIDLow(), "", 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE,pQuest->GetRewMailDelaySecs(),pQuest->GetRewMailTemplateId());
}
if(pQuest->IsDaily())
+ {
SetDailyQuestStatus(quest_id);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, 1);
+ }
if ( !pQuest->IsRepeatable() )
SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE);
@@ -12602,6 +12865,37 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
SendQuestReward( pQuest, XP, questGiver );
if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
+ if (pQuest->GetZoneOrSort() > 0)
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, pQuest->GetZoneOrSort());
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST, pQuest->GetQuestId());
+
+ uint32 zone = 0;
+ uint32 area = 0;
+
+ // remove auras from spells with quest reward state limitations
+ SpellAreaForQuestMapBounds saEndBounds = spellmgr.GetSpellAreaForQuestEndMapBounds(quest_id);
+ if(saEndBounds.first != saEndBounds.second)
+ {
+ GetZoneAndAreaId(zone,area);
+
+ for(SpellAreaForAreaMap::const_iterator itr = saEndBounds.first; itr != saEndBounds.second; ++itr)
+ if(!itr->second->IsFitToRequirements(this,zone,area))
+ RemoveAurasDueToSpell(itr->second->spellId);
+ }
+
+ // Some spells applied at quest reward
+ SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,false);
+ if(saBounds.first != saBounds.second)
+ {
+ if(!zone || !area)
+ GetZoneAndAreaId(zone,area);
+
+ for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
+ if(itr->second->autocast && itr->second->IsFitToRequirements(this,zone,area))
+ if( !HasAura(itr->second->spellId) )
+ CastSpell(this,itr->second->spellId,true);
+ }
}
void Player::FailQuest( uint32 quest_id )
@@ -12626,8 +12920,9 @@ void Player::FailTimedQuest( uint32 quest_id )
{
QuestStatusData& q_status = mQuestStatus[quest_id];
- if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
q_status.m_timer = 0;
+ if (q_status.uState != QUEST_NEW)
+ q_status.uState = QUEST_CHANGED;
IncompleteQuest( quest_id );
@@ -12737,14 +13032,14 @@ bool Player::SatisfyQuestPreviousQuest( Quest const* qInfo, bool msg )
// each-from-all exclusive group ( < 0)
// can be start if only all quests in prev quest exclusive group completed and rewarded
- ObjectMgr::ExclusiveQuestGroups::iterator iter = objmgr.mExclusiveQuestGroups.lower_bound(qPrevInfo->GetExclusiveGroup());
+ ObjectMgr::ExclusiveQuestGroups::iterator iter2 = objmgr.mExclusiveQuestGroups.lower_bound(qPrevInfo->GetExclusiveGroup());
ObjectMgr::ExclusiveQuestGroups::iterator end = objmgr.mExclusiveQuestGroups.upper_bound(qPrevInfo->GetExclusiveGroup());
- assert(iter!=end); // always must be found if qPrevInfo->ExclusiveGroup != 0
+ assert(iter2!=end); // always must be found if qPrevInfo->ExclusiveGroup != 0
- for(; iter != end; ++iter)
+ for(; iter2 != end; ++iter2)
{
- uint32 exclude_Id = iter->second;
+ uint32 exclude_Id = iter2->second;
// skip checked quest id, only state of other quests in group is interesting
if(exclude_Id == prevId)
@@ -12772,14 +13067,14 @@ bool Player::SatisfyQuestPreviousQuest( Quest const* qInfo, bool msg )
// each-from-all exclusive group ( < 0)
// can be start if only all quests in prev quest exclusive group active
- ObjectMgr::ExclusiveQuestGroups::iterator iter = objmgr.mExclusiveQuestGroups.lower_bound(qPrevInfo->GetExclusiveGroup());
+ ObjectMgr::ExclusiveQuestGroups::iterator iter2 = objmgr.mExclusiveQuestGroups.lower_bound(qPrevInfo->GetExclusiveGroup());
ObjectMgr::ExclusiveQuestGroups::iterator end = objmgr.mExclusiveQuestGroups.upper_bound(qPrevInfo->GetExclusiveGroup());
- assert(iter!=end); // always must be found if qPrevInfo->ExclusiveGroup != 0
+ assert(iter2!=end); // always must be found if qPrevInfo->ExclusiveGroup != 0
- for(; iter != end; ++iter)
+ for(; iter2 != end; ++iter2)
{
- uint32 exclude_Id = iter->second;
+ uint32 exclude_Id = iter2->second;
// skip checked quest id, only state of other quests in group is interesting
if(exclude_Id == prevId)
@@ -12827,7 +13122,7 @@ bool Player::SatisfyQuestRace( Quest const* qInfo, bool msg )
bool Player::SatisfyQuestReputation( Quest const* qInfo, bool msg )
{
uint32 fIdMin = qInfo->GetRequiredMinRepFaction(); //Min required rep
- if(fIdMin && GetReputation(fIdMin) < qInfo->GetRequiredMinRepValue())
+ if(fIdMin && GetReputationMgr().GetReputation(fIdMin) < qInfo->GetRequiredMinRepValue())
{
if( msg )
SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
@@ -12835,7 +13130,7 @@ bool Player::SatisfyQuestReputation( Quest const* qInfo, bool msg )
}
uint32 fIdMax = qInfo->GetRequiredMaxRepFaction(); //Max required rep
- if(fIdMax && GetReputation(fIdMax) >= qInfo->GetRequiredMaxRepValue())
+ if(fIdMax && GetReputationMgr().GetReputation(fIdMax) >= qInfo->GetRequiredMaxRepValue())
{
if( msg )
SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
@@ -13103,7 +13398,7 @@ void Player::SetQuestStatus( uint32 quest_id, QuestStatus status )
if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
}
- UpdateForQuestsGO();
+ UpdateForQuestWorldObjects();
}
// not used in TrinIty, but used in scripting code
@@ -13113,28 +13408,26 @@ uint32 Player::GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry)
if( !qInfo )
return 0;
- for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++)
+ for (int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
if ( qInfo->ReqCreatureOrGOId[j] == entry )
return mQuestStatus[quest_id].m_creatureOrGOcount[j];
return 0;
}
-void Player::AdjustQuestReqItemCount( Quest const* pQuest )
+void Player::AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData )
{
if ( pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER ) )
{
- for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
+ for(int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
{
uint32 reqitemcount = pQuest->ReqItemCount[i];
if( reqitemcount != 0 )
{
- uint32 quest_id = pQuest->GetQuestId();
uint32 curitemcount = GetItemCount(pQuest->ReqItemId[i],true);
- QuestStatusData& q_status = mQuestStatus[quest_id];
- q_status.m_itemcount[i] = std::min(curitemcount, reqitemcount);
- if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
+ questStatusData.m_itemcount[i] = std::min(curitemcount, reqitemcount);
+ if (questStatusData.uState != QUEST_NEW) questStatusData.uState = QUEST_CHANGED;
}
}
}
@@ -13142,7 +13435,7 @@ void Player::AdjustQuestReqItemCount( Quest const* pQuest )
uint16 Player::FindQuestSlot( uint32 quest_id ) const
{
- for ( uint16 i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
+ for ( uint16 i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
if ( GetQuestSlotQuestId(i) == quest_id )
return i;
@@ -13190,7 +13483,7 @@ void Player::GroupEventHappens( uint32 questId, WorldObject const* pEventObject
void Player::ItemAddedQuestCheck( uint32 entry, uint32 count )
{
- for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
{
uint32 questid = GetQuestSlotQuestId(i);
if ( questid == 0 )
@@ -13226,12 +13519,12 @@ void Player::ItemAddedQuestCheck( uint32 entry, uint32 count )
}
}
}
- UpdateForQuestsGO();
+ UpdateForQuestWorldObjects();
}
void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count )
{
- for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
{
uint32 questid = GetQuestSlotQuestId(i);
if(!questid)
@@ -13267,13 +13560,14 @@ void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count )
}
}
}
- UpdateForQuestsGO();
+ UpdateForQuestWorldObjects();
}
void Player::KilledMonster( uint32 entry, uint64 guid )
{
uint32 addkillcount = 1;
- for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, entry, addkillcount);
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
{
uint32 questid = GetQuestSlotQuestId(i);
if(!questid)
@@ -13328,7 +13622,7 @@ void Player::CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id )
bool isCreature = IS_CREATURE_GUID(guid);
uint32 addCastCount = 1;
- for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
{
uint32 questid = GetQuestSlotQuestId(i);
if(!questid)
@@ -13395,7 +13689,7 @@ void Player::CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id )
void Player::TalkedToCreature( uint32 entry, uint64 guid )
{
uint32 addTalkCount = 1;
- for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
{
uint32 questid = GetQuestSlotQuestId(i);
if(!questid)
@@ -13450,7 +13744,7 @@ void Player::TalkedToCreature( uint32 entry, uint64 guid )
void Player::MoneyChanged( uint32 count )
{
- for( int i = 0; i < MAX_QUEST_LOG_SIZE; i++ )
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
{
uint32 questid = GetQuestSlotQuestId(i);
if (!questid)
@@ -13478,15 +13772,51 @@ void Player::MoneyChanged( uint32 count )
}
}
+void Player::ReputationChanged(FactionEntry const* factionEntry )
+{
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
+ {
+ if(uint32 questid = GetQuestSlotQuestId(i))
+ {
+ if(Quest const* qInfo = objmgr.GetQuestTemplate(questid))
+ {
+ if(qInfo->GetRepObjectiveFaction() == factionEntry->ID )
+ {
+ QuestStatusData& q_status = mQuestStatus[questid];
+ if( q_status.m_status == QUEST_STATUS_INCOMPLETE )
+ {
+ if(GetReputationMgr().GetReputation(factionEntry) >= qInfo->GetRepObjectiveValue())
+ if ( CanCompleteQuest( questid ) )
+ CompleteQuest( questid );
+ }
+ else if( q_status.m_status == QUEST_STATUS_COMPLETE )
+ {
+ if(GetReputationMgr().GetReputation(factionEntry) < qInfo->GetRepObjectiveValue())
+ IncompleteQuest( questid );
+ }
+ }
+ }
+ }
+ }
+}
+
bool Player::HasQuestForItem( uint32 itemid ) const
{
- for( QuestStatusMap::const_iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i )
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
{
- QuestStatusData const& q_status = i->second;
+ uint32 questid = GetQuestSlotQuestId(i);
+ if ( questid == 0 )
+ continue;
+
+ QuestStatusMap::const_iterator qs_itr = mQuestStatus.find(questid);
+ if(qs_itr == mQuestStatus.end())
+ continue;
+
+ QuestStatusData const& q_status = qs_itr->second;
if (q_status.m_status == QUEST_STATUS_INCOMPLETE)
{
- Quest const* qinfo = objmgr.GetQuestTemplate(i->first);
+ Quest const* qinfo = objmgr.GetQuestTemplate(questid);
if(!qinfo)
continue;
@@ -13506,28 +13836,21 @@ bool Player::HasQuestForItem( uint32 itemid ) const
for (int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; j++)
{
// examined item is a source item
- if (qinfo->ReqSourceId[j] == itemid && qinfo->ReqSourceRef[j] > 0 && qinfo->ReqSourceRef[j] <= QUEST_OBJECTIVES_COUNT)
+ if (qinfo->ReqSourceId[j] == itemid)
{
- uint32 idx = qinfo->ReqSourceRef[j]-1;
+ ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
- // total count of created ReqItems and SourceItems is less than ReqItemCount
- if(qinfo->ReqItemId[idx] != 0 &&
- q_status.m_itemcount[idx] * qinfo->ReqSourceCount[j] + GetItemCount(itemid,true) < qinfo->ReqItemCount[idx] * qinfo->ReqSourceCount[j])
+ // 'unique' item
+ if (pProto->MaxCount && GetItemCount(itemid,true) < pProto->MaxCount)
return true;
- // total count of casted ReqCreatureOrGOs and SourceItems is less than ReqCreatureOrGOCount
- if (qinfo->ReqCreatureOrGOId[idx] != 0)
- {
- if(q_status.m_creatureOrGOcount[idx] * qinfo->ReqSourceCount[j] + GetItemCount(itemid,true) < qinfo->ReqCreatureOrGOCount[idx] * qinfo->ReqSourceCount[j])
- return true;
- }
- // spell with SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT (with script) case
- else if(qinfo->ReqSpell[idx] != 0)
+ // allows custom amount drop when not 0
+ if (qinfo->ReqSourceCount[j])
{
- // not casted and need more reagents/item for use.
- if(!q_status.m_explored && GetItemCount(itemid,true) < qinfo->ReqSourceCount[j])
+ if (GetItemCount(itemid,true) < qinfo->ReqSourceCount[j])
return true;
- }
+ } else if (GetItemCount(itemid,true) < pProto->Stackable)
+ return true;
}
}
}
@@ -13551,13 +13874,12 @@ void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGive
uint32 questid = pQuest->GetQuestId();
sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid );
gameeventmgr.HandleQuestComplete(questid);
- WorldPacket data( SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4+4+pQuest->GetRewItemsCount()*8) );
- data << questid;
- data << uint32(0x03);
+ WorldPacket data( SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4) );
+ data << uint32(questid);
if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
{
- data << XP;
+ data << uint32(XP);
data << uint32(pQuest->GetRewOrReqMoney());
}
else
@@ -13565,16 +13887,9 @@ void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGive
data << uint32(0);
data << uint32(pQuest->GetRewOrReqMoney() + int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)));
}
- data << uint32(0); // new 2.3.0, HonorPoints?
- data << uint32( pQuest->GetRewItemsCount() ); // max is 5
- for (uint32 i = 0; i < pQuest->GetRewItemsCount(); ++i)
- {
- if ( pQuest->RewItemId[i] > 0 )
- data << pQuest->RewItemId[i] << pQuest->RewItemCount[i];
- else
- data << uint32(0) << uint32(0);
- }
+ data << uint32(10*Trinity::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills()));
+ data << uint32(pQuest->GetBonusTalents()); // bonus talents
GetSession()->SendPacket( &data );
if (pQuest->GetQuestCompleteScript() != 0)
@@ -13585,8 +13900,9 @@ void Player::SendQuestFailed( uint32 quest_id )
{
if( quest_id )
{
- WorldPacket data( SMSG_QUESTGIVER_QUEST_FAILED, 4 );
+ WorldPacket data( SMSG_QUESTGIVER_QUEST_FAILED, 4+4 );
data << quest_id;
+ data << uint32(0); // failed reason (4 for inventory is full)
GetSession()->SendPacket( &data );
sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED");
}
@@ -13625,10 +13941,10 @@ void Player::SendPushToPartyResponse( Player *pPlayer, uint32 msg )
void Player::SendQuestUpdateAddItem( Quest const* pQuest, uint32 item_idx, uint32 count )
{
- WorldPacket data( SMSG_QUESTUPDATE_ADD_ITEM, (4+4) );
+ WorldPacket data( SMSG_QUESTUPDATE_ADD_ITEM, 0 );
sLog.outDebug( "WORLD: Sent SMSG_QUESTUPDATE_ADD_ITEM" );
- data << pQuest->ReqItemId[item_idx];
- data << count;
+ //data << pQuest->ReqItemId[item_idx];
+ //data << count;
GetSession()->SendPacket( &data );
}
@@ -13662,20 +13978,23 @@ void Player::SendQuestUpdateAddCreatureOrGo( Quest const* pQuest, uint64 guid, u
bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid )
{
bool delete_result = true;
- if(!result)
+ if (!result)
{
- // 0 1 2 3 4 5 6 7 8 9
- result = CharacterDatabase.PQuery("SELECT guid, data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login FROM characters WHERE guid = '%u'",guid);
- if(!result) return false;
+ // 0 1 2 3 4 5 6 7 8 9 10
+ result = CharacterDatabase.PQuery("SELECT guid, data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login, zone FROM characters WHERE guid = '%u'",guid);
+ if (!result)
+ return false;
}
- else delete_result = false;
+ else
+ delete_result = false;
Field *fields = result->Fetch();
- if(!LoadValues( fields[1].GetString()))
+ if (!LoadValues( fields[1].GetString()))
{
- sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid));
- if(delete_result) delete result;
+ sLog.outError("Player #%d have broken data in `data` field. Can't be loaded for character list.",GUID_LOPART(guid));
+ if (delete_result)
+ delete result;
return false;
}
@@ -13698,12 +14017,13 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid )
_LoadBoundInstances();*/
- if (delete_result) delete result;
+ if (delete_result)
+ delete result;
for (int i = 0; i < PLAYER_SLOTS_COUNT; i++)
m_items[i] = NULL;
- if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST) )
+ if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
m_deathState = DEAD;
return true;
@@ -13744,7 +14064,7 @@ void Player::_LoadArenaTeamInfo(QueryResult *result)
ArenaTeam* aTeam = objmgr.GetArenaTeamById(arenateamid);
if(!aTeam)
{
- sLog.outError("FATAL: couldn't load arenateam %u", arenateamid);
+ sLog.outError("Player::_LoadArenaTeamInfo: couldn't load arenateam %u, week %u, season %u, rating %u", arenateamid, played_week, played_season, personal_rating);
continue;
}
uint8 arenaSlot = aTeam->GetSlot();
@@ -13862,13 +14182,13 @@ float Player::GetFloatValueFromDB(uint16 index, uint64 guid)
bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
{
- //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [28] [29] 30 31 32 33
- //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points FROM characters WHERE guid = '%u'", guid);
+ //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [28] [29] 30 31 32 33 34 35 36 37 38 39 40
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", guid);
QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM);
if(!result)
{
- sLog.outError("ERROR: Player (GUID: %u) not found in table `characters`, can't load. ",guid);
+ sLog.outError("Player (GUID: %u) not found in table `characters`, can't load. ",guid);
return false;
}
@@ -13880,7 +14200,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
// player should be able to load/delete character only with correct account!
if( dbAccountId != GetSession()->GetAccountId() )
{
- sLog.outError("ERROR: Player (GUID: %u) loading from wrong account (is: %u, should be: %u)",guid,GetSession()->GetAccountId(),dbAccountId);
+ sLog.outError("Player (GUID: %u) loading from wrong account (is: %u, should be: %u)",guid,GetSession()->GetAccountId(),dbAccountId);
delete result;
return false;
}
@@ -13890,7 +14210,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
m_name = fields[3].GetCppString();
// check name limitations
- if(!ObjectMgr::IsValidName(m_name) || GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name))
+ if(!ObjectMgr::IsValidName(m_name) || (GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name)))
{
delete result;
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid);
@@ -13899,7 +14219,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
if(!LoadValues( fields[2].GetString()))
{
- sLog.outError("ERROR: Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid));
+ sLog.outError("Player #%d have broken data in `data` field. Can't be loaded.",GUID_LOPART(guid));
delete result;
return false;
}
@@ -13931,24 +14251,20 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
//Need to call it to initialize m_team (m_team can be calculated from m_race)
//Other way is to saves m_team into characters table.
setFactionForRace(m_race);
- SetCharm(0);
m_class = fields[5].GetUInt8();
- PlayerInfo const *info = objmgr.GetPlayerInfo(m_race, m_class);
- if(!info)
- {
- sLog.outError("Player have incorrect race/class pair. Can't be loaded.");
- delete result;
+ // load home bind and check in same time class/race pair, it used later for restore broken positions
+ if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
return false;
- }
InitPrimaryProffesions(); // to max set before any spell loaded
+ // init saved position, and fix it later if problematic
uint32 transGUID = fields[24].GetUInt32();
Relocate(fields[6].GetFloat(),fields[7].GetFloat(),fields[8].GetFloat(),fields[10].GetFloat());
- SetFallInformation(0, fields[8].GetFloat());
SetMapId(fields[9].GetUInt32());
+ SetInstanceId(fields[41].GetFloat());
SetDifficulty(fields[32].GetUInt32()); // may be changed in _LoadGroup
_LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP));
@@ -13981,10 +14297,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
if(!IsPositionValid())
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
-
- SetMapId(info->mapId);
- Relocate(info->positionX,info->positionY,info->positionZ,0.0f);
+ sLog.outError("Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ RelocateToHomebind();
transGUID = 0;
@@ -13994,49 +14308,57 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
m_movementInfo.t_o = 0.0f;
}
- if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
- return false;
+ uint32 bgid = fields[34].GetUInt32();
+ uint32 bgteam = fields[35].GetUInt32();
- // load the player's map here if it's not already loaded
- Map *map = GetMap();
- if (!map)
+ if(bgid) //saved in BattleGround
{
- AreaTrigger const* at = objmgr.GetGoBackTrigger(GetMapId());
- if(at)
+ SetBattleGroundEntryPoint(fields[36].GetUInt32(),fields[37].GetFloat(),fields[38].GetFloat(),fields[39].GetFloat(),fields[40].GetFloat());
+
+ // check entry point and fix to homebind if need
+ MapEntry const* mapEntry = sMapStore.LookupEntry(m_bgEntryPoint.mapid);
+ if(!mapEntry || mapEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint))
+ SetBattleGroundEntryPoint(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ,0.0f);
+
+ BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid, BATTLEGROUND_TYPE_NONE);
+
+ if(currentBg && currentBg->IsPlayerInBattleGround(GetGUID()))
{
- SetMapId(at->target_mapId);
- Relocate(at->target_X, at->target_Y, at->target_Z, GetOrientation());
- sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ BattleGroundQueueTypeId bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType());
+ AddBattleGroundQueueId(bgQueueTypeId);
+
+ SetBattleGroundId(currentBg->GetInstanceID(), currentBg->GetTypeID());
+ SetBGTeam(bgteam);
+
+ //join player to battleground group
+ currentBg->EventPlayerLoggedIn(this, GetGUID());
+ currentBg->AddOrSetPlayerToCorrectBgGroup(this, GetGUID(), bgteam);
+
+ SetInviteForBattleGroundQueueType(bgQueueTypeId,currentBg->GetInstanceID());
}
else
{
- SetMapId(m_homebindMapId);
- Relocate(m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
- sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ Relocate(GetBattleGroundEntryPoint());
+ //RemoveArenaAuras(true);
}
-
- map = GetMap();
- if(!map)
+ }
+ else
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId());
+ // if server restart after player save in BG or area
+ // player can have current coordinates in to BG/Arean map, fix this
+ if(!mapEntry || mapEntry->IsBattleGroundOrArena())
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
-
- SetMapId(info->mapId);
- Relocate(info->positionX,info->positionY,info->positionZ,0.0f);
+ // return to BG master
+ SetMapId(fields[36].GetUInt32());
+ Relocate(fields[37].GetFloat(),fields[38].GetFloat(),fields[39].GetFloat(),fields[40].GetFloat());
- map = GetMap();
- if(!map)
- {
- sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
- sLog.outError("CRASH.");
- assert(false);
- }
+ // check entry point and fix to homebind if need
+ mapEntry = sMapStore.LookupEntry(GetMapId());
+ if(!mapEntry || mapEntry->IsBattleGroundOrArena() || !IsPositionValid())
+ RelocateToHomebind();
}
}
- // since the player may not be bound to the map yet, make sure subsequent
- // getmap calls won't create new maps
- SetInstanceId(map->GetInstanceId());
-
- SaveRecallPosition();
if (transGUID != 0)
{
@@ -14051,12 +14373,11 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
// transport size limited
m_movementInfo.t_x > 50 || m_movementInfo.t_y > 50 || m_movementInfo.t_z > 50 )
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",
+ sLog.outError("Player (guidlow %d) have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",
guid,GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y,
GetPositionZ()+m_movementInfo.t_z,GetOrientation()+m_movementInfo.t_o);
- SetMapId(info->mapId);
- Relocate(info->positionX,info->positionY,info->positionZ,0.0f);
+ RelocateToHomebind();
m_movementInfo.t_x = 0.0f;
m_movementInfo.t_y = 0.0f;
@@ -14073,6 +14394,14 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
{
if( (*iter)->GetGUIDLow() == transGUID)
{
+ MapEntry const* transMapEntry = sMapStore.LookupEntry((*iter)->GetMapId());
+ // client without expansion support
+ if(GetSession()->Expansion() < transMapEntry->Expansion())
+ {
+ sLog.outDebug("Player %s using client without required expansion tried login at transport at non accessible map %u", GetName(), (*iter)->GetMapId());
+ break;
+ }
+
m_transport = *iter;
m_transport->AddPassenger(this);
SetMapId(m_transport->GetMapId());
@@ -14082,11 +14411,10 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
if(!m_transport)
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid transport guid (%u). Teleport to default race/class locations.",
+ sLog.outError("Player (guidlow %d) have problems with transport guid (%u). Teleport to default race/class locations.",
guid,transGUID);
- SetMapId(info->mapId);
- Relocate(info->positionX,info->positionY,info->positionZ,0.0f);
+ RelocateToHomebind();
m_movementInfo.t_x = 0.0f;
m_movementInfo.t_y = 0.0f;
@@ -14096,6 +14424,71 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
transGUID = 0;
}
}
+ else // not transport case
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId());
+ // client without expansion support
+ if(GetSession()->Expansion() < mapEntry->Expansion())
+ {
+ sLog.outDebug("Player %s using client without required expansion tried login at non accessible map %u", GetName(), GetMapId());
+ RelocateToHomebind();
+ }
+ }
+
+ // NOW player must have valid map
+ // load the player's map here if it's not already loaded
+ Map *map = GetMap();
+
+ if (!map)
+ {
+ AreaTrigger const* at = objmgr.GetGoBackTrigger(GetMapId());
+ if(at)
+ {
+ SetMapId(at->target_mapId);
+ Relocate(at->target_X, at->target_Y, at->target_Z, GetOrientation());
+ sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ }
+ else
+ {
+ RelocateToHomebind();
+ sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ }
+
+ map = GetMap();
+ if(!map)
+ {
+ sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ delete result;
+ return false;
+
+ /*SetMapId(info->mapId);
+ Relocate(info->positionX,info->positionY,info->positionZ,0.0f);
+
+ map = GetMap();
+ if(!map)
+ {
+ sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ sLog.outError("CRASH.");
+ assert(false);
+ }*/
+ }
+ }
+
+ // since the player may not be bound to the map yet, make sure subsequent
+ // getmap calls won't create new maps
+ SetInstanceId(map->GetInstanceId());
+
+ // if the player is in an instance and it has been reset in the meantime teleport him to the entrance
+ if(GetInstanceId() && !sInstanceSaveManager.GetInstanceSave(GetInstanceId()))
+ {
+ AreaTrigger const* at = objmgr.GetMapEntranceTrigger(GetMapId());
+ if(at)
+ Relocate(at->target_X, at->target_Y, at->target_Z, at->target_Orientation);
+ else
+ sLog.outError("Player %s(GUID: %u) logged in to a reset instance (map: %u) and there is no aretrigger leading to this map. Thus he can't be ported back to the entrance. This _might_ be an exploit attempt.", GetName(), GetGUIDLow(), GetMapId());
+ }
+
+ SaveRecallPosition();
time_t now = time(NULL);
time_t logoutTime = time_t(fields[16].GetUInt64());
@@ -14146,10 +14539,10 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
uint32 extraflags = fields[25].GetUInt32();
m_stableSlots = fields[26].GetUInt32();
- if(m_stableSlots > 2)
+ if(m_stableSlots > MAX_PET_STABLES)
{
- sLog.outError("Player can have not more 2 stable slots, but have in DB %u",uint32(m_stableSlots));
- m_stableSlots = 2;
+ sLog.outError("Player can have not more %u stable slots, but have in DB %u",MAX_PET_STABLES,uint32(m_stableSlots));
+ m_stableSlots = MAX_PET_STABLES;
}
m_atLoginFlags = fields[27].GetUInt32();
@@ -14172,35 +14565,20 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
SetUInt32Value(UNIT_CHANNEL_SPELL,0);
// clear charm/summon related fields
- SetCharm(NULL);
- SetPet(NULL);
- SetCharmerGUID(NULL);
- SetOwnerGUID(NULL);
- SetCreatorGUID(NULL);
+ SetUInt64Value(UNIT_FIELD_SUMMONEDBY, 0);
+ SetUInt64Value(UNIT_FIELD_CHARMEDBY, 0);
+ SetUInt64Value(UNIT_FIELD_CHARM, 0);
+ SetUInt64Value(UNIT_FIELD_SUMMON, 0);
+ SetUInt64Value(PLAYER_FARSIGHT, 0);
+ SetCreatorGUID(0);
+
+ RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE);
// reset some aura modifiers before aura apply
- SetFarSight(NULL);
SetUInt32Value(PLAYER_TRACK_CREATURES, 0 );
SetUInt32Value(PLAYER_TRACK_RESOURCES, 0 );
- // reset skill modifiers and set correct unlearn flags
- for (uint32 i = 0; i < PLAYER_MAX_SKILLS; i++)
- {
- SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0);
-
- // set correct unlearn bit
- uint32 id = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF;
- if(!id) continue;
-
- SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id);
- if(!pSkill) continue;
-
- // enable unlearn button for primary professions only
- if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION)
- SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1));
- else
- SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0));
- }
+ _LoadSkills();
// make sure the unit is considered out of combat for proper loading
ClearInCombat();
@@ -14218,6 +14596,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
// reset stats before loading any modifiers
InitStatsForLevel();
InitTaxiNodesForLevel();
+ InitGlyphsForLevel();
+ InitRunes();
// apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
@@ -14225,25 +14605,25 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
//_LoadMail();
_LoadAuras(holder->GetResult(PLAYER_LOGIN_QUERY_LOADAURAS), time_diff);
-
+ _LoadGlyphAuras();
// add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura)
if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST) )
m_deathState = DEAD;
_LoadSpells(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSPELLS));
- // after spell load
- InitTalentForLevel();
- learnSkillRewardedSpells();
-
// after spell load, learn rewarded spell if need also
_LoadQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS));
_LoadDailyQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS));
+ // after spell and quest load
+ InitTalentForLevel();
+ learnDefaultSpells();
+
_LoadTutorials(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTUTORIALS));
// must be before inventory (some items required reputation check)
- _LoadReputation(holder->GetResult(PLAYER_LOGIN_QUERY_LOADREPUTATION));
+ m_reputationMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADREPUTATION));
_LoadInventory(holder->GetResult(PLAYER_LOGIN_QUERY_LOADINVENTORY), time_diff);
@@ -14257,9 +14637,6 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
m_social = sSocialMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSOCIALLIST), GetGUIDLow());
- //if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
- // return false;
-
// check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES
// note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded
if(uint32 curTitle = GetUInt32Value(PLAYER_CHOSEN_TITLE))
@@ -14269,7 +14646,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
}
// Not finish taxi flight path
- if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes))
+ if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam()))
{
// problems with taxi path loading
TaxiNodesEntry const* nodeEntry = NULL;
@@ -14279,8 +14656,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
if(!nodeEntry) // don't know taxi start node, to homebind
{
sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow());
- SetMapId(m_homebindMapId);
- Relocate( m_homebindX, m_homebindY, m_homebindZ,0.0f);
+ RelocateToHomebind();
SaveRecallPosition(); // save as recall also to prevent recall and fall from sky
}
else // have start node, to it
@@ -14305,6 +14681,9 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
// flight will started later
}
+ // has to be called after last Relocate() in Player::LoadFromDB
+ SetFallInformation(0, GetPositionZ());
+
_LoadSpellCooldowns(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS));
// Spell code allow apply any auras to dead character in load time in aura/spell/item loading
@@ -14349,6 +14728,17 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
break;
}
+ /*switch(sWorld.getConfig(CONFIG_GM_ACCEPT_TICKETS))
+ {
+ default:
+ case 0: break; // disable
+ case 1: SetAcceptTicket(true); break; // enable
+ case 2: // save state
+ if(extraflags & PLAYER_EXTRA_GM_ACCEPT_TICKETS)
+ SetAcceptTicket(true);
+ break;
+ }*/
+
switch(sWorld.getConfig(CONFIG_GM_CHAT))
{
default:
@@ -14374,6 +14764,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
_LoadDeclinedNames(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES));
+ m_achievementMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS), holder->GetResult(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS));
+ m_achievementMgr.CheckAllAchievementCriteria();
return true;
}
@@ -14414,9 +14806,15 @@ void Player::_LoadActions(QueryResult *result)
uint8 button = fields[0].GetUInt8();
- addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8());
+ if(addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8()))
+ m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED;
+ else
+ {
+ sLog.outError( " ...at loading, and will deleted in DB also");
- m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED;
+ // Will deleted in DB at next save (it can create data until save but marked as deleted)
+ m_actionButtons[button].uState = ACTIONBUTTON_DELETED;
+ }
}
while( result->NextRow() );
@@ -14426,45 +14824,36 @@ void Player::_LoadActions(QueryResult *result)
void Player::_LoadAuras(QueryResult *result, uint32 timediff)
{
- m_Auras.clear();
- for (int i = 0; i < TOTAL_AURAS; i++)
- m_modAuras[i].clear();
+ sLog.outDebug("Loading auras for player %u",GetGUIDLow());
- // all aura related fields
- for(int i = UNIT_FIELD_AURA; i <= UNIT_FIELD_AURASTATE; ++i)
- SetUInt32Value(i, 0);
-
- //QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'",GetGUIDLow());
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_mask,stackcount,amount0,amount1,amount2,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'",GetGUIDLow());
if(result)
{
do
{
+ int32 damage[3];
Field *fields = result->Fetch();
uint64 caster_guid = fields[0].GetUInt64();
uint32 spellid = fields[1].GetUInt32();
- uint32 effindex = fields[2].GetUInt32();
+ uint32 effmask = fields[2].GetUInt32();
uint32 stackcount = fields[3].GetUInt32();
- int32 damage = (int32)fields[4].GetUInt32();
- int32 maxduration = (int32)fields[5].GetUInt32();
- int32 remaintime = (int32)fields[6].GetUInt32();
- int32 remaincharges = (int32)fields[7].GetUInt32();
+ damage[0] = int32(fields[4].GetUInt32());
+ damage[1] = int32(fields[5].GetUInt32());
+ damage[2] = int32(fields[6].GetUInt32());
+ int32 maxduration = (int32)fields[7].GetUInt32();
+ int32 remaintime = (int32)fields[8].GetUInt32();
+ int32 remaincharges = (int32)fields[9].GetUInt32();
SpellEntry const* spellproto = sSpellStore.LookupEntry(spellid);
if(!spellproto)
{
- sLog.outError("Unknown aura (spellid %u, effindex %u), ignore.",spellid,effindex);
- continue;
- }
-
- if(effindex >= 3)
- {
- sLog.outError("Invalid effect index (spellid %u, effindex %u), ignore.",spellid,effindex);
+ sLog.outError("Unknown aura (spellid %u), ignore.",spellid);
continue;
}
// negative effects should continue counting down after logout
- if (remaintime != -1 && !IsPositiveEffect(spellid, effindex))
+ if (remaintime != -1 && !IsPositiveSpell(spellid))
{
if(remaintime <= int32(timediff))
continue;
@@ -14479,21 +14868,12 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
remaincharges = spellproto->procCharges;
}
else
- remaincharges = -1;
+ remaincharges = 0;
- //do not load single target auras (unless they were cast by the player)
- if (caster_guid != GetGUID() && IsSingleTargetSpell(spellproto))
- continue;
-
- for(uint32 i=0; i<stackcount; i++)
- {
- Aura* aura = CreateAura(spellproto, effindex, NULL, this, NULL);
- if(!damage)
- damage = aura->GetModifier()->m_amount;
- aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges);
- AddAura(aura);
- sLog.outDetail("Added aura spellid %u, effect %u", spellproto->Id, effindex);
- }
+ Aura* aura = new Aura(spellproto, effmask, NULL, this, NULL, NULL);
+ aura->SetLoadedState(caster_guid,maxduration,remaintime,remaincharges, stackcount, &damage[0]);
+ AddAura(aura);
+ sLog.outDetail("Added aura spellid %u, effectmask %u", spellproto->Id, effmask);
}
while( result->NextRow() );
@@ -14504,6 +14884,36 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
CastSpell(this,SPELL_ID_PASSIVE_BATTLE_STANCE,true);
}
+void Player::_LoadGlyphAuras()
+{
+ for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
+ {
+ if (uint32 glyph = GetGlyph(i))
+ {
+ if (GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
+ {
+ if (GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(GetGlyphSlot(i)))
+ {
+ if(gp->TypeFlags == gs->TypeFlags)
+ {
+ CastSpell(this, gp->SpellId, true);
+ continue;
+ }
+ else
+ sLog.outError("Player %s has glyph with typeflags %u in slot with typeflags %u, removing.", m_name.c_str(), gp->TypeFlags, gs->TypeFlags);
+ }
+ else
+ sLog.outError("Player %s has not existing glyph slot entry %u on index %u", m_name.c_str(), GetGlyphSlot(i), i);
+ }
+ else
+ sLog.outError("Player %s has not existing glyph entry %u on index %u", m_name.c_str(), glyph, i);
+
+ // On any error remove glyph
+ SetGlyph(i, 0);
+ }
+ }
+}
+
void Player::LoadCorpse()
{
if( isAlive() )
@@ -14679,15 +15089,16 @@ void Player::_LoadInventory(QueryResult *result, uint32 timediff)
// load mailed item which should receive current player
void Player::_LoadMailedItems(Mail *mail)
{
- QueryResult* result = CharacterDatabase.PQuery("SELECT item_guid, item_template FROM mail_items WHERE mail_id='%u'", mail->messageID);
+ // data needs to be at first place for Item::LoadFromDB
+ QueryResult* result = CharacterDatabase.PQuery("SELECT data, item_guid, item_template FROM mail_items JOIN item_instance ON item_guid = guid WHERE mail_id='%u'", mail->messageID);
if(!result)
return;
do
{
Field *fields = result->Fetch();
- uint32 item_guid_low = fields[0].GetUInt32();
- uint32 item_template = fields[1].GetUInt32();
+ uint32 item_guid_low = fields[1].GetUInt32();
+ uint32 item_template = fields[2].GetUInt32();
mail->AddItem(item_guid_low, item_template);
@@ -14703,7 +15114,7 @@ void Player::_LoadMailedItems(Mail *mail)
Item *item = NewItemOrBag(proto);
- if(!item->LoadFromDB(item_guid_low, 0))
+ if(!item->LoadFromDB(item_guid_low, 0, result))
{
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);
@@ -14789,7 +15200,7 @@ void Player::LoadPet()
// just not added to the map
if(IsInWorld())
{
- Pet *pet = new Pet;
+ Pet *pet = new Pet(this);
if(!pet->LoadPetFromDB(this,0,0,true))
delete pet;
}
@@ -14839,7 +15250,7 @@ void Player::_LoadQuestStatus(QueryResult *result)
if (quest_time <= sWorld.GetGameTime())
questStatusData.m_timer = 1;
else
- questStatusData.m_timer = (quest_time - sWorld.GetGameTime()) * 1000;
+ questStatusData.m_timer = (quest_time - sWorld.GetGameTime()) * IN_MILISECONDS;
}
else
quest_time = 0;
@@ -14884,6 +15295,9 @@ void Player::_LoadQuestStatus(QueryResult *result)
if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId()))
SetTitle(titleEntry);
}
+
+ if(pQuest->GetBonusTalents())
+ m_questRewardTalentCount+=pQuest->GetBonusTalents();
}
sLog.outDebug("Quest status is {%u} for quest {%u} for player (GUID: %u)", questStatusData.m_status, quest_id, GetGUIDLow());
@@ -14942,68 +15356,9 @@ void Player::_LoadDailyQuestStatus(QueryResult *result)
m_DailyQuestChanged = false;
}
-void Player::_LoadReputation(QueryResult *result)
-{
- m_factions.clear();
-
- // Set initial reputations (so everything is nifty before DB data load)
- SetInitialFactions();
-
- //QueryResult *result = CharacterDatabase.PQuery("SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'",GetGUIDLow());
-
- if(result)
- {
- do
- {
- Field *fields = result->Fetch();
-
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt32());
- if( factionEntry && (factionEntry->reputationListID >= 0))
- {
- FactionState* faction = &m_factions[factionEntry->reputationListID];
-
- // update standing to current
- faction->Standing = int32(fields[1].GetUInt32());
-
- uint32 dbFactionFlags = fields[2].GetUInt32();
-
- if( dbFactionFlags & FACTION_FLAG_VISIBLE )
- SetFactionVisible(faction); // have internal checks for forced invisibility
-
- if( dbFactionFlags & FACTION_FLAG_INACTIVE)
- SetFactionInactive(faction,true); // have internal checks for visibility requirement
-
- if( dbFactionFlags & FACTION_FLAG_AT_WAR ) // DB at war
- SetFactionAtWar(faction,true); // have internal checks for FACTION_FLAG_PEACE_FORCED
- else // DB not at war
- {
- // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN)
- if( faction->Flags & FACTION_FLAG_VISIBLE )
- SetFactionAtWar(faction,false); // have internal checks for FACTION_FLAG_PEACE_FORCED
- }
-
- // set atWar for hostile
- if(GetReputationRank(factionEntry) <= REP_HOSTILE)
- SetFactionAtWar(faction,true);
-
- // reset changed flag if values similar to saved in DB
- if(faction->Flags==dbFactionFlags)
- faction->Changed = false;
- }
- }
- while( result->NextRow() );
-
- delete result;
- }
-}
-
void Player::_LoadSpells(QueryResult *result)
{
- for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
- delete itr->second;
- m_spells.clear();
-
- //QueryResult *result = CharacterDatabase.PQuery("SELECT spell,slot,active FROM character_spell WHERE guid = '%u'",GetGUIDLow());
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT spell,active,disabled FROM character_spell WHERE guid = '%u'",GetGUIDLow());
if(result)
{
@@ -15011,7 +15366,7 @@ void Player::_LoadSpells(QueryResult *result)
{
Field *fields = result->Fetch();
- addSpell(fields[0].GetUInt16(), fields[2].GetBool(), false, true, fields[1].GetUInt16(), fields[3].GetBool());
+ addSpell(fields[0].GetUInt16(), fields[1].GetBool(), false, false, fields[2].GetBool());
}
while( result->NextRow() );
@@ -15083,6 +15438,14 @@ void Player::_LoadBoundInstances(QueryResult *result)
// so the value read from the DB may be wrong here but only if the InstanceSave is loaded
// and in that case it is not used
+ MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
+ if(!mapEntry || !mapEntry->IsDungeon())
+ {
+ sLog.outError("_LoadBoundInstances: player %s(%d) has bind to not existed or not dungeon map %d", GetName(), GetGUIDLow(), mapId);
+ CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId);
+ continue;
+ }
+
if(!perm && group)
{
sLog.outError("_LoadBoundInstances: player %s(%d) is in group %d but has a non-permanent character bind to map %d,%d,%d", GetName(), GetGUIDLow(), GUID_LOPART(group->GetLeaderGUID()), mapId, instanceId, difficulty);
@@ -15160,29 +15523,29 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave *save, bool permanent, b
void Player::SendRaidInfo()
{
+ uint32 counter = 0;
+
WorldPacket data(SMSG_RAID_INSTANCE_INFO, 4);
- uint32 counter = 0, i;
- for(i = 0; i < TOTAL_DIFFICULTIES; i++)
- for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
- if(itr->second.perm) counter++;
+ size_t p_counter = data.wpos();
+ data << uint32(counter); // placeholder
- data << counter;
- for(i = 0; i < TOTAL_DIFFICULTIES; i++)
+ for(int i = 0; i < TOTAL_DIFFICULTIES; ++i)
{
for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
{
if(itr->second.perm)
{
InstanceSave *save = itr->second.save;
- data << (save->GetMapId());
- data << (uint32)(save->GetResetTime() - time(NULL));
- data << save->GetInstanceId();
- data << uint32(counter);
- counter--;
+ data << uint32(save->GetMapId());
+ data << uint32(save->GetResetTime() - time(NULL));
+ data << uint32(save->GetInstanceId());
+ data << uint32(save->GetDifficulty());
+ ++counter;
}
}
}
+ data.put<uint32>(p_counter,counter);
GetSession()->SendPacket(&data);
}
@@ -15316,7 +15679,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report
if(missingItem)
GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), ar->levelMin, objmgr.GetItemPrototype(missingItem)->Name1);
else if(missingKey)
- SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY2);
+ SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY);
else if(missingHeroicQuest)
GetSession()->SendAreaTriggerMessage(ar->heroicQuestFailedText.c_str());
else if(missingQuest)
@@ -15332,6 +15695,13 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report
bool Player::_LoadHomeBind(QueryResult *result)
{
+ PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass());
+ if(!info)
+ {
+ sLog.outError("Player have incorrect race/class pair. Can't be loaded.");
+ return false;
+ }
+
bool ok = false;
//QueryResult *result = CharacterDatabase.PQuery("SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(playerGuid));
if (result)
@@ -15344,9 +15714,11 @@ bool Player::_LoadHomeBind(QueryResult *result)
m_homebindZ = fields[4].GetFloat();
delete result;
- // accept saved data only for valid position (and non instanceable)
+ MapEntry const* bindMapEntry = sMapStore.LookupEntry(m_homebindMapId);
+
+ // accept saved data only for valid position (and non instanceable), and accessable
if( MapManager::IsValidMapCoord(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ) &&
- !sMapStore.LookupEntry(m_homebindMapId)->Instanceable() )
+ !bindMapEntry->Instanceable() && GetSession()->Expansion() >= bindMapEntry->Expansion())
{
ok = true;
}
@@ -15356,9 +15728,6 @@ bool Player::_LoadHomeBind(QueryResult *result)
if(!ok)
{
- PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass());
- if(!info) return false;
-
m_homebindMapId = info->mapId;
m_homebindZoneId = info->zoneId;
m_homebindX = info->positionX;
@@ -15368,7 +15737,7 @@ bool Player::_LoadHomeBind(QueryResult *result)
CharacterDatabase.PExecute("INSERT INTO character_homebind (guid,map,zone,position_x,position_y,position_z) VALUES ('%u', '%u', '%u', '%f', '%f', '%f')", GetGUIDLow(), m_homebindMapId, (uint32)m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ);
}
- DEBUG_LOG("Setting player home position: mapid is: %u, zoneid is %u, X is %f, Y is %f, Z is %f\n",
+ DEBUG_LOG("Setting player home position: mapid is: %u, zoneid is %u, X is %f, Y is %f, Z is %f",
m_homebindMapId, m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ);
return true;
@@ -15386,12 +15755,6 @@ void Player::SaveToDB()
// first save/honor gain after midnight will also update the player's honor fields
UpdateHonorFields();
- // players aren't saved on battleground maps
- uint32 mapid = IsBeingTeleported() ? GetTeleportDest().mapid : GetMapId();
- const MapEntry * me = sMapStore.LookupEntry(mapid);
- if(!me || me->IsBattleGroundOrArena())
- return;
-
int is_save_resting = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0;
//save, far from tavern/city
//save, but in tavern/city
@@ -15406,10 +15769,9 @@ void Player::SaveToDB()
uint32 tmp_displayid = GetDisplayId();
// Set player sit state to standing on save, also stealth and shifted form
- SetByteValue(UNIT_FIELD_BYTES_1, 0, 0); // stand state
+ SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND);
SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift
- SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); // stand flags?
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
SetDisplayId(GetNativeDisplayId());
bool inworld = IsInWorld();
@@ -15423,29 +15785,21 @@ void Player::SaveToDB()
std::ostringstream ss;
ss << "INSERT INTO characters (guid,account,name,race,class,"
- "map, dungeon_difficulty, position_x, position_y, position_z, orientation, data, "
+ "map, instance_id, dungeon_difficulty, position_x, position_y, position_z, orientation, data, "
"taximask, online, cinematic, "
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, "
"trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, "
- "death_expire_time, taxi_path, arena_pending_points, latency) VALUES ("
+ "death_expire_time, taxi_path, arena_pending_points, latency, bgid, bgteam, bgmap, bgx, bgy, bgz, bgo) VALUES ("
<< GetGUIDLow() << ", "
<< GetSession()->GetAccountId() << ", '"
<< sql_name << "', "
<< m_race << ", "
<< m_class << ", ";
- bool save_to_dest = false;
- if(IsBeingTeleported())
- {
- // don't save to battlegrounds or arenas
- const MapEntry *entry = sMapStore.LookupEntry(GetTeleportDest().mapid);
- if(entry && entry->map_type != MAP_BATTLEGROUND && entry->map_type != MAP_ARENA)
- save_to_dest = true;
- }
-
- if(!save_to_dest)
+ if(!IsBeingTeleported())
{
ss << GetMapId() << ", "
+ << (uint32)GetInstanceId() << ", "
<< (uint32)GetDifficulty() << ", "
<< finiteAlways(GetPositionX()) << ", "
<< finiteAlways(GetPositionY()) << ", "
@@ -15455,6 +15809,7 @@ void Player::SaveToDB()
else
{
ss << GetTeleportDest().mapid << ", "
+ << (uint32)0 << ", "
<< (uint32)GetDifficulty() << ", "
<< finiteAlways(GetTeleportDest().x) << ", "
<< finiteAlways(GetTeleportDest().y) << ", "
@@ -15468,12 +15823,11 @@ void Player::SaveToDB()
ss << GetUInt32Value(i) << " ";
}
- ss << "', '";
+ ss << "', ";
- for( i = 0; i < 8; i++ )
- ss << m_taxi.GetTaximask(i) << " ";
+ ss << m_taxi; // string with TaxiMaskSize numbers
- ss << "', ";
+ ss << ", ";
ss << (inworld ? 1 : 0);
ss << ", ";
@@ -15516,7 +15870,7 @@ void Player::SaveToDB()
ss << uint32(m_stableSlots); // to prevent save uint8 as char
ss << ", ";
- ss << uint32(m_atLoginFlags);
+ ss << uint32(m_atLoginFlags & ((1<<AT_LOAD_PET_FLAGS) -1));
ss << ", ";
ss << GetZoneId();
@@ -15527,9 +15881,19 @@ void Player::SaveToDB()
ss << ", '";
ss << m_taxi.SaveTaxiDestinationsToString();
- ss << "', '0', '";
+ ss << "', '0', ";
ss << GetSession()->GetLatency();
- ss << "' )";
+ ss << ", ";
+ ss << GetBattleGroundId();
+ ss << ", ";
+ ss << GetBGTeam();
+ ss << ", ";
+ ss << m_bgEntryPoint.mapid << ", "
+ << finiteAlways(m_bgEntryPoint.x) << ", "
+ << finiteAlways(m_bgEntryPoint.y) << ", "
+ << finiteAlways(m_bgEntryPoint.z) << ", "
+ << finiteAlways(m_bgEntryPoint.o);
+ ss << ")";
CharacterDatabase.Execute( ss.str().c_str() );
@@ -15544,7 +15908,8 @@ void Player::SaveToDB()
_SaveSpellCooldowns();
_SaveActions();
_SaveAuras();
- _SaveReputation();
+ m_achievementMgr.SaveToDB();
+ m_reputationMgr.SaveToDB();
CharacterDatabase.CommitTransaction();
@@ -15558,23 +15923,6 @@ void Player::SaveToDB()
// save pet (hunter pet level and experience and all type pets health/mana).
if(Pet* pet = GetPet())
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
-
- //to prevent access to DB we should cache some data, which is used very often
- CachePlayerInfoMap::iterator _iter = objmgr.m_mPlayerInfoMap.find(GetGUIDLow());
- if(_iter != objmgr.m_mPlayerInfoMap.end())//skip new players
- {
- _iter->second->unLevel = getLevel();
-
- _iter->second->unArenaInfoSlot0 = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5);
- _iter->second->unArenaInfoSlot1 = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5);
- _iter->second->unArenaInfoSlot2 = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5);
-
- _iter->second->unfield = GetUInt32Value(UNIT_FIELD_BYTES_0);
-
- _iter->second->unArenaInfoId0 = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (0 * 6));
- _iter->second->unArenaInfoId1 = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (1 * 6));
- _iter->second->unArenaInfoId2 = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (2 * 6));
- }
}
// fast save function for item/money cheating preventing - save only inventory and money state
@@ -15619,56 +15967,35 @@ void Player::_SaveAuras()
CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",GetGUIDLow());
AuraMap const& auras = GetAuras();
+ for(AuraMap::const_iterator itr = auras.begin(); itr !=auras.end() ; ++itr)
+ {
+ // skip:
+ // area auras or single cast auras casted by other unit
+ // passive auras and stances
+ if (itr->second->IsPassive()
+ || itr->second->IsAuraType(SPELL_AURA_MOD_SHAPESHIFT)
+ || itr->second->IsRemovedOnShapeLost())
+ continue;
+ bool isCaster = itr->second->GetCasterGUID() == GetGUID();
+ if (!isCaster)
+ if (itr->second->IsSingleTarget()
+ || itr->second->IsAreaAura())
+ continue;
- if (auras.empty())
- return;
-
- spellEffectPair lastEffectPair = auras.begin()->first;
- uint32 stackCounter = 1;
-
- for(AuraMap::const_iterator itr = auras.begin(); ; ++itr)
- {
- if(itr == auras.end() || lastEffectPair != itr->first)
+ int32 amounts[MAX_SPELL_EFFECTS];
+ for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i)
{
- AuraMap::const_iterator itr2 = itr;
- // save previous spellEffectPair to db
- itr2--;
- SpellEntry const *spellInfo = itr2->second->GetSpellProto();
-
- //skip all auras from spells that are passive or need a shapeshift
- if (!(itr2->second->IsPassive() || itr2->second->IsRemovedOnShapeLost()))
- {
- //do not save single target auras (unless they were cast by the player)
- if (!(itr2->second->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(spellInfo)))
- {
- uint8 i;
- // or apply at cast SPELL_AURA_MOD_SHAPESHIFT or SPELL_AURA_MOD_STEALTH auras
- for (i = 0; i < 3; i++)
- if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT ||
- spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH)
- break;
-
- if (i == 3)
- {
- CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges) "
- "VALUES ('%u', '" I64FMTD "' ,'%u', '%u', '%u', '%d', '%d', '%d', '%d')",
- GetGUIDLow(), itr2->second->GetCasterGUID(), (uint32)itr2->second->GetId(), (uint32)itr2->second->GetEffIndex(), (uint32)itr2->second->GetStackAmount(), itr2->second->GetModifier()->m_amount,int(itr2->second->GetAuraMaxDuration()),int(itr2->second->GetAuraDuration()),int(itr2->second->m_procCharges));
- }
- }
- }
-
- if(itr == auras.end())
- break;
+ if (AuraEffect * partAura = itr->second->GetPartAura(i))
+ amounts[i]=partAura->GetAmount();
+ else
+ amounts[i]=0;
}
- //TODO: if need delete this
- if (lastEffectPair == itr->first)
- stackCounter++;
- else
- {
- lastEffectPair = itr->first;
- stackCounter = 1;
- }
+ CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_mask,stackcount,amount0, amount1, amount2,maxduration,remaintime,remaincharges) "
+ "VALUES ('%u', '" I64FMTD "', '%u', '%u', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
+ GetGUIDLow(), itr->second->GetCasterGUID(),(uint32)itr->second->GetId(), (uint32)itr->second->GetEffectMask(),
+ (int32)itr->second->GetStackAmount(), (int32)amounts[0], (int32)amounts[1], (int32)amounts[2]
+ ,int(itr->second->GetAuraMaxDuration()),int(itr->second->GetAuraDuration()),int(itr->second->GetAuraCharges()));
}
}
@@ -15808,11 +16135,11 @@ void Player::_SaveQuestStatus()
case QUEST_NEW :
CharacterDatabase.PExecute("INSERT INTO character_queststatus (guid,quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4) "
"VALUES ('%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')",
- GetGUIDLow(), i->first, i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3]);
+ GetGUIDLow(), i->first, i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / IN_MILISECONDS+ sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3]);
break;
case QUEST_CHANGED :
CharacterDatabase.PExecute("UPDATE character_queststatus SET status = '%u',rewarded = '%u',explored = '%u',timer = '" I64FMTD "',mobcount1 = '%u',mobcount2 = '%u',mobcount3 = '%u',mobcount4 = '%u',itemcount1 = '%u',itemcount2 = '%u',itemcount3 = '%u',itemcount4 = '%u' WHERE guid = '%u' AND quest = '%u' ",
- i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3], GetGUIDLow(), i->first );
+ i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / IN_MILISECONDS + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3], GetGUIDLow(), i->first );
break;
case QUEST_UNCHANGED:
break;
@@ -15838,33 +16165,28 @@ void Player::_SaveDailyQuestStatus()
GetGUIDLow(), GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx),uint64(m_lastDailyQuestTime));
}
-void Player::_SaveReputation()
-{
- for(FactionStateList::iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
- {
- if (itr->second.Changed)
- {
- CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u' AND faction='%u'", GetGUIDLow(), itr->second.ID);
- CharacterDatabase.PExecute("INSERT INTO character_reputation (guid,faction,standing,flags) VALUES ('%u', '%u', '%i', '%u')", GetGUIDLow(), itr->second.ID, itr->second.Standing, itr->second.Flags);
- itr->second.Changed = false;
- }
- }
-}
-
void Player::_SaveSpells()
{
- for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
+ for (PlayerSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end();)
{
- ++next;
if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED)
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first);
- if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED)
- CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,slot,active,disabled) VALUES ('%u', '%u', '%u','%u','%u')", GetGUIDLow(), itr->first, itr->second->slotId,itr->second->active ? 1 : 0,itr->second->disabled ? 1 : 0);
+
+ // add only changed/new not dependent spells
+ if (!itr->second->dependent && (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED))
+ CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,active,disabled) VALUES ('%u', '%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second->active ? 1 : 0,itr->second->disabled ? 1 : 0);
if (itr->second->state == PLAYERSPELL_REMOVED)
- _removeSpell(itr->first);
+ {
+ delete itr->second;
+ m_spells.erase(itr++);
+ }
else
+ {
itr->second->state = PLAYERSPELL_UNCHANGED;
+ ++itr;
+ }
+
}
}
@@ -16036,6 +16358,42 @@ void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid)
Player::SetUInt32ValueInDB(index, temp, guid);
}
+void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair)
+{
+ Tokens tokens;
+ if(!LoadValuesArrayFromDB(tokens, guid))
+ return;
+
+ uint32 unit_bytes0 = GetUInt32ValueFromArray(tokens, UNIT_FIELD_BYTES_0);
+ uint8 race = unit_bytes0 & 0xFF;
+ uint8 class_ = (unit_bytes0 >> 8) & 0xFF;
+
+ PlayerInfo const* info = objmgr.GetPlayerInfo(race, class_);
+ if(!info)
+ return;
+
+ unit_bytes0 &= ~(0xFF << 16);
+ unit_bytes0 |= (gender << 16);
+ SetUInt32ValueInArray(tokens, UNIT_FIELD_BYTES_0, unit_bytes0);
+
+ SetUInt32ValueInArray(tokens, UNIT_FIELD_DISPLAYID, gender ? info->displayId_f : info->displayId_m);
+ SetUInt32ValueInArray(tokens, UNIT_FIELD_NATIVEDISPLAYID, gender ? info->displayId_f : info->displayId_m);
+
+ SetUInt32ValueInArray(tokens, PLAYER_BYTES, (skin | (face << 8) | (hairStyle << 16) | (hairColor << 24)));
+
+ uint32 player_bytes2 = GetUInt32ValueFromArray(tokens, PLAYER_BYTES_2);
+ player_bytes2 &= ~0xFF;
+ player_bytes2 |= facialHair;
+ SetUInt32ValueInArray(tokens, PLAYER_BYTES_2, player_bytes2);
+
+ uint32 player_bytes3 = GetUInt32ValueFromArray(tokens, PLAYER_BYTES_3);
+ player_bytes3 &= ~0xFF;
+ player_bytes3 |= gender;
+ SetUInt32ValueInArray(tokens, PLAYER_BYTES_3, player_bytes3);
+
+ SaveValuesArrayInDB(tokens, guid);
+}
+
void Player::SendAttackSwingNotStanding()
{
WorldPacket data(SMSG_ATTACKSWING_NOTSTANDING, 0);
@@ -16068,20 +16426,11 @@ void Player::SendAttackSwingBadFacingAttack()
void Player::SendAutoRepeatCancel()
{
- WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, 0);
+ WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, GetPackGUID().size());
+ data.append(GetPackGUID()); // may be it's target guid
GetSession()->SendPacket( &data );
}
-void Player::PlaySound(uint32 Sound, bool OnlySelf)
-{
- WorldPacket data(SMSG_PLAY_SOUND, 4);
- data << Sound;
- if (OnlySelf)
- GetSession()->SendPacket( &data );
- else
- SendMessageToSet( &data, true );
-}
-
void Player::SendExplorationExperience(uint32 Area, uint32 Experience)
{
WorldPacket data( SMSG_EXPLORATION_EXPERIENCE, 8 );
@@ -16222,11 +16571,32 @@ void Player::UpdateDuelFlag(time_t currTime)
duel->opponent->duel->startTime = currTime;
}
+Pet* Player::GetPet() const
+{
+ if(uint64 pet_guid = GetPetGUID())
+ {
+ if(!IS_PET_GUID(pet_guid))
+ return NULL;
+
+ if(Pet* pet = ObjectAccessor::GetPet(pet_guid))
+ return pet;
+
+ //there may be a guardian in slot
+ //sLog.outError("Player::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
+ //const_cast<Player*>(this)->SetPetGUID(0);
+ }
+
+ return NULL;
+}
+
void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
{
if(!pet)
pet = GetPet();
+ if(pet)
+ sLog.outDebug("RemovePet %u, %u, %u", pet->GetEntry(), mode, returnreagent);
+
if(returnreagent && (pet || m_temporaryUnsummonedPetNumber))
{
//returning of reagents only for players, so best done here
@@ -16256,25 +16626,6 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
if(!pet || pet->GetOwnerGUID()!=GetGUID())
return;
- // only if current pet in slot
- switch(pet->getPetType())
- {
- case MINI_PET:
- m_miniPet = 0;
- break;
- case GUARDIAN_PET:
- m_guardianPets.erase(pet->GetGUID());
- break;
- case POSSESSED_PET:
- m_guardianPets.erase(pet->GetGUID());
- pet->RemoveCharmedOrPossessedBy(NULL);
- break;
- default:
- if(GetPetGUID() == pet->GetGUID())
- SetPet(NULL);
- break;
- }
-
pet->CombatStop();
if(returnreagent)
@@ -16291,7 +16642,18 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
}
}
- pet->SavePetToDB(mode);
+ // only if current pet in slot
+ switch(pet->getPetType())
+ {
+ case POSSESSED_PET:
+ pet->RemoveCharmedOrPossessedBy(NULL);
+ break;
+ default:
+ pet->SavePetToDB(mode);
+ break;
+ }
+
+ SetMinion(pet, false);
pet->CleanupsBeforeDelete();
pet->AddObjectToRemoveList();
@@ -16299,8 +16661,9 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
if(pet->isControlled())
{
- WorldPacket data(SMSG_PET_SPELLS, 8);
+ WorldPacket data(SMSG_PET_SPELLS, 8+4);
data << uint64(0);
+ data << uint32(0);
GetSession()->SendPacket(&data);
if(GetGroup())
@@ -16308,66 +16671,29 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
}
}
-void Player::RemoveMiniPet()
-{
- if(Pet* pet = GetMiniPet())
- {
- pet->Remove(PET_SAVE_AS_DELETED);
- m_miniPet = 0;
- }
-}
-
-Pet* Player::GetMiniPet()
-{
- if(!m_miniPet)
- return NULL;
- return ObjectAccessor::GetPet(m_miniPet);
-}
-
-void Player::RemoveGuardians()
+void Player::StopCastingCharm()
{
- while(!m_guardianPets.empty())
- {
- uint64 guid = *m_guardianPets.begin();
- if(Pet* pet = ObjectAccessor::GetPet(guid))
- pet->Remove(PET_SAVE_AS_DELETED);
-
- m_guardianPets.erase(guid);
- }
-}
+ ExitVehicle();
-bool Player::HasGuardianWithEntry(uint32 entry)
-{
- // pet guid middle part is entry (and creature also)
- // and in guardian list must be guardians with same entry _always_
- for(GuardianPetList::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr)
- if(GUID_ENPART(*itr)==entry)
- return true;
-
- return false;
-}
-
-void Player::Uncharm()
-{
Unit* charm = GetCharm();
if(!charm)
return;
- if(charm->GetTypeId() == TYPEID_UNIT && ((Creature*)charm)->isPet()
- && ((Pet*)charm)->getPetType() == POSSESSED_PET)
+ if(charm->GetTypeId() == TYPEID_UNIT)
{
- ((Pet*)charm)->Remove(PET_SAVE_AS_DELETED);
+ if(((Creature*)charm)->isPet() && ((Pet*)charm)->getPetType() == POSSESSED_PET)
+ ((Pet*)charm)->Remove(PET_SAVE_AS_DELETED);
}
- else
+ if(GetCharmGUID())
{
- charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM);
- charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS_PET);
- charm->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS);
+ charm->RemoveAurasByType(SPELL_AURA_MOD_CHARM);
+ charm->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET);
+ charm->RemoveAurasByType(SPELL_AURA_MOD_POSSESS);
}
if(GetCharmGUID())
{
- sLog.outError("CRASH ALARM! Player %s is not able to uncharm unit (Entry: %u, Type: %u)", GetName(), charm->GetEntry(), charm->GetTypeId());
+ sLog.outCrash("Player %s is not able to uncharm unit (Entry: %u, Type: %u)", GetName(), charm->GetEntry(), charm->GetTypeId());
}
}
@@ -16388,6 +16714,10 @@ void Player::Say(const std::string& text, const uint32 language)
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_SAY, text, language);
SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),true);
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_PUBLIC))
+ sLog.outChat("[SAY] Player %s says (language %u): %s",
+ GetName(), language, text.c_str());
}
void Player::Yell(const std::string& text, const uint32 language)
@@ -16395,6 +16725,10 @@ void Player::Yell(const std::string& text, const uint32 language)
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_YELL, text, language);
SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),true);
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_PUBLIC))
+ sLog.outChat("[YELL] Player %s yells (language %u): %s",
+ GetName(), language, text.c_str());
}
void Player::TextEmote(const std::string& text)
@@ -16402,6 +16736,10 @@ void Player::TextEmote(const std::string& text)
WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL);
SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true, !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT), true );
+
+ if(sWorld.getConfig(CONFIG_CHATLOG_PUBLIC))
+ sLog.outChat("[TEXTEMOTE] Player %s emotes: %s",
+ GetName(), text.c_str());
}
void Player::Whisper(const std::string& text, uint32 language,uint64 receiver)
@@ -16411,6 +16749,10 @@ void Player::Whisper(const std::string& text, uint32 language,uint64 receiver)
Player *rPlayer = objmgr.GetPlayer(receiver);
+ if(sWorld.getConfig(CONFIG_CHATLOG_WHISPER))
+ sLog.outChat("[WHISPER] Player %s tells %s: %s",
+ GetName(), rPlayer->GetName(), text.c_str());
+
// when player you are whispering to is dnd, he cannot receive your message, unless you are in gm mode
if(!rPlayer->isDND() || isGameMaster())
{
@@ -16447,71 +16789,80 @@ void Player::PetSpellInitialize()
{
Pet* pet = GetPet();
- if(pet)
- {
- uint8 addlist = 0;
+ if(!pet)
+ return;
- sLog.outDebug("Pet Spells Groups");
+ sLog.outDebug("Pet Spells Groups");
- CreatureInfo const *cinfo = pet->GetCreatureInfo();
+ CharmInfo *charmInfo = pet->GetCharmInfo();
- if(pet->isControlled() && (pet->getPetType() == HUNTER_PET || cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK))
- {
- for(PetSpellMap::iterator itr = pet->m_spells.begin();itr != pet->m_spells.end();++itr)
- {
- if(itr->second->state == PETSPELL_REMOVED)
- continue;
- ++addlist;
- }
- }
+ WorldPacket data(SMSG_PET_SPELLS, 8+4+4+4+10*4);
+ data << uint64(pet->GetGUID());
+ data << uint32(pet->GetCreatureInfo()->family); // creature family (required for pet talents)
+ data << uint32(0);
+ data << uint8(pet->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0);
- // first line + actionbar + spellcount + spells + last adds
- WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);
+ // action bar loop
+ for(uint32 i = 0; i < MAX_SPELL_CONTROL_BAR; ++i)
+ {
+ data << uint32(charmInfo->GetActionBarEntry(i)->Raw);
+ }
- CharmInfo *charmInfo = pet->GetCharmInfo();
+ size_t spellsCountPos = data.wpos();
- //16
- data << (uint64)pet->GetGUID() << uint32(0x00000000) << uint8(pet->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0);
+ // spells count
+ uint8 addlist = 0;
+ data << uint8(addlist); // placeholder
- for(uint32 i = 0; i < 10; i++) //40
+ if (pet->IsPermanentPetFor(this))
+ {
+ // spells loop
+ for (PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
{
- data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type);
+ if(itr->second.state == PETSPELL_REMOVED)
+ continue;
+
+ data << uint16(itr->first);
+ data << uint16(itr->second.active); // pet spell active state isn't boolean
+ ++addlist;
}
+ }
- data << uint8(addlist); //1
+ data.put<uint8>(spellsCountPos, addlist);
- if(addlist && pet->isControlled())
- {
- for (PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
- {
- if(itr->second->state == PETSPELL_REMOVED)
- continue;
+ uint8 cooldownsCount = pet->m_CreatureSpellCooldowns.size() + pet->m_CreatureCategoryCooldowns.size();
+ data << uint8(cooldownsCount);
- data << uint16(itr->first);
- data << uint16(itr->second->active); // pet spell active state isn't boolean
- }
- }
+ time_t curTime = time(NULL);
- //data << uint8(0x01) << uint32(0x6010) << uint32(0x01) << uint32(0x05) << uint16(0x00); //15
- uint8 count = 3; //1+8+8+8=25
+ for(CreatureSpellCooldowns::const_iterator itr = pet->m_CreatureSpellCooldowns.begin(); itr != pet->m_CreatureSpellCooldowns.end(); ++itr)
+ {
+ time_t cooldown = (itr->second > curTime) ? (itr->second - curTime) * IN_MILISECONDS : 0;
- // if count = 0, then end of packet...
- data << count;
- // uint32 value is spell id...
- // uint64 value is constant 0, unknown...
- data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3
- //data << uint32(0x5fd1) << uint64(0); // if count = 2
- data << uint32(0x8e8c) << uint64(0); // if count = 3
- data << uint32(0x8e8b) << uint64(0); // if count = 3
+ data << uint16(itr->first); // spellid
+ data << uint16(0); // spell category?
+ data << uint32(cooldown); // cooldown
+ data << uint32(0); // category cooldown
+ }
- GetSession()->SendPacket(&data);
+ for(CreatureSpellCooldowns::const_iterator itr = pet->m_CreatureCategoryCooldowns.begin(); itr != pet->m_CreatureCategoryCooldowns.end(); ++itr)
+ {
+ time_t cooldown = (itr->second > curTime) ? (itr->second - curTime) * IN_MILISECONDS : 0;
+
+ data << uint16(itr->first); // spellid
+ data << uint16(0); // spell category?
+ data << uint32(0); // cooldown
+ data << uint32(cooldown); // category cooldown
}
+
+ data.hexlike();
+
+ GetSession()->SendPacket(&data);
}
void Player::PossessSpellInitialize()
{
Unit* charm = GetCharm();
-
if(!charm)
return;
@@ -16523,32 +16874,69 @@ void Player::PossessSpellInitialize()
return;
}
- uint8 addlist = 0;
- WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds
+ WorldPacket data(SMSG_PET_SPELLS, 20+40+1+1);
- //16
- data << (uint64)charm->GetGUID() << uint32(0x00000000) << uint8(0) << uint8(0) << uint16(0);
+ //basic info 20
+ data << uint64(charm->GetGUID());
+ data << uint32(0x00000000);
+ data << uint32(0);
+ data << uint32(0);
- for(uint32 i = 0; i < 10; i++) //40
- {
+ //action bar 40
+ for(uint32 i = 0; i < 10; i++)
data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type);
- }
- data << uint8(addlist); //1
+ //addlist 1
+ data << uint8(0);
- uint8 count = 3;
- data << count;
- data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3
- data << uint32(0x8e8c) << uint64(0); // if count = 3
- data << uint32(0x8e8b) << uint64(0); // if count = 3
+ //cooldown 1
+ data << uint8(0);
GetSession()->SendPacket(&data);
}
-void Player::CharmSpellInitialize()
+void Player::VehicleSpellInitialize()
{
- Unit* charm = GetCharm();
+ Unit* charm = m_Vehicle;
+ if(!charm)
+ return;
+
+ WorldPacket data(SMSG_PET_SPELLS, 8+4+4+4+4*10+1+1);
+ data << uint64(charm->GetGUID());
+ data << uint32(0x00000000);
+ data << uint32(0x00000000);
+ data << uint32(0x00000101);
+
+ for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
+ {
+ uint32 spellId = ((Creature*)charm)->m_spells[i];
+ if(!spellId)
+ continue;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
+ if(!spellInfo)
+ continue;
+
+ if(IsPassiveSpell(spellId) || spellInfo->activeIconID == 2158) //flight
+ {
+ charm->CastSpell(charm, spellId, true);
+ data << uint16(0) << uint8(0) << uint8(i+8);
+ }
+ else
+ data << uint16(spellId) << uint8(0) << uint8(i+8);
+ }
+
+ for(uint32 i = CREATURE_MAX_SPELLS; i < MAX_SPELL_CONTROL_BAR; ++i)
+ data << uint16(0) << uint8(0) << uint8(i+8);
+ data << uint8(0);
+ data << uint8(0);
+ GetSession()->SendPacket(&data);
+}
+
+void Player::CharmSpellInitialize()
+{
+ Unit* charm = GetFirstControlled();
if(!charm)
return;
@@ -16560,14 +16948,12 @@ void Player::CharmSpellInitialize()
}
uint8 addlist = 0;
-
if(charm->GetTypeId() != TYPEID_PLAYER)
{
CreatureInfo const *cinfo = ((Creature*)charm)->GetCreatureInfo();
-
- if(cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)
+ //if(cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)
{
- for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
+ for(uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
{
if(charmInfo->GetCharmSpell(i)->spellId)
++addlist;
@@ -16575,27 +16961,29 @@ void Player::CharmSpellInitialize()
}
}
- WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds
-
- data << (uint64)charm->GetGUID() << uint32(0x00000000);
+ WorldPacket data(SMSG_PET_SPELLS, 20+40+1+4*addlist+1);// first line + actionbar + spellcount + spells + last adds
+ //basic info 20
+ data << uint64(charm->GetGUID());
+ data << uint32(0);
+ data << uint32(0);
if(charm->GetTypeId() != TYPEID_PLAYER)
data << uint8(((Creature*)charm)->GetReactState()) << uint8(charmInfo->GetCommandState());
else
data << uint8(0) << uint8(0);
-
data << uint16(0);
- for(uint32 i = 0; i < 10; i++) //40
+ //action bar 40
+ for(uint32 i = 0; i < MAX_SPELL_CONTROL_BAR; ++i) //40
{
data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type);
}
+ //add list
data << uint8(addlist); //1
-
if(addlist)
{
- for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
+ for(uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
{
CharmSpellEntry *cspell = charmInfo->GetCharmSpell(i);
if(cspell->spellId)
@@ -16606,49 +16994,19 @@ void Player::CharmSpellInitialize()
}
}
- uint8 count = 3;
- data << count;
- data << uint32(0x6010) << uint64(0); // if count = 1, 2 or 3
- data << uint32(0x8e8c) << uint64(0); // if count = 3
- data << uint32(0x8e8b) << uint64(0); // if count = 3
+ //cooldown
+ uint8 count = 0;
+ data << uint8(count); // cooldowns count
GetSession()->SendPacket(&data);
}
-int32 Player::GetTotalFlatMods(uint32 spellId, SpellModOp op)
-{
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
- if (!spellInfo) return 0;
- int32 total = 0;
- for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr)
- {
- SpellModifier *mod = *itr;
-
- if(!IsAffectedBySpellmod(spellInfo,mod))
- continue;
-
- if (mod->type == SPELLMOD_FLAT)
- total += mod->value;
- }
- return total;
-}
-
-int32 Player::GetTotalPctMods(uint32 spellId, SpellModOp op)
+void Player::SendRemoveControlBar()
{
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
- if (!spellInfo) return 0;
- int32 total = 0;
- for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr)
- {
- SpellModifier *mod = *itr;
-
- if(!IsAffectedBySpellmod(spellInfo,mod))
- continue;
-
- if (mod->type == SPELLMOD_PCT)
- total += mod->value;
- }
- return total;
+ WorldPacket data(SMSG_PET_SPELLS, 8+4);
+ data << uint64(0);
+ data << uint32(0);
+ GetSession()->SendPacket(&data);
}
bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell)
@@ -16668,22 +17026,27 @@ bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mo
return false;
}
- return spellmgr.IsAffectedBySpell(spellInfo,mod->spellId,mod->effectId,mod->mask);
+ return spellmgr.IsAffectedByMod(spellInfo, mod);
}
void Player::AddSpellMod(SpellModifier* mod, bool apply)
{
uint16 Opcode= (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER;
- for(int eff=0;eff<64;++eff)
+ uint8 i=0;
+ flag96 _mask;
+ for(int eff=0;eff<96;++eff)
{
- uint64 _mask = uint64(1) << eff;
+ if ((eff!=0) && (eff%32==0))
+ i++;
+
+ _mask[i] = uint32(1) << (eff-(32*i));
if ( mod->mask & _mask)
{
int32 val = 0;
for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr)
{
- if ((*itr)->type == mod->type && (*itr)->mask & _mask)
+ if ((*itr)->type == mod->type && (*itr)->mask & _mask )
val += (*itr)->value;
}
val += apply ? mod->value : -(mod->value);
@@ -16720,7 +17083,7 @@ void Player::RemoveSpellMods(Spell const* spell)
if (mod && mod->charges == -1 && (mod->lastAffected == spell || mod->lastAffected==NULL))
{
- RemoveAurasDueToSpell(mod->spellId);
+ RemoveAurasDueToSpell(mod->spellId, 0, AURA_REMOVE_BY_EXPIRE);
if (m_spellMods[i].empty())
break;
else
@@ -16782,6 +17145,27 @@ void Player::RemovePetitionsAndSigns(uint64 guid, uint32 type)
CharacterDatabase.CommitTransaction();
}
+void Player::LeaveAllArenaTeams(uint64 guid)
+{
+ QueryResult *result = CharacterDatabase.PQuery("SELECT arena_team_member.arenateamid FROM arena_team_member JOIN arena_team ON arena_team_member.arenateamid = arena_team.arenateamid WHERE guid='%u'", GUID_LOPART(guid));
+ if(!result)
+ return;
+
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 at_id = fields[0].GetUInt32();
+ if(at_id != 0)
+ {
+ ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
+ if(at)
+ at->DelMember(guid);
+ }
+ } while (result->NextRow());
+
+ delete result;
+}
+
void Player::SetRestBonus (float rest_bonus_new)
{
// Prevent resting on max level
@@ -16812,7 +17196,7 @@ void Player::HandleStealthedUnitsDetection()
{
std::list<Unit*> stealthedUnits;
Trinity::AnyStealthedCheck u_check;
- Trinity::UnitListSearcher<Trinity::AnyStealthedCheck > searcher(stealthedUnits, u_check);
+ Trinity::UnitListSearcher<Trinity::AnyStealthedCheck > searcher(this, stealthedUnits, u_check);
VisitNearbyObject(World::GetMaxVisibleDistance(), searcher);
for (std::list<Unit*>::iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i)
@@ -16832,53 +17216,98 @@ void Player::HandleStealthedUnitsDetection()
}
}
-bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_id, Creature* npc)
+bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= NULL*/, uint32 spellid /*= 0*/)
{
if(nodes.size() < 2)
return false;
- // not let cheating with start flight mounted
- if(IsMounted())
+ // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi
+ if(GetSession()->isLogingOut() || isInCombat())
{
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
- data << uint32(ERR_TAXIPLAYERALREADYMOUNTED);
+ data << uint32(ERR_TAXIPLAYERBUSY);
GetSession()->SendPacket(&data);
return false;
}
- if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW )
- {
- WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
- data << uint32(ERR_TAXIPLAYERSHAPESHIFTED);
- GetSession()->SendPacket(&data);
+ if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
return false;
- }
- // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi
- if(GetSession()->isLogingOut() ||
- (!m_currentSpells[CURRENT_GENERIC_SPELL] ||
- m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Effect[0] != SPELL_EFFECT_SEND_TAXI)&&
- IsNonMeleeSpellCasted(false) ||
- isInCombat())
+ // taximaster case
+ if(npc)
{
- WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
- data << uint32(ERR_TAXIPLAYERBUSY);
- GetSession()->SendPacket(&data);
- return false;
+ // not let cheating with start flight mounted
+ if(IsMounted())
+ {
+ WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
+ data << uint32(ERR_TAXIPLAYERALREADYMOUNTED);
+ GetSession()->SendPacket(&data);
+ return false;
+ }
+
+ if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW )
+ {
+ WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
+ data << uint32(ERR_TAXIPLAYERSHAPESHIFTED);
+ GetSession()->SendPacket(&data);
+ return false;
+ }
+
+ // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi
+ if(IsNonMeleeSpellCasted(false))
+ {
+ WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
+ data << uint32(ERR_TAXIPLAYERBUSY);
+ GetSession()->SendPacket(&data);
+ return false;
+ }
}
+ // cast case or scripted call case
+ else
+ {
+ RemoveAurasByType(SPELL_AURA_MOUNTED);
- if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
- return false;
+ if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW )
+ RemoveAurasDueToSpell(m_ShapeShiftFormSpellId);
+
+ if(m_currentSpells[CURRENT_GENERIC_SPELL] && m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id != spellid)
+ InterruptSpell(CURRENT_GENERIC_SPELL,false);
+
+ InterruptSpell(CURRENT_AUTOREPEAT_SPELL,false);
+
+ if(m_currentSpells[CURRENT_CHANNELED_SPELL] && m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id != spellid)
+ InterruptSpell(CURRENT_CHANNELED_SPELL,true);
+ }
uint32 sourcenode = nodes[0];
// starting node too far away (cheat?)
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(sourcenode);
- if( !node || node->map_id != GetMapId() ||
- (node->x - GetPositionX())*(node->x - GetPositionX())+
- (node->y - GetPositionY())*(node->y - GetPositionY())+
- (node->z - GetPositionZ())*(node->z - GetPositionZ()) >
- (2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE) )
+ if (!node)
+ {
+ WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
+ data << uint32(ERR_TAXINOSUCHPATH);
+ GetSession()->SendPacket(&data);
+ return false;
+ }
+
+ // check node starting pos data set case if provided
+ if (node->x != 0.0f || node->y != 0.0f || node->z != 0.0f)
+ {
+ if (node->map_id != GetMapId() ||
+ (node->x - GetPositionX())*(node->x - GetPositionX())+
+ (node->y - GetPositionY())*(node->y - GetPositionY())+
+ (node->z - GetPositionZ())*(node->z - GetPositionZ()) >
+ (2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE)*(2*INTERACTION_DISTANCE))
+ {
+ WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
+ data << uint32(ERR_TAXITOOFARAWAY);
+ GetSession()->SendPacket(&data);
+ return false;
+ }
+ }
+ // node must have pos if taxi master case (npc != NULL)
+ else if (npc)
{
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR);
@@ -16930,10 +17359,11 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
prevnode = lastnode;
}
- if(!mount_id) // if not provide then attempt use default.
- mount_id = objmgr.GetTaxiMount(sourcenode, GetTeam());
+ // get mount model (in case non taximaster (npc==NULL) allow more wide lookup)
+ uint16 mount_id = objmgr.GetTaxiMount(sourcenode, GetTeam(), npc == NULL);
- if (mount_id == 0 || sourcepath == 0)
+ // in spell case allow 0 model
+ if (mount_id == 0 && spellid == 0 || sourcepath == 0)
{
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR);
@@ -16944,10 +17374,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
uint32 money = GetMoney();
- if(npc)
- {
+ if (npc)
totalcost = (uint32)ceil(totalcost*GetReputationPriceDiscount(npc));
- }
if(money < totalcost)
{
@@ -16960,6 +17388,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
//Checks and preparations done, DO FLIGHT
ModifyMoney(-(int32)totalcost);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost);
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1);
// prevent stealth flight
//RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
@@ -16975,6 +17405,21 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
return true;
}
+bool Player::ActivateTaxiPathTo( uint32 taxi_path_id, uint32 spellid /*= 0*/ )
+{
+ TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(taxi_path_id);
+ if(!entry)
+ return false;
+
+ std::vector<uint32> nodes;
+
+ nodes.resize(2);
+ nodes[0] = entry->from;
+ nodes[1] = entry->to;
+
+ return ActivateTaxiPathTo(nodes,NULL,spellid);
+}
+
void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs )
{
// last check 2.0.10
@@ -17005,7 +17450,7 @@ void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs )
{
data << unSpellId;
data << unTimeMs; // in m.secs
- AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/1000);
+ AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/IN_MILISECONDS);
}
}
GetSession()->SendPacket(&data);
@@ -17071,7 +17516,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
return false;
}
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*this, vendorguid,UNIT_NPC_FLAG_VENDOR);
+ Creature *pCreature = GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR);
if (!pCreature)
{
sLog.outDebug( "WORLD: BuyItemFromVendor - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
@@ -17344,16 +17789,46 @@ void Player::UpdateHomebindTime(uint32 time)
}
}
+void Player::UpdatePvPState(bool onlyFFA)
+{
+ // TODO: should we always synchronize UNIT_FIELD_BYTES_2, 1 of controller and controlled?
+ if(!pvpInfo.inNoPvPArea && !isGameMaster()
+ && (pvpInfo.inFFAPvPArea || sWorld.IsFFAPvPRealm()))
+ {
+ if(!HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
+ {
+ SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
+ for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
+ (*itr)->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
+ }
+ }
+ else if(HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
+ {
+ RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
+ for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
+ (*itr)->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
+ }
+
+ if(onlyFFA)
+ return;
+
+ if(pvpInfo.inHostileArea) // in hostile area
+ {
+ if(!IsPvP() || pvpInfo.endTimer != 0)
+ UpdatePvP(true, true);
+ }
+ else // in friendly area
+ {
+ if(IsPvP() && !HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_IN_PVP) && pvpInfo.endTimer == 0)
+ pvpInfo.endTimer = time(0); // start toggle-off
+ }
+}
+
void Player::UpdatePvP(bool state, bool ovrride)
{
if(!state || ovrride)
{
SetPvP(state);
- if(Pet* pet = GetPet())
- pet->SetPvP(state);
- if(Unit* charmed = GetCharm())
- charmed->SetPvP(state);
-
pvpInfo.endTimer = 0;
}
else
@@ -17361,13 +17836,102 @@ void Player::UpdatePvP(bool state, bool ovrride)
if(pvpInfo.endTimer != 0)
pvpInfo.endTimer = time(NULL);
else
- {
SetPvP(state);
+ }
+}
- if(Pet* pet = GetPet())
- pet->SetPvP(state);
- if(Unit* charmed = GetCharm())
- charmed->SetPvP(state);
+void Player::AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell, bool infinityCooldown)
+{
+ // init cooldown values
+ uint32 cat = 0;
+ int32 rec = -1;
+ int32 catrec = -1;
+
+ // some special item spells without correct cooldown in SpellInfo
+ // cooldown information stored in item prototype
+ // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
+
+ if(itemId)
+ {
+ if(ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemId))
+ {
+ for(int idx = 0; idx < 5; ++idx)
+ {
+ if(proto->Spells[idx].SpellId == spellInfo->Id)
+ {
+ cat = proto->Spells[idx].SpellCategory;
+ rec = proto->Spells[idx].SpellCooldown;
+ catrec = proto->Spells[idx].SpellCategoryCooldown;
+ break;
+ }
+ }
+ }
+ }
+
+ // if no cooldown found above then base at DBC data
+ if(rec < 0 && catrec < 0)
+ {
+ cat = spellInfo->Category;
+ rec = spellInfo->RecoveryTime;
+ catrec = spellInfo->CategoryRecoveryTime;
+ }
+
+ time_t curTime = time(NULL);
+
+ time_t catrecTime;
+ time_t recTime;
+
+ // overwrite time for selected category
+ if(infinityCooldown)
+ {
+ // use +MONTH as infinity mark for spell cooldown (will checked as MONTH/2 at save ans skipped)
+ // but not allow ignore until reset or re-login
+ catrecTime = catrec > 0 ? curTime+MONTH : 0;
+ recTime = rec > 0 ? curTime+MONTH : catrecTime;
+ }
+ else
+ {
+ // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
+ // prevent 0 cooldowns set by another way
+ if (rec <= 0 && catrec <= 0 && (cat == 76 || IsAutoRepeatRangedSpell(spellInfo) && spellInfo->Id != SPELL_ID_AUTOSHOT))
+ rec = GetAttackTime(RANGED_ATTACK);
+
+ // Now we have cooldown data (if found any), time to apply mods
+ if(rec > 0)
+ ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell);
+
+ if(catrec > 0)
+ ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell);
+
+ // replace negative cooldowns by 0
+ if (rec < 0) rec = 0;
+ if (catrec < 0) catrec = 0;
+
+ // no cooldown after applying spell mods
+ if( rec == 0 && catrec == 0)
+ return;
+
+ catrecTime = catrec ? curTime+catrec/IN_MILISECONDS : 0;
+ recTime = rec ? curTime+rec/IN_MILISECONDS : catrecTime;
+ }
+
+ // self spell cooldown
+ if(recTime > 0)
+ AddSpellCooldown(spellInfo->Id, itemId, recTime);
+
+ // category spells
+ if (cat && catrec > 0)
+ {
+ SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
+ if(i_scstore != sSpellCategoryStore.end())
+ {
+ for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
+ {
+ if(*i_scset == spellInfo->Id) // skip main spell, already handled above
+ continue;
+
+ AddSpellCooldown(*i_scset, itemId, catrecTime);
+ }
}
}
}
@@ -17380,25 +17944,41 @@ void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time)
m_spellCooldowns[spellid] = sc;
}
-void Player::SendCooldownEvent(SpellEntry const *spellInfo)
+void Player::SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId, Spell* spell)
{
- if ( !(spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) )
- return;
+ // start cooldowns at server side, if any
+ AddSpellAndCategoryCooldowns(spellInfo,itemId,spell);
- // Get spell cooldown
- int32 cooldown = GetSpellRecoveryTime(spellInfo);
- // Apply spellmods
- ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown);
- if (cooldown < 0)
- cooldown = 0;
- // Add cooldown
- AddSpellCooldown(spellInfo->Id, 0, time(NULL) + cooldown / 1000);
- // Send activate
+ // Send activate cooldown timer (possible 0) at client side
WorldPacket data(SMSG_COOLDOWN_EVENT, (4+8));
data << spellInfo->Id;
data << GetGUID();
SendDirectMessage(&data);
}
+
+void Player::UpdatePotionCooldown(Spell* spell)
+{
+ // no potion used i combat or still in combat
+ if(!m_lastPotionId || isInCombat())
+ return;
+
+ // Call not from spell cast, send cooldown event for item spells if no in combat
+ if(!spell)
+ {
+ // spell/item pair let set proper cooldown (except not existed charged spell cooldown spellmods for potions)
+ if(ItemPrototype const* proto = ObjectMgr::GetItemPrototype(m_lastPotionId))
+ for(int idx = 0; idx < 5; ++idx)
+ if(proto->Spells[idx].SpellId && proto->Spells[idx].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
+ if(SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[idx].SpellId))
+ SendCooldownEvent(spellInfo,m_lastPotionId);
+ }
+ // from spell cases (m_lastPotionId set in Spell::SendSpellCooldown)
+ else
+ SendCooldownEvent(spell->m_spellInfo,m_lastPotionId,spell);
+
+ m_lastPotionId = 0;
+}
+
//slot to be excluded while counting
bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot)
{
@@ -17563,13 +18143,14 @@ void Player::LeaveBattleground(bool teleportToEntryPoint)
{
if(BattleGround *bg = GetBattleGround())
{
- bool need_debuf = bg->isBattleGround() && !isGameMaster() && (bg->GetStatus() == STATUS_IN_PROGRESS) && sWorld.getConfig(CONFIG_BATTLEGROUND_CAST_DESERTER);
-
bg->RemovePlayerAtLeave(GetGUID(), teleportToEntryPoint, true);
// call after remove to be sure that player resurrected for correct cast
- if(need_debuf)
- CastSpell(this, 26013, true); // Deserter
+ if( bg->isBattleGround() && !isGameMaster() && sWorld.getConfig(CONFIG_BATTLEGROUND_CAST_DESERTER) )
+ {
+ if( bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN )
+ CastSpell(this, 26013, true); // Deserter
+ }
}
}
@@ -17599,7 +18180,7 @@ void Player::ReportedAfkBy(Player* reporter)
return;
// check if player has 'Idle' or 'Inactive' debuff
- if(m_bgAfkReporter.find(reporter->GetGUIDLow())==m_bgAfkReporter.end() && !HasAura(43680,0) && !HasAura(43681,0) && reporter->CanReportAfkDueToLimit())
+ if(m_bgAfkReporter.find(reporter->GetGUIDLow())==m_bgAfkReporter.end() && !HasAura(43680) && !HasAura(43681) && reporter->CanReportAfkDueToLimit())
{
m_bgAfkReporter.insert(reporter->GetGUIDLow());
// 3 players have to complain to apply debuff
@@ -17615,9 +18196,13 @@ void Player::ReportedAfkBy(Player* reporter)
bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList, bool is3dDistance) const
{
// Always can see self
- if (u == this)
+ if (m_mover == u || this == u)
return true;
+ // phased visibility (both must phased in same way)
+ if(!InSamePhase(u))
+ return false;
+
// player visible for other player if not logout and at same transport
// including case when player is out of world
bool at_same_transport =
@@ -17634,47 +18219,42 @@ bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList, bool
if(u->GetVisibility() == VISIBILITY_RESPAWN)
return false;
- // always seen by owner
- if(GetGUID() == u->GetCharmerOrOwnerGUID())
- return true;
-
// Grid dead/alive checks
// non visible at grid for any stealth state
if(!u->IsVisibleInGridForPlayer(this))
return false;
- // If the player is currently channeling vision, update visibility from the target unit's location
- const WorldObject* target = GetFarsightTarget();
- if (!target || !HasFarsightVision()) // Vision needs to be on the farsight target
- target = this;
+ // always seen by owner
+ if(GetGUID() == u->GetCharmerOrOwnerGUID())
+ return true;
// different visible distance checks
if(isInFlight()) // what see player in flight
{
- if (!target->IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
+ if (!m_seer->IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
return false;
}
else if(!u->isAlive()) // distance for show body
{
- if (!target->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
+ if (!m_seer->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
return false;
}
else if(u->GetTypeId()==TYPEID_PLAYER) // distance for show player
{
// Players far than max visible distance for player or not in our map are not visible too
- if (!at_same_transport && !target->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
+ if (!at_same_transport && !m_seer->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
return false;
}
else if(u->GetCharmerOrOwnerGUID()) // distance for show pet/charmed
{
// Pet/charmed far than max visible distance for player or not in our map are not visible too
- if (!target->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
+ if (!m_seer->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
return false;
}
else // distance for show creature
{
// Units far than max visible distance for creature or not in our map are not visible too
- if (!target->IsWithinDistInMap(u
+ if (!m_seer->IsWithinDistInMap(u
, u->isActiveObject() ? (MAX_VISIBILITY_DISTANCE - (inVisibleList ? 0.0f : World::GetVisibleUnitGreyDistance()))
: (World::GetMaxVisibleDistanceForCreature() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))
, is3dDistance))
@@ -17695,7 +18275,7 @@ bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList, bool
}
// GM's can see everyone with invisibilitymask with less or equal security level
- if(m_invisibilityMask || u->m_invisibilityMask)
+ if(m_mover->m_invisibilityMask || u->m_invisibilityMask)
{
if(isGameMaster())
{
@@ -17706,7 +18286,7 @@ bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList, bool
}
// player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting)
- if(!canDetectInvisibilityOf(u))
+ if(!m_mover->canDetectInvisibilityOf(u))
if(!(u->GetTypeId()==TYPEID_PLAYER && !IsHostileTo(u) && IsGroupVisibleFor(((Player*)u))))
return false;
}
@@ -17721,7 +18301,7 @@ bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList, bool
detect = false;
if(m_DetectInvTimer < 300 || !HaveAtClient(u))
if(!(u->GetTypeId()==TYPEID_PLAYER && !IsHostileTo(u) && IsGroupVisibleFor(((Player*)u))))
- if(!detect || !canDetectStealthOf(u, GetDistance(u)))
+ if(!detect || !m_mover->canDetectStealthOf(u, GetDistance(u)))
return false;
}
@@ -17834,7 +18414,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
void Player::SendInitialVisiblePackets(Unit* target)
{
- SendAuraDurationsForTarget(target);
+ SendAurasForTarget(target);
if(target->isAlive())
{
if(target->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE)
@@ -17955,7 +18535,7 @@ void Player::AddComboPoints(Unit* target, int8 count)
return;
// without combo points lost (duration checked in aura)
- RemoveSpellsCausingAura(SPELL_AURA_RETAIN_COMBO_POINTS);
+ RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
if(target->GetGUID() == m_comboTarget)
{
@@ -17964,8 +18544,8 @@ void Player::AddComboPoints(Unit* target, int8 count)
else
{
if(m_comboTarget)
- if(Unit* target = ObjectAccessor::GetUnit(*this,m_comboTarget))
- target->RemoveComboPointHolder(GetGUIDLow());
+ if(Unit* target2 = ObjectAccessor::GetUnit(*this,m_comboTarget))
+ target2->RemoveComboPointHolder(GetGUIDLow());
m_comboTarget = target->GetGUID();
m_comboPoints = count;
@@ -17985,7 +18565,7 @@ void Player::ClearComboPoints()
return;
// without combopoints lost (duration checked in aura)
- RemoveSpellsCausingAura(SPELL_AURA_RETAIN_COMBO_POINTS);
+ RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
m_comboPoints = 0;
@@ -17999,7 +18579,8 @@ void Player::ClearComboPoints()
void Player::SetGroup(Group *group, int8 subgroup)
{
- if(group == NULL) m_group.unlink();
+ if(group == NULL)
+ m_group.unlink();
else
{
// never use SetGroup without a subgroup unless you specify NULL for group
@@ -18011,7 +18592,7 @@ void Player::SetGroup(Group *group, int8 subgroup)
void Player::SendInitialPacketsBeforeAddToMap()
{
- WorldPacket data(SMSG_SET_REST_START, 4);
+ WorldPacket data(SMSG_SET_REST_START_OBSOLETE, 4);
data << uint32(0); // unknown, may be rest state time or experience
GetSession()->SendPacket(&data);
@@ -18038,9 +18619,13 @@ void Player::SendInitialPacketsBeforeAddToMap()
GetSession()->SendPacket(&data);
SendInitialActionButtons();
- SendInitialReputations();
- UpdateZone(GetZoneId());
- SendInitWorldStates();
+ m_reputationMgr.SendInitialReputations();
+ m_achievementMgr.SendAllAchievementData();
+
+ // update zone
+ uint32 newzone, newarea;
+ GetZoneAndAreaId(newzone,newarea);
+ UpdateZone(newzone,newarea); // also call SendInitWorldStates();
// SMSG_SET_AURA_SINGLE
@@ -18050,12 +18635,16 @@ void Player::SendInitialPacketsBeforeAddToMap()
GetSession()->SendPacket( &data );
// set fly flag if in fly form or taxi flight to prevent visually drop at ground in showup moment
- if(HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED) || isInFlight())
+ if(HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || isInFlight())
AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
}
void Player::SendInitialPacketsAfterAddToMap()
{
+ WorldPacket data(SMSG_TIME_SYNC_REQ, 4); // new 2.0.x, enable movement
+ data << uint32(0x00000000); // on blizz it increments periodically
+ GetSession()->SendPacket(&data);
+
CastSpell(this, 836, true); // LOGINEFFECT
// set some aura effects that send packet to player client after add player to map
@@ -18065,11 +18654,11 @@ void Player::SendInitialPacketsAfterAddToMap()
{
SPELL_AURA_MOD_FEAR, SPELL_AURA_TRANSFORM, SPELL_AURA_WATER_WALK,
SPELL_AURA_FEATHER_FALL, SPELL_AURA_HOVER, SPELL_AURA_SAFE_FALL,
- SPELL_AURA_FLY, SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED, SPELL_AURA_NONE
+ SPELL_AURA_FLY, SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED, SPELL_AURA_NONE
};
for(AuraType const* itr = &auratypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
{
- Unit::AuraList const& auraList = GetAurasByType(*itr);
+ Unit::AuraEffectList const& auraList = GetAurasByType(*itr);
if(!auraList.empty())
auraList.front()->ApplyModifier(true,true);
}
@@ -18080,12 +18669,13 @@ void Player::SendInitialPacketsAfterAddToMap()
// manual send package (have code in ApplyModifier(true,true); that don't must be re-applied.
if(HasAuraType(SPELL_AURA_MOD_ROOT))
{
- WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
- data.append(GetPackGUID());
- data << (uint32)2;
- SendMessageToSet(&data,true);
+ WorldPacket data2(SMSG_FORCE_MOVE_ROOT, 10);
+ data2.append(GetPackGUID());
+ data2 << (uint32)2;
+ SendMessageToSet(&data2,true);
}
+ SendAurasForTarget(this);
SendEnchantmentDurations(); // must be after add to map
SendItemDurations(); // must be after add to map
}
@@ -18098,16 +18688,24 @@ void Player::SendUpdateToOutOfRangeGroupMembers()
group->UpdatePlayerOutOfRange(this);
m_groupUpdateMask = GROUP_UPDATE_FLAG_NONE;
- m_auraUpdateMask = 0;
+ m_auraRaidUpdateMask = 0;
if(Pet *pet = GetPet())
- pet->ResetAuraUpdateMask();
+ pet->ResetAuraUpdateMaskForRaid();
}
-void Player::SendTransferAborted(uint32 mapid, uint16 reason)
+void Player::SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg)
{
WorldPacket data(SMSG_TRANSFER_ABORTED, 4+2);
data << uint32(mapid);
- data << uint16(reason); // transfer abort reason
+ data << uint8(reason); // transfer abort reason
+ switch(reason)
+ {
+ case TRANSFER_ABORT_INSUF_EXPAN_LVL:
+ case TRANSFER_ABORT_DIFFICULTY:
+ case TRANSFER_ABORT_UNIQUE_MESSAGE:
+ data << uint8(arg);
+ break;
+ }
GetSession()->SendPacket(&data);
}
@@ -18132,7 +18730,7 @@ void Player::SendInstanceResetWarning(uint32 mapid, uint32 time)
void Player::ApplyEquipCooldown( Item * pItem )
{
- for(int i = 0; i <5; ++i)
+ for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = pItem->GetProto()->Spells[i];
@@ -18173,22 +18771,18 @@ void Player::resetSpells()
learnQuestRewardedSpells();
}
-void Player::learnDefaultSpells(bool loading)
+void Player::learnDefaultSpells()
{
// learn default race/class spells
PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(),getClass());
- std::list<CreateSpellPair>::const_iterator spell_itr;
- for (spell_itr = info->spell.begin(); spell_itr!=info->spell.end(); ++spell_itr)
+ for (PlayerCreateInfoSpells::const_iterator itr = info->spell.begin(); itr!=info->spell.end(); ++itr)
{
- uint16 tspell = spell_itr->first;
- if (tspell)
- {
- sLog.outDebug("PLAYER: Adding initial spell, id = %u",tspell);
- if(loading || !spell_itr->second) // not care about passive spells or loading case
- addSpell(tspell,spell_itr->second);
- else // but send in normal spell in game learn case
- learnSpell(tspell);
- }
+ uint32 tspell = *itr;
+ sLog.outDebug("PLAYER (Class: %u Race: %u): Adding initial spell, id = %u",uint32(getClass()),uint32(getRace()), tspell);
+ if(!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add
+ addSpell(tspell,true,true,true,false);
+ else // but send in normal spell in game learn case
+ learnSpell(tspell,true);
}
}
@@ -18280,7 +18874,7 @@ void Player::learnQuestRewardedSpells()
}
}
-void Player::learnSkillRewardedSpells(uint32 skill_id )
+void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value )
{
uint32 raceMask = getRaceMask();
uint32 classMask = getClassMask();
@@ -18298,35 +18892,56 @@ void Player::learnSkillRewardedSpells(uint32 skill_id )
if (sSpellStore.LookupEntry(pAbility->spellId))
{
- // Ok need learn spell
- learnSpell(pAbility->spellId);
+ // need unlearn spell
+ if (skill_value < pAbility->req_skill_value)
+ removeSpell(pAbility->spellId);
+ // need learn
+ else if (!IsInWorld())
+ addSpell(pAbility->spellId,true,true,true,false);
+ else
+ learnSpell(pAbility->spellId,true);
}
}
}
-void Player::learnSkillRewardedSpells()
+void Player::SendAurasForTarget(Unit *target)
{
- for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
- {
- if(!GetUInt32Value(PLAYER_SKILL_INDEX(i)))
- continue;
-
- uint32 pskill = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF;
+ if(!target || target->GetVisibleAuras()->empty()) // speedup things
+ return;
- learnSkillRewardedSpells(pskill);
- }
-}
+ WorldPacket data(SMSG_AURA_UPDATE_ALL);
+ data.append(target->GetPackGUID());
-void Player::SendAuraDurationsForTarget(Unit* target)
-{
- for(Unit::AuraMap::const_iterator itr = target->GetAuras().begin(); itr != target->GetAuras().end(); ++itr)
+ Unit::VisibleAuraMap const *visibleAuras = target->GetVisibleAuras();
+ for(Unit::VisibleAuraMap::const_iterator itr = visibleAuras->begin(); itr != visibleAuras->end(); ++itr)
{
- Aura* aura = itr->second;
- if(aura->GetAuraSlot() >= MAX_AURAS || aura->IsPassive() || aura->GetCasterGUID()!=GetGUID())
- continue;
+ Aura * aura=itr->second;
+ data << uint8(aura->GetAuraSlot());
+ data << uint32(aura->GetId());
+
+ // flags
+ data << aura->m_auraFlags;
+ // level
+ data << aura->m_auraLevel;
+ // charges
+ data << uint8(aura->GetStackAmount()>1 ? aura->GetStackAmount() : aura->GetAuraCharges());
+
+ if(!(aura->m_auraFlags & AFLAG_CASTER))
+ {
+ if (Unit * caster = aura->GetCaster())
+ data.append(caster->GetPackGUID());
+ else
+ data << uint8(0);
+ }
- aura->SendAuraDurationForCaster(this);
+ if(aura->m_auraFlags & AFLAG_DURATION) // include aura duration
+ {
+ data << uint32(aura->GetAuraMaxDuration());
+ data << uint32(aura->GetAuraDuration());
+ }
}
+
+ GetSession()->SendPacket(&data);
}
void Player::SetDailyQuestStatus( uint32 quest_id )
@@ -18358,7 +18973,7 @@ BattleGround* Player::GetBattleGround() const
if(GetBattleGroundId()==0)
return NULL;
- return sBattleGroundMgr.GetBattleGround(GetBattleGroundId());
+ return sBattleGroundMgr.GetBattleGround(GetBattleGroundId(), m_bgTypeID);
}
bool Player::InArena() const
@@ -18370,7 +18985,7 @@ bool Player::InArena() const
return true;
}
-bool Player::GetBGAccessByLevel(uint32 bgTypeId) const
+bool Player::GetBGAccessByLevel(BattleGroundTypeId bgTypeId) const
{
// get a template bg instead of running one
BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
@@ -18383,46 +18998,26 @@ bool Player::GetBGAccessByLevel(uint32 bgTypeId) const
return true;
}
-uint32 Player::GetMinLevelForBattleGroundQueueId(uint32 queue_id)
-{
- if(queue_id < 1)
- return 0;
-
- if(queue_id >=6)
- queue_id = 6;
-
- return 10*(queue_id+1);
-}
-
-uint32 Player::GetMaxLevelForBattleGroundQueueId(uint32 queue_id)
-{
- if(queue_id >=6)
- return 255; // hardcoded max level
-
- return 10*(queue_id+2)-1;
-}
-
-//TODO make this more generic - current implementation is wrong
-uint32 Player::GetBattleGroundQueueIdFromLevel() const
+BGQueueIdBasedOnLevel Player::GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const
{
+ //returned to hardcoded version of this function, because there is no way to code it dynamic
uint32 level = getLevel();
- if(level <= 19)
- return 0;
- else if (level > 69)
- return 6;
- else
- return level/10 - 1; // 20..29 -> 1, 30-39 -> 2, ...
- /*
- assert(bgTypeId < MAX_BATTLEGROUND_TYPES);
- BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
- assert(bg);
- return (getLevel() - bg->GetMinLevel()) / 10;*/
+ if( bgTypeId == BATTLEGROUND_AV )
+ level--;
+
+ uint32 queue_id = (level / 10) - 1; // for ranges 0 - 19, 20 - 29, 30 - 39, 40 - 49, 50 - 59, 60 - 69, 70 -79, 80
+ if( queue_id >= MAX_BATTLEGROUND_QUEUES )
+ {
+ sLog.outError("BattleGround: too high queue_id %u this shouldn't happen", queue_id);
+ return QUEUE_ID_MAX_LEVEL_80;
+ }
+ return BGQueueIdBasedOnLevel(queue_id);
}
float Player::GetReputationPriceDiscount( Creature const* pCreature ) const
{
FactionTemplateEntry const* vendor_faction = pCreature->getFactionTemplateEntry();
- if(!vendor_faction)
+ if(!vendor_faction || !vendor_faction->faction)
return 1.0f;
ReputationRank rank = GetReputationRank(vendor_faction->faction);
@@ -18439,28 +19034,42 @@ bool Player::IsSpellFitByClassAndRace( uint32 spell_id ) const
SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id);
SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id);
+ if(lower==upper)
+ return true;
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
{
// skip wrong race skills
if( _spell_idx->second->racemask && (_spell_idx->second->racemask & racemask) == 0)
- return false;
+ continue;
// skip wrong class skills
if( _spell_idx->second->classmask && (_spell_idx->second->classmask & classmask) == 0)
- return false;
+ continue;
+
+ return true;
}
- return true;
+
+ return false;
}
-bool Player::HasQuestForGO(int32 GOId)
+bool Player::HasQuestForGO(int32 GOId) const
{
- for( QuestStatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i )
+ for( int i = 0; i < MAX_QUEST_LOG_SIZE; ++i )
{
- QuestStatusData qs=i->second;
+ uint32 questid = GetQuestSlotQuestId(i);
+ if ( questid == 0 )
+ continue;
+
+ QuestStatusMap::const_iterator qs_itr = mQuestStatus.find(questid);
+ if(qs_itr == mQuestStatus.end())
+ continue;
+
+ QuestStatusData const& qs = qs_itr->second;
+
if (qs.m_status == QUEST_STATUS_INCOMPLETE)
{
- Quest const* qinfo = objmgr.GetQuestTemplate(i->first);
+ Quest const* qinfo = objmgr.GetQuestTemplate(questid);
if(!qinfo)
continue;
@@ -18480,7 +19089,7 @@ bool Player::HasQuestForGO(int32 GOId)
return false;
}
-void Player::UpdateForQuestsGO()
+void Player::UpdateForQuestWorldObjects()
{
if(m_clientGUIDs.empty())
return;
@@ -18495,6 +19104,24 @@ void Player::UpdateForQuestsGO()
if(obj)
obj->BuildValuesUpdateBlockForPlayer(&udata,this);
}
+ else if(IS_CREATURE_GUID(*itr) || IS_VEHICLE_GUID(*itr))
+ {
+ Creature *obj = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, *itr);
+ if(!obj)
+ continue;
+ // check if this unit requires quest specific flags
+
+ SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap;
+ for(SpellClickInfoMap::const_iterator itr = map.lower_bound(obj->GetEntry()); itr != map.upper_bound(obj->GetEntry()); ++itr)
+ {
+ if(itr->second.questId != 0)
+ {
+ obj->BuildCreateUpdateBlockForPlayer(&udata,this);
+ break;
+ }
+ }
+
+ }
}
udata.BuildPacket(&packet);
GetSession()->SendPacket(&packet);
@@ -18520,11 +19147,14 @@ void Player::SummonIfPossible(bool agree)
}
// drop flag at summon
+ // this code can be reached only when GM is summoning player who carries flag, because player should be immune to summoning spells when he carries flag
if(BattleGround *bg = GetBattleGround())
bg->EventPlayerDroppedFlag(this);
m_summon_expire = 0;
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS, 1);
+
TeleportTo(m_summon_mapid, m_summon_x, m_summon_y, m_summon_z,GetOrientation());
}
@@ -18555,9 +19185,8 @@ void Player::AutoUnequipOffhandIfNeed()
if(!offItem)
return;
- Item *mainItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND );
-
- if(!mainItem || mainItem->GetProto()->InventoryType != INVTYPE_2HWEAPON)
+ // need unequip offhand for 2h-weapon without TitanGrip (in any from hands)
+ if (CanTitanGrip() || (offItem->GetProto()->InventoryType != INVTYPE_2HWEAPON && !IsTwoHandUsed()))
return;
ItemPosCountVec off_dest;
@@ -18569,7 +19198,16 @@ void Player::AutoUnequipOffhandIfNeed()
}
else
{
- sLog.outError("Player::EquipItem: Can's store offhand item at 2hand item equip for player (GUID: %u).",GetGUIDLow());
+ MailItemsInfo mi;
+ mi.AddItem(offItem->GetGUIDLow(), offItem->GetEntry(), offItem);
+ MoveItemFromInventory(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND, true);
+ CharacterDatabase.BeginTransaction();
+ offItem->DeleteFromInventoryDB(); // deletes item from character's inventory
+ offItem->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone
+ CharacterDatabase.CommitTransaction();
+
+ std::string subject = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM);
+ WorldSession::SendMailTo(this, MAIL_NORMAL, MAIL_STATIONERY_GM, GetGUIDLow(), GetGUIDLow(), subject, 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
}
}
@@ -18590,7 +19228,7 @@ bool Player::HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item cons
case ITEM_CLASS_WEAPON:
{
for(int i= EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_TABARD; ++i)
- if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
+ if(Item *item = GetUseableItemByPos( INVENTORY_SLOT_BAG_0, i ))
if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo))
return true;
break;
@@ -18599,17 +19237,17 @@ bool Player::HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item cons
{
// tabard not have dependent spells
for(int i= EQUIPMENT_SLOT_START; i< EQUIPMENT_SLOT_MAINHAND; ++i)
- if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, i ))
+ if(Item *item = GetUseableItemByPos( INVENTORY_SLOT_BAG_0, i ))
if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo))
return true;
// shields can be equipped to offhand slot
- if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
+ if(Item *item = GetUseableItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo))
return true;
// ranged slot can have some armor subclasses
- if(Item *item = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
+ if(Item *item = GetUseableItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
if(item!=ignoreItem && item->IsFitToSpellRequirements(spellInfo))
return true;
@@ -18623,6 +19261,24 @@ bool Player::HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item cons
return false;
}
+bool Player::CanNoReagentCast(SpellEntry const* spellInfo) const
+{
+ // don't take reagents for spells with SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP
+ if (spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP &&
+ HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION))
+ return true;
+
+ // Check no reagent use mask
+ flag96 noReagentMask;
+ noReagentMask[0] = GetUInt32Value(PLAYER_NO_REAGENT_COST_1);
+ noReagentMask[1] = GetUInt32Value(PLAYER_NO_REAGENT_COST_1+1);
+ noReagentMask[2] = GetUInt32Value(PLAYER_NO_REAGENT_COST_1+2);
+ if (spellInfo->SpellFamilyFlags & noReagentMask)
+ return true;
+
+ return false;
+}
+
void Player::RemoveItemDependentAurasAndCasts( Item * pItem )
{
AuraMap& auras = GetAuras();
@@ -18646,8 +19302,7 @@ void Player::RemoveItemDependentAurasAndCasts( Item * pItem )
}
// no alt item, remove aura, restart check
- RemoveAurasDueToSpell(aura->GetId());
- itr = auras.begin();
+ RemoveAura(itr);
}
// currently casted spells can be dependent from item
@@ -18664,11 +19319,11 @@ uint32 Player::GetResurrectionSpellId()
// search priceless resurrection possibilities
uint32 prio = 0;
uint32 spell_id = 0;
- AuraList const& dummyAuras = GetAurasByType(SPELL_AURA_DUMMY);
- for(AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
+ AuraEffectList const& dummyAuras = GetAurasByType(SPELL_AURA_DUMMY);
+ for(AuraEffectList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
// Soulstone Resurrection // prio: 3 (max, non death persistent)
- if( prio < 2 && (*itr)->GetSpellProto()->SpellVisual == 99 && (*itr)->GetSpellProto()->SpellIconID == 92 )
+ if( prio < 2 && (*itr)->GetSpellProto()->SpellVisual[0] == 99 && (*itr)->GetSpellProto()->SpellIconID == 92 )
{
switch((*itr)->GetId())
{
@@ -18678,8 +19333,9 @@ uint32 Player::GetResurrectionSpellId()
case 20764: spell_id = 20760; break; // rank 4
case 20765: spell_id = 20761; break; // rank 5
case 27239: spell_id = 27240; break; // rank 6
+ case 47883: spell_id = 47882; break; // rank 7
default:
- sLog.outError("Unhandled spell %%u: S.Resurrection",(*itr)->GetId());
+ sLog.outError("Unhandled spell %u: S.Resurrection",(*itr)->GetId());
continue;
}
@@ -18700,6 +19356,26 @@ uint32 Player::GetResurrectionSpellId()
return spell_id;
}
+// Used in triggers for check "Only to targets that grant experience or honor" req
+bool Player::isHonorOrXPTarget(Unit* pVictim)
+{
+ uint32 v_level = pVictim->getLevel();
+ uint32 k_grey = Trinity::XP::GetGrayLevel(getLevel());
+
+ // Victim level less gray level
+ if(v_level<=k_grey)
+ return false;
+
+ if(pVictim->GetTypeId() == TYPEID_UNIT)
+ {
+ if (((Creature*)pVictim)->isTotem() ||
+ ((Creature*)pVictim)->isPet() ||
+ ((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL)
+ return false;
+ }
+ return true;
+}
+
bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim)
{
bool PvP = pVictim->isCharmedOwnedByPlayerOrPlayer();
@@ -18797,19 +19473,44 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim)
return xp || honored_kill;
}
+void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewardSource)
+{
+ uint64 creature_guid = pRewardSource->GetTypeId()==TYPEID_UNIT ? pRewardSource->GetGUID() : uint64(0);
+
+ // prepare data for near group iteration
+ if(Group *pGroup = GetGroup())
+ {
+ for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player* pGroupGuy = itr->getSource();
+ if(!pGroupGuy)
+ continue;
+
+ if(!pGroupGuy->IsAtGroupRewardDistance(pRewardSource))
+ continue; // member (alive or dead) or his corpse at req. distance
+
+ // quest objectives updated only for alive group member or dead but with not released body
+ if(pGroupGuy->isAlive()|| !pGroupGuy->GetCorpse())
+ pGroupGuy->KilledMonster(creature_id, creature_guid);
+ }
+ }
+ else // if (!pGroup)
+ KilledMonster(creature_id, creature_guid);
+}
+
bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
{
- if(pRewardSource->GetDistance(this) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ if (pRewardSource->IsWithinDistInMap(this,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)))
return true;
- if(isAlive())
+ if (isAlive())
return false;
Corpse* corpse = GetCorpse();
- if(!corpse)
+ if (!corpse)
return false;
- return pRewardSource->GetDistance(corpse) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE);
+ return pRewardSource->IsWithinDistInMap(corpse,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE));
}
uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const
@@ -18821,12 +19522,15 @@ uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const
return 0;
// weapon skill or (unarmed for base attack)
- uint32 skill = item ? item->GetSkill() : SKILL_UNARMED;
+ uint32 skill = item ? item->GetSkill() : uint32(SKILL_UNARMED);
return GetBaseSkillValue(skill);
}
void Player::ResurectUsingRequestData()
{
+ /// Teleport before resurrecting, otherwise the player might get attacked from creatures near his corpse
+ TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation());
+
ResurrectPlayer(0.0f,false);
if(GetMaxHealth() > m_resurrectHealth)
@@ -18844,8 +19548,6 @@ void Player::ResurectUsingRequestData()
SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY) );
SpawnCorpseBones();
-
- TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation());
}
void Player::SetClientControl(Unit* target, uint8 allowMove)
@@ -18854,34 +19556,25 @@ void Player::SetClientControl(Unit* target, uint8 allowMove)
data.append(target->GetPackGUID());
data << uint8(allowMove);
GetSession()->SendPacket(&data);
+ if(target == this)
+ SetMover(this);
}
void Player::UpdateZoneDependentAuras( uint32 newZone )
{
// remove new continent flight forms
- if( !isGameMaster() &&
- GetVirtualMapForMapAndZone(GetMapId(),newZone) != 530)
+ if( !IsAllowUseFlyMountsHere() )
{
- RemoveSpellsCausingAura(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED);
- RemoveSpellsCausingAura(SPELL_AURA_FLY);
+ RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED);
+ RemoveAurasByType(SPELL_AURA_FLY);
}
- // Some spells applied at enter into zone (with subzones)
- // Human Illusion
- // NOTE: these are removed by RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP);
- if ( newZone == 2367 ) // Old Hillsbrad Foothills
- {
- uint32 spellid = 0;
- // all horde races
- if( GetTeam() == HORDE )
- spellid = getGender() == GENDER_FEMALE ? 35481 : 35480;
- // and some alliance races
- else if( getRace() == RACE_NIGHTELF || getRace() == RACE_DRAENEI )
- spellid = getGender() == GENDER_FEMALE ? 35483 : 35482;
-
- if(spellid && !HasAura(spellid,0) )
- CastSpell(this,spellid,true);
- }
+ // Some spells applied at enter into zone (with subzones), aura removed in UpdateAreaDependentAuras that called always at zone->area update
+ SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newZone);
+ for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
+ if(itr->second->autocast && itr->second->IsFitToRequirements(this,newZone,0))
+ if( !HasAura(itr->second->spellId) )
+ CastSpell(this,itr->second->spellId,true);
}
void Player::UpdateAreaDependentAuras( uint32 newArea )
@@ -18890,26 +19583,18 @@ void Player::UpdateAreaDependentAuras( uint32 newArea )
for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
{
// use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date
- if(!IsSpellAllowedInLocation(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea))
+ if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this) != SPELL_CAST_OK)
RemoveAura(iter);
else
++iter;
}
- // unmount if enter in this subzone
- if( newArea == 35)
- RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
- // Dragonmaw Illusion
- else if( newArea == 3759 || newArea == 3966 || newArea == 3939 )
- {
- if( GetDummyAura(40214) )
- {
- if( !HasAura(40216,0) )
- CastSpell(this,40216,true);
- if( !HasAura(42016,0) )
- CastSpell(this,42016,true);
- }
- }
+ // some auras applied at subzone enter
+ SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newArea);
+ for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
+ if(itr->second->autocast && itr->second->IsFitToRequirements(this,m_zoneUpdateId,newArea))
+ if( !HasAura(itr->second->spellId) )
+ CastSpell(this,itr->second->spellId,true);
}
uint32 Player::GetCorpseReclaimDelay(bool pvp) const
@@ -18995,7 +19680,7 @@ void Player::SendCorpseReclaimDelay(bool load)
//! corpse reclaim delay 30 * 1000ms or longer at often deaths
WorldPacket data(SMSG_CORPSE_RECLAIM_DELAY, 4);
- data << uint32(delay*1000);
+ data << uint32(delay*IN_MILISECONDS);
GetSession()->SendPacket( &data );
}
@@ -19040,21 +19725,85 @@ PartyResult Player::CanUninviteFromGroup() const
return PARTY_RESULT_OK;
}
+void Player::SetBattleGroundRaid(Group* group, int8 subgroup)
+{
+ //we must move references from m_group to m_originalGroup
+ SetOriginalGroup(GetGroup(), GetSubGroup());
+
+ m_group.unlink();
+ m_group.link(group, this);
+ m_group.setSubGroup((uint8)subgroup);
+}
+
+void Player::RemoveFromBattleGroundRaid()
+{
+ //remove existing reference
+ m_group.unlink();
+ if( Group* group = GetOriginalGroup() )
+ {
+ m_group.link(group, this);
+ m_group.setSubGroup(GetOriginalSubGroup());
+ }
+ SetOriginalGroup(NULL);
+}
+
+void Player::SetOriginalGroup(Group *group, int8 subgroup)
+{
+ if( group == NULL )
+ m_originalGroup.unlink();
+ else
+ {
+ // never use SetOriginalGroup without a subgroup unless you specify NULL for group
+ assert(subgroup >= 0);
+ m_originalGroup.link(group, this);
+ m_originalGroup.setSubGroup((uint8)subgroup);
+ }
+}
+
void Player::UpdateUnderwaterState( Map* m, float x, float y, float z )
{
- float water_z = m->GetWaterLevel(x,y);
- float height_z = m->GetHeight(x,y,z, false); // use .map base surface height
- uint8 flag1 = m->GetTerrainType(x,y);
+ LiquidData liquid_status;
+ ZLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
+ if (!res)
+ {
+ m_MirrorTimerFlags &= ~(UNDERWATER_INWATER|UNDERWATER_INLAVA|UNDERWATER_INSLIME|UNDERWARER_INDARKWATER);
+ // Small hack for enable breath in WMO
+ if (IsInWater())
+ m_MirrorTimerFlags|=UNDERWATER_INWATER;
+ return;
+ }
+
+ // All liquids type - check under water position
+ if (liquid_status.type&(MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN|MAP_LIQUID_TYPE_MAGMA|MAP_LIQUID_TYPE_SLIME))
+ {
+ if ( res & LIQUID_MAP_UNDER_WATER)
+ m_MirrorTimerFlags |= UNDERWATER_INWATER;
+ else
+ m_MirrorTimerFlags &= ~UNDERWATER_INWATER;
+ }
- //!Underwater check, not in water if underground or above water level
- if (height_z <= INVALID_HEIGHT || z < (height_z-2) || z > (water_z - 2) )
- m_isunderwater &= 0x7A;
- else if ((z < (water_z - 2)) && (flag1 & 0x01))
- m_isunderwater |= 0x01;
+ // Allow travel in dark water on taxi or transport
+ if ((liquid_status.type & MAP_LIQUID_TYPE_DARK_WATER) && !isInFlight() && !GetTransport())
+ m_MirrorTimerFlags |= UNDERWARER_INDARKWATER;
+ else
+ m_MirrorTimerFlags &= ~UNDERWARER_INDARKWATER;
- //!in lava check, anywhere under lava level
- if ((height_z <= INVALID_HEIGHT || z < (height_z - 0)) && (flag1 == 0x00) && IsInWater())
- m_isunderwater |= 0x80;
+ // in lava check, anywhere in lava level
+ if (liquid_status.type&MAP_LIQUID_TYPE_MAGMA)
+ {
+ if (res & (LIQUID_MAP_UNDER_WATER|LIQUID_MAP_IN_WATER|LIQUID_MAP_WATER_WALK))
+ m_MirrorTimerFlags |= UNDERWATER_INLAVA;
+ else
+ m_MirrorTimerFlags &= ~UNDERWATER_INLAVA;
+ }
+ // in slime check, anywhere in slime level
+ if (liquid_status.type&MAP_LIQUID_TYPE_SLIME)
+ {
+ if (res & (LIQUID_MAP_UNDER_WATER|LIQUID_MAP_IN_WATER|LIQUID_MAP_WATER_WALK))
+ m_MirrorTimerFlags |= UNDERWATER_INSLIME;
+ else
+ m_MirrorTimerFlags &= ~UNDERWATER_INSLIME;
+ }
}
void Player::SetCanParry( bool value )
@@ -19087,140 +19836,157 @@ bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const
//-------------TRINITY---------------
//***********************************
-void Player::HandleFallDamage(MovementInfo& movementInfo)
+void Player::StopCastingBindSight()
{
- if(movementInfo.fallTime < 1500)
- return;
-
- // calculate total z distance of the fall
- float z_diff = m_lastFallZ - movementInfo.z;
- sLog.outDebug("zDiff = %f", z_diff);
-
- //Players with low fall distance, Feather Fall or physical immunity (charges used) are ignored
- // 14.57 can be calculated by resolving damageperc formular below to 0
- if (z_diff >= 14.57f && !isDead() && !isGameMaster() &&
- !HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) &&
- !HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL,true) )
+ if(WorldObject* target = GetViewpoint())
{
- //Safe fall, fall height reduction
- int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
-
- float damageperc = 0.018f*(z_diff-safe_fall)-0.2426f;
-
- if(damageperc >0 )
+ if(target->isType(TYPEMASK_UNIT))
{
- uint32 damage = (uint32)(damageperc * GetMaxHealth()*sWorld.getRate(RATE_DAMAGE_FALL));
-
- float height = movementInfo.z;
- UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
-
- if (damage > 0)
- {
- //Prevent fall damage from being more than the player maximum health
- if (damage > GetMaxHealth())
- damage = GetMaxHealth();
-
- // Gust of Wind
- if (GetDummyAura(43621))
- damage = GetMaxHealth()/2;
-
- EnvironmentalDamage(GetGUID(), DAMAGE_FALL, damage);
- }
-
- //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
- DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
+ ((Unit*)target)->RemoveAura(SPELL_AURA_BIND_SIGHT, GetGUID());
+ ((Unit*)target)->RemoveAura(SPELL_AURA_MOD_POSSESS, GetGUID());
+ ((Unit*)target)->RemoveAura(SPELL_AURA_MOD_POSSESS_PET, GetGUID());
}
}
}
-void Player::HandleFallUnderMap()
+void Player::SetViewpoint(WorldObject* target, bool apply)
{
- if(InBattleGround()
- && GetBattleGround()
- && GetBattleGround()->HandlePlayerUnderMap(this))
+ if(apply)
{
- // do nothing, the handle already did if returned true
+ sLog.outDebug("Player::CreateViewpoint: Player %s create seer %u (TypeId: %u).", GetName(), target->GetEntry(), target->GetTypeId());
+
+ if(!AddUInt64Value(PLAYER_FARSIGHT, target->GetGUID()))
+ {
+ sLog.outCrash("Player::CreateViewpoint: Player %s cannot add new viewpoint!", GetName());
+ return;
+ }
+
+ if(target->isType(TYPEMASK_UNIT) && !m_Vehicle)
+ ((Unit*)target)->AddPlayerToVision(this);
}
else
{
- // NOTE: this is actually called many times while falling
- // even after the player has been teleported away
- // TODO: discard movement packets after the player is rooted
- if(isAlive())
+ sLog.outDebug("Player::CreateViewpoint: Player %s remove seer", GetName());
+
+ if(!RemoveUInt64Value(PLAYER_FARSIGHT, target->GetGUID()))
{
- EnvironmentalDamage(GetGUID(),DAMAGE_FALL_TO_VOID, GetMaxHealth());
- // change the death state to CORPSE to prevent the death timer from
- // starting in the next player update
- KillPlayer();
- BuildPlayerRepop();
+ sLog.outCrash("Player::CreateViewpoint: Player %s cannot remove current viewpoint!", GetName());
+ return;
}
- // cancel the death timer here if started
- RepopAtGraveyard();
+ if(target->isType(TYPEMASK_UNIT) && !m_Vehicle)
+ ((Unit*)target)->RemovePlayerFromVision(this);
+
+ //must immediately set seer back otherwise may crash
+ m_seer = this;
+
+ //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0);
+ //GetSession()->SendPacket(&data);
}
}
-void Player::SetViewport(uint64 guid, bool moveable)
+WorldObject* Player::GetViewpoint() const
{
- WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, 8+1);
- data.appendPackGUID(guid); // Packed guid of object to set client's view to
- data << (moveable ? uint8(0x01) : uint8(0x00)); // 0 - can't move; 1 - can move
- m_session->SendPacket(&data);
- sLog.outDetail("Viewport for "I64FMT" (%s) changed to "I64FMT, GetGUID(), GetName(), guid);
+ if(uint64 guid = GetUInt64Value(PLAYER_FARSIGHT))
+ return (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*this, guid, TYPEMASK_SEER);
+ return NULL;
}
-WorldObject* Player::GetFarsightTarget() const
-{
- // Players can have in farsight field another player's guid, a creature's guid, or a dynamic object's guid
- if (uint64 guid = GetUInt64Value(PLAYER_FARSIGHT))
- return (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*this, guid, TYPEMASK_PLAYER | TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT);
- return NULL;
+bool Player::CanUseBattleGroundObject()
+{
+ // TODO : some spells gives player ForceReaction to one faction (ReputationMgr::ApplyForceReaction)
+ // maybe gameobject code should handle that ForceReaction usage
+ // BUG: sometimes when player clicks on flag in AB - client won't send gameobject_use, only gameobject_report_use packet
+ return ( //InBattleGround() && // in battleground - not need, check in other cases
+ //!IsMounted() && - not correct, player is dismounted when he clicks on flag
+ //player cannot use object when he is invulnerable (immune)
+ !isTotalImmune() && // not totally immune
+ //i'm not sure if these two are correct, because invisible players should get visible when they click on flag
+ !HasStealthAura() && // not stealthed
+ !HasInvisibilityAura() && // not invisible
+ !HasAura(SPELL_RECENTLY_DROPPED_FLAG) && // can't pickup
+ isAlive() // live player
+ );
}
-void Player::StopCastingBindSight()
+bool Player::CanCaptureTowerPoint()
{
- if(WorldObject* target = GetFarsightTarget())
- {
- if(target->isType(TYPEMASK_UNIT))
- {
- ((Unit*)target)->RemoveAuraTypeByCaster(SPELL_AURA_BIND_SIGHT, GetGUID());
- ((Unit*)target)->RemoveAuraTypeByCaster(SPELL_AURA_MOD_POSSESS, GetGUID());
- ((Unit*)target)->RemoveAuraTypeByCaster(SPELL_AURA_MOD_POSSESS_PET, GetGUID());
- }
- }
+ return ( !HasStealthAura() && // not stealthed
+ !HasInvisibilityAura() && // not invisible
+ isAlive() // live player
+ );
}
-void Player::ClearFarsight()
+uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair)
{
- if (GetUInt64Value(PLAYER_FARSIGHT))
- {
- SetUInt64Value(PLAYER_FARSIGHT, 0);
- WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0);
- GetSession()->SendPacket(&data);
- }
+ uint32 level = getLevel();
+
+ if(level > GT_MAX_LEVEL)
+ level = GT_MAX_LEVEL; // max level in this dbc
+
+ uint8 hairstyle = GetByteValue(PLAYER_BYTES, 2);
+ uint8 haircolor = GetByteValue(PLAYER_BYTES, 3);
+ uint8 facialhair = GetByteValue(PLAYER_BYTES_2, 0);
+
+ if((hairstyle == newhairstyle) && (haircolor == newhaircolor) && (facialhair == newfacialhair))
+ return 0;
+
+ GtBarberShopCostBaseEntry const *bsc = sGtBarberShopCostBaseStore.LookupEntry(level - 1);
+
+ if(!bsc) // shouldn't happen
+ return 0xFFFFFFFF;
+
+ float cost = 0;
+
+ if(hairstyle != newhairstyle)
+ cost += bsc->cost; // full price
+
+ if((haircolor != newhaircolor) && (hairstyle == newhairstyle))
+ cost += bsc->cost * 0.5f; // +1/2 of price
+
+ if(facialhair != newfacialhair)
+ cost += bsc->cost * 0.75f; // +3/4 of price
+
+ return uint32(cost);
}
-void Player::SetFarsightTarget(WorldObject* obj)
+void Player::InitGlyphsForLevel()
{
- if (!obj || !obj->isType(TYPEMASK_PLAYER | TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT))
- return;
+ for(uint32 i = 0; i < sGlyphSlotStore.GetNumRows(); ++i)
+ if(GlyphSlotEntry const * gs = sGlyphSlotStore.LookupEntry(i))
+ if(gs->Order)
+ SetGlyphSlot(gs->Order - 1, gs->Id);
+
+ uint32 level = getLevel();
+ uint32 value = 0;
- // Remove the current target if there is one
- StopCastingBindSight();
+ // 0x3F = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 for 80 level
+ if(level >= 15)
+ value |= (0x01 | 0x02);
+ if(level >= 30)
+ value |= 0x08;
+ if(level >= 50)
+ value |= 0x04;
+ if(level >= 70)
+ value |= 0x10;
+ if(level >= 80)
+ value |= 0x20;
- SetUInt64Value(PLAYER_FARSIGHT, obj->GetGUID());
+ SetUInt32Value(PLAYER_GLYPHS_ENABLED, value);
}
-bool Player::isAllowUseBattleGroundObject()
+bool Player::isTotalImmune()
{
- return ( //InBattleGround() && // in battleground - not need, check in other cases
- !IsMounted() && // not mounted
- !isTotalImmunity() && // not totally immuned
- !HasStealthAura() && // not stealthed
- !HasInvisibilityAura() && // not invisible
- !HasAura(SPELL_RECENTLY_DROPPED_FLAG, 0) && // can't pickup
- isAlive() // live player
- );
+ AuraEffectList const& immune = GetAurasByType(SPELL_AURA_SCHOOL_IMMUNITY);
+
+ uint32 immuneMask = 0;
+ for(AuraEffectList::const_iterator itr = immune.begin(); itr != immune.end(); ++itr)
+ {
+ immuneMask |= (*itr)->GetMiscValue();
+ if( immuneMask & SPELL_SCHOOL_MASK_ALL ) // total immunity
+ return true;
+ }
+ return false;
}
bool Player::HasTitle(uint32 bitIndex)
@@ -19240,23 +20006,22 @@ void Player::SetTitle(CharTitlesEntry const* title)
SetFlag(PLAYER__FIELD_KNOWN_TITLES+fieldIndexOffset, flag);
}
-
/*-----------------------TRINITY--------------------------*/
bool Player::isTotalImmunity()
{
- AuraList const& immune = GetAurasByType(SPELL_AURA_SCHOOL_IMMUNITY);
+ AuraEffectList const& immune = GetAurasByType(SPELL_AURA_SCHOOL_IMMUNITY);
- for(AuraList::const_iterator itr = immune.begin(); itr != immune.end(); ++itr)
+ for(AuraEffectList::const_iterator itr = immune.begin(); itr != immune.end(); ++itr)
{
- if (((*itr)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_ALL) !=0) // total immunity
+ if (((*itr)->GetMiscValue() & SPELL_SCHOOL_MASK_ALL) !=0) // total immunity
{
return true;
}
- if (((*itr)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) !=0) // physical damage immunity
+ if (((*itr)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) !=0) // physical damage immunity
{
- for(AuraList::const_iterator i = immune.begin(); i != immune.end(); ++i)
+ for(AuraEffectList::const_iterator i = immune.begin(); i != immune.end(); ++i)
{
- if (((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_MAGIC) !=0) // magic immunity
+ if (((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) !=0) // magic immunity
{
return true;
}
@@ -19274,9 +20039,9 @@ void Player::UpdateCharmedAI()
//kill self if charm aura has infinite duration
if(charmer->IsInEvadeMode())
{
- AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_CHARM);
- for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
- if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->IsPermanent())
+ AuraEffectList const& auras = GetAurasByType(SPELL_AURA_MOD_CHARM);
+ for(AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
+ if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetParentAura()->IsPermanent())
{
charmer->DealDamage(this, GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
return;
@@ -19298,3 +20063,628 @@ void Player::UpdateCharmedAI()
}
}
+void Player::ConvertRune(uint8 index, uint8 newType)
+{
+ SetCurrentRune(index, newType);
+
+ WorldPacket data(SMSG_CONVERT_RUNE, 2);
+ data << uint8(index);
+ data << uint8(newType);
+ GetSession()->SendPacket(&data);
+}
+
+void Player::ResyncRunes(uint8 count)
+{
+ WorldPacket data(SMSG_RESYNC_RUNES, count * 2);
+ for(uint32 i = 0; i < count; ++i)
+ {
+ data << uint8(GetCurrentRune(i)); // rune type
+ data << uint8(255 - (GetRuneCooldown(i) * 51)); // passed cooldown time (0-255)
+ }
+ GetSession()->SendPacket(&data);
+}
+
+void Player::AddRunePower(uint8 index)
+{
+ WorldPacket data(SMSG_ADD_RUNE_POWER, 4);
+ data << uint32(1 << index); // mask (0x00-0x3F probably)
+ GetSession()->SendPacket(&data);
+}
+
+void Player::InitRunes()
+{
+ if(getClass() != CLASS_DEATH_KNIGHT)
+ return;
+
+ m_runes = new Runes;
+
+ m_runes->runeState = 0;
+
+ for(uint32 i = 0; i < MAX_RUNES; ++i)
+ {
+ SetBaseRune(i, i / 2); // init base types
+ SetCurrentRune(i, i / 2); // init current types
+ SetRuneCooldown(i, 0); // reset cooldowns
+ m_runes->SetRuneState(i);
+ }
+
+ for(uint32 i = 0; i < NUM_RUNE_TYPES; ++i)
+ SetFloatValue(PLAYER_RUNE_REGEN_1 + i, 0.1f);
+}
+
+void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast)
+{
+ Loot loot;
+ loot.FillLoot (loot_id,store,this,true);
+
+ uint32 max_slot = loot.GetMaxSlotInLootFor(this);
+ for(uint32 i = 0; i < max_slot; ++i)
+ {
+ LootItem* lootItem = loot.LootItemInSlot(i,this);
+
+ ItemPosCountVec dest;
+ uint8 msg = CanStoreNewItem (bag,slot,dest,lootItem->itemid,lootItem->count);
+ if(msg != EQUIP_ERR_OK && slot != NULL_SLOT)
+ msg = CanStoreNewItem( bag, NULL_SLOT,dest,lootItem->itemid,lootItem->count);
+ if( msg != EQUIP_ERR_OK && bag != NULL_BAG)
+ msg = CanStoreNewItem( NULL_BAG, NULL_SLOT,dest,lootItem->itemid,lootItem->count);
+ if(msg != EQUIP_ERR_OK)
+ {
+ SendEquipError( msg, NULL, NULL );
+ continue;
+ }
+
+ Item* pItem = StoreNewItem (dest,lootItem->itemid,true,lootItem->randomPropertyId);
+ SendNewItem(pItem, lootItem->count, false, false, broadcast);
+ }
+}
+
+uint32 Player::CalculateTalentsPoints() const
+{
+ uint32 base_talent = getLevel() < 10 ? 0 : uint32((getLevel()-9)*sWorld.getRate(RATE_TALENT));
+
+ if(getClass() != CLASS_DEATH_KNIGHT)
+ return base_talent;
+
+ uint32 talentPointsForLevel =
+ (getLevel() < 56 ? 0 : uint32((getLevel()-55)*sWorld.getRate(RATE_TALENT)))
+ + m_questRewardTalentCount;
+
+ if(talentPointsForLevel > base_talent)
+ talentPointsForLevel = base_talent;
+
+ return talentPointsForLevel;
+}
+
+bool Player::IsAllowUseFlyMountsHere() const
+{
+ if (isGameMaster())
+ return true;
+
+ uint32 zoneId = GetZoneId();
+ uint32 v_map = GetVirtualMapForMapAndZone(GetMapId(), zoneId);
+ return v_map == 530 || v_map == 571 && HasSpell(54197) && zoneId != 4197;
+}
+
+void Player::learnSpellHighRank(uint32 spellid)
+{
+ learnSpell(spellid,false);
+
+ if(uint32 next = spellmgr.GetNextSpellInChain(spellid))
+ learnSpellHighRank(next);
+}
+
+void Player::_LoadSkills()
+{
+ // Note: skill data itself loaded from `data` field. This is only cleanup part of load
+
+ // reset skill modifiers and set correct unlearn flags
+ for (uint32 i = 0; i < PLAYER_MAX_SKILLS; i++)
+ {
+ SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i),0);
+
+ // set correct unlearn bit
+ uint32 id = GetUInt32Value(PLAYER_SKILL_INDEX(i)) & 0x0000FFFF;
+ if(!id) continue;
+
+ SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(id);
+ if(!pSkill) continue;
+
+ // enable unlearn button for primary professions only
+ if (pSkill->categoryId == SKILL_CATEGORY_PROFESSION)
+ SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,1));
+ else
+ SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id,0));
+
+ // set fixed skill ranges
+ switch(GetSkillRangeType(pSkill,false))
+ {
+ case SKILL_RANGE_LANGUAGE: // 300..300
+ SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(300,300));
+ break;
+ case SKILL_RANGE_MONO: // 1..1, grey monolite bar
+ SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(1,1));
+ break;
+ default:
+ break;
+ }
+
+ uint32 vskill = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i)));
+ learnSkillRewardedSpells(id, vskill);
+ }
+
+ // special settings
+ if(getClass()==CLASS_DEATH_KNIGHT)
+ {
+ uint32 base_level = std::min(getLevel(),sWorld.getConfig (CONFIG_START_HEROIC_PLAYER_LEVEL));
+ if(base_level < 1)
+ base_level = 1;
+ uint32 base_skill = (base_level-1)*5; // 270 at starting level 55
+ if(base_skill < 1)
+ base_skill = 1; // skill mast be known and then > 0 in any case
+
+ if(GetPureSkillValue (SKILL_FIRST_AID) < base_skill)
+ SetSkill(SKILL_FIRST_AID,base_skill, base_skill);
+ if(GetPureSkillValue (SKILL_AXES) < base_skill)
+ SetSkill(SKILL_AXES, base_skill,base_skill);
+ if(GetPureSkillValue (SKILL_DEFENSE) < base_skill)
+ SetSkill(SKILL_DEFENSE, base_skill,base_skill);
+ if(GetPureSkillValue (SKILL_POLEARMS) < base_skill)
+ SetSkill(SKILL_POLEARMS, base_skill,base_skill);
+ if(GetPureSkillValue (SKILL_SWORDS) < base_skill)
+ SetSkill(SKILL_SWORDS, base_skill,base_skill);
+ if(GetPureSkillValue (SKILL_2H_AXES) < base_skill)
+ SetSkill(SKILL_2H_AXES, base_skill,base_skill);
+ if(GetPureSkillValue (SKILL_2H_SWORDS) < base_skill)
+ SetSkill(SKILL_2H_SWORDS, base_skill,base_skill);
+ if(GetPureSkillValue (SKILL_UNARMED) < base_skill)
+ SetSkill(SKILL_UNARMED, base_skill,base_skill);
+ }
+}
+
+uint32 Player::GetPhaseMaskForSpawn() const
+{
+ uint32 phase = PHASEMASK_NORMAL;
+ if(!isGameMaster())
+ phase = GetPhaseMask();
+ else
+ {
+ AuraEffectList const& phases = GetAurasByType(SPELL_AURA_PHASE);
+ if(!phases.empty())
+ phase = phases.front()->GetMiscValue();
+ }
+
+ // some aura phases include 1 normal map in addition to phase itself
+ if(uint32 n_phase = phase & ~PHASEMASK_NORMAL)
+ return n_phase;
+
+ return PHASEMASK_NORMAL;
+}
+
+uint8 Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) const
+{
+ ItemPrototype const* pProto = pItem->GetProto();
+
+ // proto based limitations
+ if(uint8 res = CanEquipUniqueItem(pProto,eslot,limit_count))
+ return res;
+
+ // check unique-equipped on gems
+ for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
+ {
+ uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
+ if(!enchant_id)
+ continue;
+ SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
+ if(!enchantEntry)
+ continue;
+
+ ItemPrototype const* pGem = objmgr.GetItemPrototype(enchantEntry->GemID);
+ if(!pGem)
+ continue;
+
+ // include for check equip another gems with same limit category for not equipped item (and then not counted)
+ uint32 gem_limit_count = !pItem->IsEquipped() && pGem->ItemLimitCategory
+ ? pItem->GetGemCountWithLimitCategory(pGem->ItemLimitCategory) : 1;
+
+ if(uint8 res = CanEquipUniqueItem(pGem, eslot,gem_limit_count))
+ return res;
+ }
+
+ return EQUIP_ERR_OK;
+}
+
+uint8 Player::CanEquipUniqueItem( ItemPrototype const* itemProto, uint8 except_slot, uint32 limit_count) const
+{
+ // check unique-equipped on item
+ if (itemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
+ {
+ // there is an equip limit on this item
+ if(HasItemOrGemWithIdEquipped(itemProto->ItemId,1,except_slot))
+ return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
+ }
+
+ // check unique-equipped limit
+ if (itemProto->ItemLimitCategory)
+ {
+ ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(itemProto->ItemLimitCategory);
+ if(!limitEntry)
+ return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
+
+ if(limit_count > limitEntry->maxCount)
+ return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE; // attempt add too many limit category items (gems)
+
+ // there is an equip limit on this item
+ if(HasItemOrGemWithLimitCategoryEquipped(itemProto->ItemLimitCategory,limitEntry->maxCount-limit_count+1,except_slot))
+ return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE;
+ }
+
+ return EQUIP_ERR_OK;
+}
+
+void Player::HandleFall(MovementInfo const& movementInfo)
+{
+ // calculate total z distance of the fall
+ float z_diff = m_lastFallZ - movementInfo.z;
+ //sLog.outDebug("zDiff = %f", z_diff);
+
+ //Players with low fall distance, Feather Fall or physical immunity (charges used) are ignored
+ // 14.57 can be calculated by resolving damageperc formula below to 0
+ if (z_diff >= 14.57f && !isDead() && !isGameMaster() &&
+ !HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) &&
+ !HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL) )
+ {
+ //Safe fall, fall height reduction
+ int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
+
+ float damageperc = 0.018f*(z_diff-safe_fall)-0.2426f;
+
+ if(damageperc >0 )
+ {
+ uint32 damage = (uint32)(damageperc * GetMaxHealth()*sWorld.getRate(RATE_DAMAGE_FALL));
+
+ float height = movementInfo.z;
+ UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
+
+ if (damage > 0)
+ {
+ //Prevent fall damage from being more than the player maximum health
+ if (damage > GetMaxHealth())
+ damage = GetMaxHealth();
+
+ // Gust of Wind
+ if (GetDummyAura(43621))
+ damage = GetMaxHealth()/2;
+
+ EnvironmentalDamage(DAMAGE_FALL, damage);
+
+ // recheck alive, might have died of EnvironmentalDamage
+ if (isAlive())
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING, uint32(z_diff*100));
+ }
+
+ //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
+ DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
+ }
+ }
+}
+
+void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 miscvalue1/*=0*/, uint32 miscvalue2/*=0*/, Unit *unit/*=NULL*/, uint32 time/*=0*/ )
+{
+ GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1,miscvalue2,unit,time);
+}
+
+void Player::LearnTalent(uint32 talentId, uint32 talentRank)
+{
+ uint32 CurTalentPoints = GetFreeTalentPoints();
+
+ if(CurTalentPoints == 0)
+ return;
+
+ if (talentRank >= MAX_TALENT_RANK)
+ return;
+
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentId );
+
+ if(!talentInfo)
+ return;
+
+ TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
+
+ if(!talentTabInfo)
+ return;
+
+ // prevent learn talent for different class (cheating)
+ if( (getClassMask() & talentTabInfo->ClassMask) == 0 )
+ return;
+
+ // find current max talent rank
+ int32 curtalent_maxrank = 0;
+ for(int32 k = MAX_TALENT_RANK-1; k > -1; --k)
+ {
+ if(talentInfo->RankID[k] && HasSpell(talentInfo->RankID[k]))
+ {
+ curtalent_maxrank = k + 1;
+ break;
+ }
+ }
+
+ // we already have same or higher talent rank learned
+ if(curtalent_maxrank >= (talentRank + 1))
+ return;
+
+ // check if we have enough talent points
+ if(CurTalentPoints < (talentRank - curtalent_maxrank + 1))
+ return;
+
+ // Check if it requires another talent
+ if (talentInfo->DependsOn > 0)
+ {
+ if(TalentEntry const *depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
+ {
+ bool hasEnoughRank = false;
+ for (int i = talentInfo->DependsOnRank; i < MAX_TALENT_RANK; i++)
+ {
+ if (depTalentInfo->RankID[i] != 0)
+ if (HasSpell(depTalentInfo->RankID[i]))
+ hasEnoughRank = true;
+ }
+ if (!hasEnoughRank)
+ return;
+ }
+ }
+
+ // Find out how many points we have in this field
+ uint32 spentPoints = 0;
+
+ uint32 tTab = talentInfo->TalentTab;
+ if (talentInfo->Row > 0)
+ {
+ unsigned int numRows = sTalentStore.GetNumRows();
+ for (unsigned int i = 0; i < numRows; i++) // Loop through all talents.
+ {
+ // Someday, someone needs to revamp
+ const TalentEntry *tmpTalent = sTalentStore.LookupEntry(i);
+ if (tmpTalent) // the way talents are tracked
+ {
+ if (tmpTalent->TalentTab == tTab)
+ {
+ for (int j = 0; j < MAX_TALENT_RANK; j++)
+ {
+ if (tmpTalent->RankID[j] != 0)
+ {
+ if (HasSpell(tmpTalent->RankID[j]))
+ {
+ spentPoints += j + 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // not have required min points spent in talent tree
+ if(spentPoints < (talentInfo->Row * MAX_TALENT_RANK))
+ return;
+
+ // spell not set in talent.dbc
+ uint32 spellid = talentInfo->RankID[talentRank];
+ if( spellid == 0 )
+ {
+ sLog.outError("Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank);
+ return;
+ }
+
+ // already known
+ if(HasSpell(spellid))
+ return;
+
+ // learn! (other talent ranks will unlearned at learning)
+ learnSpell(spellid, false);
+ sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
+
+ // update free talent points
+ SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
+}
+
+void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank)
+{
+ Pet *pet = GetPet();
+
+ if(!pet)
+ return;
+
+ if(petGuid != pet->GetGUID())
+ return;
+
+ uint32 CurTalentPoints = pet->GetFreeTalentPoints();
+
+ if(CurTalentPoints == 0)
+ return;
+
+ if (talentRank >= MAX_PET_TALENT_RANK)
+ return;
+
+ TalentEntry const *talentInfo = sTalentStore.LookupEntry(talentId);
+
+ if(!talentInfo)
+ return;
+
+ TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
+
+ if(!talentTabInfo)
+ return;
+
+ CreatureInfo const *ci = pet->GetCreatureInfo();
+
+ if(!ci)
+ return;
+
+ CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
+
+ if(!pet_family)
+ return;
+
+ if(pet_family->petTalentType < 0) // not hunter pet
+ return;
+
+ // prevent learn talent for different family (cheating)
+ if(!((1 << pet_family->petTalentType) & talentTabInfo->petTalentMask))
+ return;
+
+ // find current max talent rank
+ int32 curtalent_maxrank = 0;
+ for(int32 k = MAX_TALENT_RANK-1; k > -1; --k)
+ {
+ if(talentInfo->RankID[k] && pet->HasSpell(talentInfo->RankID[k]))
+ {
+ curtalent_maxrank = k + 1;
+ break;
+ }
+ }
+
+ // we already have same or higher talent rank learned
+ if(curtalent_maxrank >= (talentRank + 1))
+ return;
+
+ // check if we have enough talent points
+ if(CurTalentPoints < (talentRank - curtalent_maxrank + 1))
+ return;
+
+ // Check if it requires another talent
+ if (talentInfo->DependsOn > 0)
+ {
+ if(TalentEntry const *depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
+ {
+ bool hasEnoughRank = false;
+ for (int i = talentInfo->DependsOnRank; i < MAX_TALENT_RANK; i++)
+ {
+ if (depTalentInfo->RankID[i] != 0)
+ if (pet->HasSpell(depTalentInfo->RankID[i]))
+ hasEnoughRank = true;
+ }
+ if (!hasEnoughRank)
+ return;
+ }
+ }
+
+ // Find out how many points we have in this field
+ uint32 spentPoints = 0;
+
+ uint32 tTab = talentInfo->TalentTab;
+ if (talentInfo->Row > 0)
+ {
+ unsigned int numRows = sTalentStore.GetNumRows();
+ for (unsigned int i = 0; i < numRows; ++i) // Loop through all talents.
+ {
+ // Someday, someone needs to revamp
+ const TalentEntry *tmpTalent = sTalentStore.LookupEntry(i);
+ if (tmpTalent) // the way talents are tracked
+ {
+ if (tmpTalent->TalentTab == tTab)
+ {
+ for (int j = 0; j < MAX_TALENT_RANK; j++)
+ {
+ if (tmpTalent->RankID[j] != 0)
+ {
+ if (pet->HasSpell(tmpTalent->RankID[j]))
+ {
+ spentPoints += j + 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // not have required min points spent in talent tree
+ if(spentPoints < (talentInfo->Row * MAX_PET_TALENT_RANK))
+ return;
+
+ // spell not set in talent.dbc
+ uint32 spellid = talentInfo->RankID[talentRank];
+ if( spellid == 0 )
+ {
+ sLog.outError("Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank);
+ return;
+ }
+
+ // already known
+ if(pet->HasSpell(spellid))
+ return;
+
+ // learn! (other talent ranks will unlearned at learning)
+ pet->learnSpell(spellid);
+ sLog.outDetail("PetTalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
+
+ // update free talent points
+ pet->SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
+}
+
+void Player::UpdateKnownCurrencies(uint32 itemId, bool apply)
+{
+ if(CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemId))
+ {
+ if(apply)
+ SetFlag64(PLAYER_FIELD_KNOWN_CURRENCIES,(1LL << (ctEntry->BitIndex-1)));
+ else
+ RemoveFlag64(PLAYER_FIELD_KNOWN_CURRENCIES,(1LL << (ctEntry->BitIndex-1)));
+ }
+}
+
+void Player::UpdateFallInformationIfNeed( MovementInfo const& minfo,uint16 opcode )
+{
+ if (m_lastFallTime >= minfo.fallTime || m_lastFallZ <=minfo.z || opcode == MSG_MOVE_FALL_LAND)
+ SetFallInformation(minfo.fallTime, minfo.z);
+}
+
+void Player::UnsummonPetTemporaryIfAny()
+{
+ Pet* pet = GetPet();
+ if(!pet)
+ return;
+
+ if(!m_temporaryUnsummonedPetNumber && pet->isControlled() && !pet->isTemporarySummoned() )
+ {
+ m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber();
+ m_oldpetspell = pet->GetUInt32Value(UNIT_CREATED_BY_SPELL);
+ }
+
+ RemovePet(pet, PET_SAVE_AS_CURRENT);
+}
+
+void Player::ResummonPetTemporaryUnSummonedIfAny()
+{
+ if(!m_temporaryUnsummonedPetNumber)
+ return;
+
+ // not resummon in not appropriate state
+ if(IsPetNeedBeTemporaryUnsummoned())
+ return;
+
+ if(GetPetGUID())
+ return;
+
+ Pet* NewPet = new Pet(this);
+ if(!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true))
+ delete NewPet;
+
+ m_temporaryUnsummonedPetNumber = 0;
+}
+
+bool Player::canSeeSpellClickOn(Creature const *c) const
+{
+ SpellClickInfoMap::const_iterator lower = objmgr.mSpellClickInfoMap.lower_bound(c->GetEntry());
+ SpellClickInfoMap::const_iterator upper = objmgr.mSpellClickInfoMap.upper_bound(c->GetEntry());
+ if(lower == upper)
+ return true;
+
+ for(SpellClickInfoMap::const_iterator itr = lower; itr != upper; ++itr)
+ {
+ if(itr->second.questId == 0 || GetQuestStatus(itr->second.questId) == itr->second.questStatus)
+ return true;
+ }
+ return false;
+}
diff --git a/src/game/Player.h b/src/game/Player.h
index 27e088f5131..aee7cd14991 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +35,9 @@
#include "Pet.h"
#include "MapReference.h"
#include "Util.h" // for Tokens typedef
+#include "AchievementMgr.h"
+#include "ReputationMgr.h"
+#include "BattleGround.h"
#include<string>
#include<vector>
@@ -45,8 +48,8 @@ class DynamicObject;
class Creature;
class Pet;
class PlayerMenu;
-class Transport;
class UpdateMask;
+class SpellCastTargets;
class PlayerSocial;
class OutdoorPvP;
@@ -54,6 +57,7 @@ typedef std::deque<Mail*> PlayerMails;
#define PLAYER_MAX_SKILLS 127
#define PLAYER_MAX_DAILY_QUESTS 25
+#define AT_LOAD_PET_FLAGS 16
// Note: SPELLMOD_* values is aura types in fact
enum SpellModType
@@ -62,6 +66,18 @@ enum SpellModType
SPELLMOD_PCT = 108 // SPELL_AURA_ADD_PCT_MODIFIER
};
+// 2^n values, Player::m_isunderwater is a bitmask. These are mangos internal values, they are never send to any client
+enum PlayerUnderwaterState
+{
+ UNDERWATER_NONE = 0x00,
+ UNDERWATER_INWATER = 0x01, // terrain type is water and player is afflicted by it
+ UNDERWATER_INLAVA = 0x02, // terrain type is lava and player is afflicted by it
+ UNDERWATER_INSLIME = 0x04, // terrain type is lava and player is afflicted by it
+ UNDERWARER_INDARKWATER = 0x08, // terrain type is dark water and player is afflicted by it
+
+ UNDERWATER_EXIST_TIMERS = 0x10
+};
+
enum PlayerSpellState
{
PLAYERSPELL_UNCHANGED = 0,
@@ -72,27 +88,26 @@ enum PlayerSpellState
struct PlayerSpell
{
- uint16 slotId : 16;
PlayerSpellState state : 8;
- bool active : 1;
- bool disabled : 1;
+ bool active : 1; // show in spellbook
+ bool dependent : 1; // learned as result another spell learn, skill grow, quest reward, etc
+ bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks
};
-#define SPELL_WITHOUT_SLOT_ID uint16(-1)
-
+// Spell modifier (used for modify other spells)
struct SpellModifier
{
+ SpellModifier() : charges(0), lastAffected(NULL) {}
SpellModOp op : 8;
SpellModType type : 8;
int16 charges : 16;
int32 value;
- uint64 mask;
+ flag96 mask;
uint32 spellId;
- uint32 effectId;
Spell const* lastAffected;
};
-typedef UNORDERED_MAP<uint16, PlayerSpell*> PlayerSpellMap;
+typedef UNORDERED_MAP<uint32, PlayerSpell*> PlayerSpellMap;
typedef std::list<SpellModifier*> SpellModList;
struct SpellCooldown
@@ -107,7 +122,8 @@ enum TrainerSpellState
{
TRAINER_SPELL_GREEN = 0,
TRAINER_SPELL_RED = 1,
- TRAINER_SPELL_GRAY = 2
+ TRAINER_SPELL_GRAY = 2,
+ TRAINER_SPELL_GREEN_DISABLED = 10 // custom value, not send to client: formally green but learn not allowed
};
enum ActionButtonUpdateState
@@ -141,8 +157,6 @@ enum ActionButtonType
typedef std::map<uint8,ActionButton> ActionButtonList;
-typedef std::pair<uint16, uint8> CreateSpellPair;
-
struct PlayerCreateInfoItem
{
PlayerCreateInfoItem(uint32 id, uint32 amount) : item_id(id), item_amount(amount) {}
@@ -174,6 +188,8 @@ struct PlayerLevelInfo
uint8 stats[MAX_STATS];
};
+typedef std::list<uint32> PlayerCreateInfoSpells;
+
struct PlayerInfo
{
// existence checked by displayId != 0 // existence checked by displayId != 0
@@ -189,7 +205,7 @@ struct PlayerInfo
uint16 displayId_m;
uint16 displayId_f;
PlayerCreateInfoItems item;
- std::list<CreateSpellPair> spell;
+ PlayerCreateInfoSpells spell;
std::list<uint16> action[4];
PlayerLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1
@@ -197,9 +213,11 @@ struct PlayerInfo
struct PvPInfo
{
- PvPInfo() : inHostileArea(false), endTimer(0) {}
+ PvPInfo() : inHostileArea(false), inNoPvPArea(false), inFFAPvPArea(false), endTimer(0) {}
bool inHostileArea;
+ bool inNoPvPArea;
+ bool inFFAPvPArea;
time_t endTimer;
};
@@ -224,37 +242,44 @@ struct Areas
float y2;
};
-enum FactionFlags
+#define MAX_RUNES 6
+#define RUNE_COOLDOWN 5 // 5*2=10 sec
+
+enum RuneType
{
- FACTION_FLAG_VISIBLE = 0x01, // makes visible in client (set or can be set at interaction with target of this faction)
- FACTION_FLAG_AT_WAR = 0x02, // enable AtWar-button in client. player controlled (except opposition team always war state), Flag only set on initial creation
- FACTION_FLAG_HIDDEN = 0x04, // hidden faction from reputation pane in client (player can gain reputation, but this update not sent to client)
- FACTION_FLAG_INVISIBLE_FORCED = 0x08, // always overwrite FACTION_FLAG_VISIBLE and hide faction in rep.list, used for hide opposite team factions
- FACTION_FLAG_PEACE_FORCED = 0x10, // always overwrite FACTION_FLAG_AT_WAR, used for prevent war with own team factions
- FACTION_FLAG_INACTIVE = 0x20, // player controlled, state stored in characters.data ( CMSG_SET_FACTION_INACTIVE )
- FACTION_FLAG_RIVAL = 0x40 // flag for the two competing outland factions
+ RUNE_BLOOD = 0,
+ RUNE_UNHOLY = 1,
+ RUNE_FROST = 2,
+ RUNE_DEATH = 3,
+ NUM_RUNE_TYPES = 4
};
-typedef uint32 RepListID;
-struct FactionState
+struct RuneInfo
{
- uint32 ID;
- RepListID ReputationListID;
- uint32 Flags;
- int32 Standing;
- bool Changed;
+ uint8 BaseRune;
+ uint8 CurrentRune;
+ uint8 Cooldown;
};
-typedef std::map<RepListID,FactionState> FactionStateList;
-
-typedef std::map<uint32,ReputationRank> ForcedReactions;
+struct Runes
+{
+ RuneInfo runes[MAX_RUNES];
+ uint8 runeState; // mask of available runes
-typedef std::set<uint64> GuardianPetList;
+ void SetRuneState(uint8 index, bool set = true)
+ {
+ if(set)
+ runeState |= (1 << index); // usable
+ else
+ runeState &= ~(1 << index); // on cooldown
+ }
+};
struct EnchantDuration
{
EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) {};
- EnchantDuration(Item * _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot), leftduration(_leftduration) { assert(item); };
+ EnchantDuration(Item * _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot),
+ leftduration(_leftduration){ assert(item); };
Item * item;
EnchantmentSlot slot;
@@ -328,52 +353,6 @@ enum DrunkenState
DRUNKEN_SMASHED = 3
};
-enum PlayerStateType
-{
- /*
- PLAYER_STATE_DANCE
- PLAYER_STATE_SLEEP
- PLAYER_STATE_SIT
- PLAYER_STATE_STAND
- PLAYER_STATE_READYUNARMED
- PLAYER_STATE_WORK
- PLAYER_STATE_POINT(DNR)
- PLAYER_STATE_NONE // not used or just no state, just standing there?
- PLAYER_STATE_STUN
- PLAYER_STATE_DEAD
- PLAYER_STATE_KNEEL
- PLAYER_STATE_USESTANDING
- PLAYER_STATE_STUN_NOSHEATHE
- PLAYER_STATE_USESTANDING_NOSHEATHE
- PLAYER_STATE_WORK_NOSHEATHE
- PLAYER_STATE_SPELLPRECAST
- PLAYER_STATE_READYRIFLE
- PLAYER_STATE_WORK_NOSHEATHE_MINING
- PLAYER_STATE_WORK_NOSHEATHE_CHOPWOOD
- PLAYER_STATE_AT_EASE
- PLAYER_STATE_READY1H
- PLAYER_STATE_SPELLKNEELSTART
- PLAYER_STATE_SUBMERGED
- */
-
- PLAYER_STATE_NONE = 0,
- PLAYER_STATE_SIT = 1,
- PLAYER_STATE_SIT_CHAIR = 2,
- PLAYER_STATE_SLEEP = 3,
- PLAYER_STATE_SIT_LOW_CHAIR = 4,
- PLAYER_STATE_SIT_MEDIUM_CHAIR = 5,
- PLAYER_STATE_SIT_HIGH_CHAIR = 6,
- PLAYER_STATE_DEAD = 7,
- PLAYER_STATE_KNEEL = 8,
-
- PLAYER_STATE_FORM_ALL = 0x00FF0000,
-
- PLAYER_STATE_FLAG_ALWAYS_STAND = 0x01, // byte 4
- PLAYER_STATE_FLAG_CREEP = 0x02000000,
- PLAYER_STATE_FLAG_UNTRACKABLE = 0x04000000,
- PLAYER_STATE_FLAG_ALL = 0xFF000000,
-};
-
enum PlayerFlags
{
PLAYER_FLAGS_GROUP_LEADER = 0x00000001,
@@ -382,17 +361,25 @@ enum PlayerFlags
PLAYER_FLAGS_GM = 0x00000008,
PLAYER_FLAGS_GHOST = 0x00000010,
PLAYER_FLAGS_RESTING = 0x00000020,
- PLAYER_FLAGS_FFA_PVP = 0x00000080,
+ PLAYER_FLAGS_UNK7 = 0x00000040,
+ PLAYER_FLAGS_UNK8 = 0x00000080, // pre-3.0.3 PLAYER_FLAGS_FFA_PVP flag for FFA PVP state
PLAYER_FLAGS_CONTESTED_PVP = 0x00000100, // Player has been involved in a PvP combat and will be attacked by contested guards
PLAYER_FLAGS_IN_PVP = 0x00000200,
PLAYER_FLAGS_HIDE_HELM = 0x00000400,
PLAYER_FLAGS_HIDE_CLOAK = 0x00000800,
- PLAYER_FLAGS_UNK1 = 0x00001000, // played long time
- PLAYER_FLAGS_UNK2 = 0x00002000, // played too long time
- PLAYER_FLAGS_UNK3 = 0x00008000, // strange visual effect (2.0.1), looks like PLAYER_FLAGS_GHOST flag
- PLAYER_FLAGS_SANCTUARY = 0x00010000, // player entered sanctuary
- PLAYER_FLAGS_UNK4 = 0x00020000, // taxi benchmark mode (on/off) (2.0.1)
- PLAYER_UNK = 0x00040000, // 2.0.8...
+ PLAYER_FLAGS_UNK13 = 0x00001000, // played long time
+ PLAYER_FLAGS_UNK14 = 0x00002000, // played too long time
+ PLAYER_FLAGS_UNK15 = 0x00004000,
+ PLAYER_FLAGS_UNK16 = 0x00008000, // strange visual effect (2.0.1), looks like PLAYER_FLAGS_GHOST flag
+ PLAYER_FLAGS_UNK17 = 0x00010000, // pre-3.0.3 PLAYER_FLAGS_SANCTUARY flag for player entered sanctuary
+ PLAYER_FLAGS_UNK18 = 0x00020000, // taxi benchmark mode (on/off) (2.0.1)
+ PLAYER_FLAGS_PVP_TIMER = 0x00040000, // 3.0.2, pvp timer active (after you disable pvp manually)
+ PLAYER_FLAGS_UNK20 = 0x00080000,
+ PLAYER_FLAGS_UNK21 = 0x00100000,
+ PLAYER_FLAGS_UNK22 = 0x00200000,
+ PLAYER_FLAGS_UNK23 = 0x00400000,
+ PLAYER_ALLOW_ONLY_ABILITY = 0x00800000, // used by bladestorm and killing spree
+ PLAYER_FLAGS_UNK25 = 0x01000000 // disabled all melee ability on tab include autoattack
};
// used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1<<bit_index) without (-1)
@@ -472,17 +459,7 @@ enum ActivateTaxiReplies
ERR_TAXINOTSTANDING = 12
};
-enum LootType
-{
- LOOT_CORPSE = 1,
- LOOT_SKINNING = 2,
- LOOT_FISHING = 3,
- LOOT_PICKPOCKETING = 4, // unsupported by client, sending LOOT_SKINNING instead
- LOOT_DISENCHANTING = 5, // unsupported by client, sending LOOT_SKINNING instead
- LOOT_PROSPECTING = 6, // unsupported by client, sending LOOT_SKINNING instead
- LOOT_INSIGNIA = 7, // unsupported by client, sending LOOT_SKINNING instead
- LOOT_FISHINGHOLE = 8 // unsupported by client, sending LOOT_FISHING instead
-};
+
enum MirrorTimerType
{
@@ -490,6 +467,8 @@ enum MirrorTimerType
BREATH_TIMER = 1,
FIRE_TIMER = 2
};
+#define MAX_TIMERS 3
+#define DISABLED_MIRROR_TIMER -1
// 2^n values
enum PlayerExtraFlags
@@ -511,7 +490,8 @@ enum AtLoginFlags
AT_LOGIN_NONE = 0,
AT_LOGIN_RENAME = 1,
AT_LOGIN_RESET_SPELLS = 2,
- AT_LOGIN_RESET_TALENTS = 4
+ AT_LOGIN_RESET_TALENTS = 4,
+ AT_LOGIN_CUSTOMIZE = 8,
};
typedef std::map<uint32, QuestStatusData> QuestStatusMap;
@@ -543,11 +523,13 @@ enum PlayerSlots
// first slot for item stored (in any way in player m_items data)
PLAYER_SLOT_START = 0,
// last+1 slot for item stored (in any way in player m_items data)
- PLAYER_SLOT_END = 118,
+ PLAYER_SLOT_END = 200,
PLAYER_SLOTS_COUNT = (PLAYER_SLOT_END - PLAYER_SLOT_START)
};
-enum EquipmentSlots
+#define INVENTORY_SLOT_BAG_0 255
+
+enum EquipmentSlots // 19 slots
{
EQUIPMENT_SLOT_START = 0,
EQUIPMENT_SLOT_HEAD = 0,
@@ -572,111 +554,67 @@ enum EquipmentSlots
EQUIPMENT_SLOT_END = 19
};
-enum InventorySlots
+enum InventorySlots // 4 slots
{
- INVENTORY_SLOT_BAG_0 = 255,
INVENTORY_SLOT_BAG_START = 19,
- INVENTORY_SLOT_BAG_1 = 19,
- INVENTORY_SLOT_BAG_2 = 20,
- INVENTORY_SLOT_BAG_3 = 21,
- INVENTORY_SLOT_BAG_4 = 22,
- INVENTORY_SLOT_BAG_END = 23,
+ INVENTORY_SLOT_BAG_END = 23
+};
+enum InventoryPackSlots // 16 slots
+{
INVENTORY_SLOT_ITEM_START = 23,
- INVENTORY_SLOT_ITEM_1 = 23,
- INVENTORY_SLOT_ITEM_2 = 24,
- INVENTORY_SLOT_ITEM_3 = 25,
- INVENTORY_SLOT_ITEM_4 = 26,
- INVENTORY_SLOT_ITEM_5 = 27,
- INVENTORY_SLOT_ITEM_6 = 28,
- INVENTORY_SLOT_ITEM_7 = 29,
- INVENTORY_SLOT_ITEM_8 = 30,
- INVENTORY_SLOT_ITEM_9 = 31,
- INVENTORY_SLOT_ITEM_10 = 32,
- INVENTORY_SLOT_ITEM_11 = 33,
- INVENTORY_SLOT_ITEM_12 = 34,
- INVENTORY_SLOT_ITEM_13 = 35,
- INVENTORY_SLOT_ITEM_14 = 36,
- INVENTORY_SLOT_ITEM_15 = 37,
- INVENTORY_SLOT_ITEM_16 = 38,
INVENTORY_SLOT_ITEM_END = 39
};
-enum BankSlots
+enum BankItemSlots // 28 slots
{
BANK_SLOT_ITEM_START = 39,
- BANK_SLOT_ITEM_1 = 39,
- BANK_SLOT_ITEM_2 = 40,
- BANK_SLOT_ITEM_3 = 41,
- BANK_SLOT_ITEM_4 = 42,
- BANK_SLOT_ITEM_5 = 43,
- BANK_SLOT_ITEM_6 = 44,
- BANK_SLOT_ITEM_7 = 45,
- BANK_SLOT_ITEM_8 = 46,
- BANK_SLOT_ITEM_9 = 47,
- BANK_SLOT_ITEM_10 = 48,
- BANK_SLOT_ITEM_11 = 49,
- BANK_SLOT_ITEM_12 = 50,
- BANK_SLOT_ITEM_13 = 51,
- BANK_SLOT_ITEM_14 = 52,
- BANK_SLOT_ITEM_15 = 53,
- BANK_SLOT_ITEM_16 = 54,
- BANK_SLOT_ITEM_17 = 55,
- BANK_SLOT_ITEM_18 = 56,
- BANK_SLOT_ITEM_19 = 57,
- BANK_SLOT_ITEM_20 = 58,
- BANK_SLOT_ITEM_21 = 59,
- BANK_SLOT_ITEM_22 = 60,
- BANK_SLOT_ITEM_23 = 61,
- BANK_SLOT_ITEM_24 = 62,
- BANK_SLOT_ITEM_25 = 63,
- BANK_SLOT_ITEM_26 = 64,
- BANK_SLOT_ITEM_27 = 65,
- BANK_SLOT_ITEM_28 = 66,
- BANK_SLOT_ITEM_END = 67,
+ BANK_SLOT_ITEM_END = 67
+};
+enum BankBagSlots // 7 slots
+{
BANK_SLOT_BAG_START = 67,
- BANK_SLOT_BAG_1 = 67,
- BANK_SLOT_BAG_2 = 68,
- BANK_SLOT_BAG_3 = 69,
- BANK_SLOT_BAG_4 = 70,
- BANK_SLOT_BAG_5 = 71,
- BANK_SLOT_BAG_6 = 72,
- BANK_SLOT_BAG_7 = 73,
BANK_SLOT_BAG_END = 74
};
-enum BuyBackSlots
+enum BuyBackSlots // 12 slots
{
// stored in m_buybackitems
BUYBACK_SLOT_START = 74,
- BUYBACK_SLOT_1 = 74,
- BUYBACK_SLOT_2 = 75,
- BUYBACK_SLOT_3 = 76,
- BUYBACK_SLOT_4 = 77,
- BUYBACK_SLOT_5 = 78,
- BUYBACK_SLOT_6 = 79,
- BUYBACK_SLOT_7 = 80,
- BUYBACK_SLOT_8 = 81,
- BUYBACK_SLOT_9 = 82,
- BUYBACK_SLOT_10 = 83,
- BUYBACK_SLOT_11 = 84,
- BUYBACK_SLOT_12 = 85,
BUYBACK_SLOT_END = 86
};
-enum KeyRingSlots
+enum KeyRingSlots // 32 slots
{
KEYRING_SLOT_START = 86,
KEYRING_SLOT_END = 118
};
+enum VanityPetSlots // 18 slots
+{
+ VANITYPET_SLOT_START = 118, // not use, vanity pets stored as spells
+ VANITYPET_SLOT_END = 136 // not allowed any content in.
+};
+
+enum CurrencyTokenSlots // 32 slots
+{
+ CURRENCYTOKEN_SLOT_START = 136,
+ CURRENCYTOKEN_SLOT_END = 168
+};
+
+enum QuestBagSlots // 32 slots
+{
+ QUESTBAG_SLOT_START = 168, // not use
+ QUESTBAG_SLOT_END = 200 // not allowed any content in.
+};
+
struct ItemPosCount
{
- ItemPosCount(uint16 _pos, uint8 _count) : pos(_pos), count(_count) {}
+ ItemPosCount(uint16 _pos, uint32 _count) : pos(_pos), count(_count) {}
bool isContainedIn(std::vector<ItemPosCount> const& vec) const;
uint16 pos;
- uint8 count;
+ uint32 count;
};
typedef std::vector<ItemPosCount> ItemPosCountVec;
@@ -689,14 +627,15 @@ enum TradeSlots
enum TransferAbortReason
{
- TRANSFER_ABORT_MAX_PLAYERS = 0x0001, // Transfer Aborted: instance is full
- TRANSFER_ABORT_NOT_FOUND = 0x0002, // Transfer Aborted: instance not found
- TRANSFER_ABORT_TOO_MANY_INSTANCES = 0x0003, // You have entered too many instances recently.
- TRANSFER_ABORT_ZONE_IN_COMBAT = 0x0005, // Unable to zone in while an encounter is in progress.
- TRANSFER_ABORT_INSUF_EXPAN_LVL1 = 0x0106, // You must have TBC expansion installed to access this area.
- TRANSFER_ABORT_DIFFICULTY1 = 0x0007, // Normal difficulty mode is not available for %s.
- TRANSFER_ABORT_DIFFICULTY2 = 0x0107, // Heroic difficulty mode is not available for %s.
- TRANSFER_ABORT_DIFFICULTY3 = 0x0207 // Epic difficulty mode is not available for %s.
+ TRANSFER_ABORT_ERROR = 0x00,
+ TRANSFER_ABORT_MAX_PLAYERS = 0x01, // Transfer Aborted: instance is full
+ TRANSFER_ABORT_NOT_FOUND = 0x02, // Transfer Aborted: instance not found
+ TRANSFER_ABORT_TOO_MANY_INSTANCES = 0x03, // You have entered too many instances recently.
+ TRANSFER_ABORT_ZONE_IN_COMBAT = 0x05, // Unable to zone in while an encounter is in progress.
+ TRANSFER_ABORT_INSUF_EXPAN_LVL = 0x06, // You must have <TBC,WotLK> expansion installed to access this area.
+ TRANSFER_ABORT_DIFFICULTY = 0x07, // <Normal,Heroic,Epic> difficulty mode is not available for %s.
+ TRANSFER_ABORT_UNIQUE_MESSAGE = 0x08, // Until you've escaped TLK's grasp, you cannot leave this place!
+ TRANSFER_ABORT_TOO_MANY_REALM_INSTANCES = 0x09 // Additional instances cannot be launched, please try again later.
};
enum InstanceResetWarningType
@@ -707,41 +646,6 @@ enum InstanceResetWarningType
RAID_INSTANCE_WELCOME = 4 // Welcome to %s. This raid instance is scheduled to reset in %s.
};
-struct MovementInfo
-{
- // common
- //uint32 flags;
- uint8 unk1;
- uint32 time;
- float x, y, z, o;
- // transport
- uint64 t_guid;
- float t_x, t_y, t_z, t_o;
- uint32 t_time;
- // swimming and unk
- float s_pitch;
- // last fall time
- uint32 fallTime;
- // jumping
- float j_unk, j_sinAngle, j_cosAngle, j_xyspeed;
- // spline
- float u_unk1;
-
- MovementInfo()
- {
- //flags =
- time = t_time = fallTime = 0;
- unk1 = 0;
- x = y = z = o = t_x = t_y = t_z = t_o = s_pitch = j_unk = j_sinAngle = j_cosAngle = j_xyspeed = u_unk1 = 0.0f;
- t_guid = 0;
- }
-
- /*void SetMovementFlags(uint32 _flags)
- {
- flags = _flags;
- }*/
-};
-
// flags that use in movement check for example at spell casting
MovementFlags const movementFlagsMask = MovementFlags(
MOVEMENTFLAG_FORWARD |MOVEMENTFLAG_BACKWARD |MOVEMENTFLAG_STRAFE_LEFT|MOVEMENTFLAG_STRAFE_RIGHT|
@@ -812,8 +716,9 @@ enum PlayerLoginQueryIndex
PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES = 16,
PLAYER_LOGIN_QUERY_LOADGUILD = 17,
PLAYER_LOGIN_QUERY_LOADARENAINFO = 18,
-
- MAX_PLAYER_LOGIN_QUERY
+ PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS = 19,
+ PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS = 20,
+ MAX_PLAYER_LOGIN_QUERY = 21
};
// Player summoning auto-decline time (in secs)
@@ -842,7 +747,7 @@ struct AccessRequirement
std::string questFailedText;
uint32 heroicQuest;
std::string heroicQuestFailedText;
- };
+};
class TRINITY_DLL_SPEC PlayerTaxi
{
@@ -850,11 +755,9 @@ class TRINITY_DLL_SPEC PlayerTaxi
PlayerTaxi();
~PlayerTaxi() {}
// Nodes
- void InitTaxiNodesForLevel(uint32 race, uint32 level);
+ void InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint32 level);
void LoadTaxiMask(const char* data);
- void SaveTaxiMask(const char* data);
- uint32 GetTaximask( uint8 index ) const { return m_taximask[index]; }
bool IsTaximaskNodeKnown(uint32 nodeidx) const
{
uint8 field = uint8((nodeidx - 1) / 32);
@@ -876,7 +779,7 @@ class TRINITY_DLL_SPEC PlayerTaxi
void AppendTaximaskTo(ByteBuffer& data,bool all);
// Destinations
- bool LoadTaxiDestinationsFromString(const std::string& values);
+ bool LoadTaxiDestinationsFromString(const std::string& values, uint32 team);
std::string SaveTaxiDestinationsToString();
void ClearTaxiDestinations() { m_TaxiDestinations.clear(); }
@@ -890,11 +793,15 @@ class TRINITY_DLL_SPEC PlayerTaxi
return GetTaxiDestination();
}
bool empty() const { return m_TaxiDestinations.empty(); }
+
+ friend std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi);
private:
TaxiMask m_taximask;
std::deque<uint32> m_TaxiDestinations;
};
+std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi);
+
class TRINITY_DLL_SPEC Player : public Unit
{
friend class WorldSession;
@@ -912,16 +819,6 @@ class TRINITY_DLL_SPEC Player : public Unit
void AddToWorld();
void RemoveFromWorld();
- void SetViewport(uint64 guid, bool movable);
- void StopCastingCharm() { Uncharm(); }
- void StopCastingBindSight();
- WorldObject* GetFarsightTarget() const;
- void ClearFarsight();
- void SetFarsightTarget(WorldObject* target);
- // Controls if vision is currently on farsight object, updated in FAR_SIGHT opcode
- void SetFarsightVision(bool apply) { m_farsightVision = apply; }
- bool HasFarsightVision() const { return m_farsightVision; }
-
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0);
bool TeleportTo(WorldLocation const &loc, uint32 options = 0)
@@ -952,10 +849,12 @@ class TRINITY_DLL_SPEC Player : public Unit
void SendInitialPacketsBeforeAddToMap();
void SendInitialPacketsAfterAddToMap();
- void SendTransferAborted(uint32 mapid, uint16 reason);
+ void SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg = 0);
void SendInstanceResetWarning(uint32 mapid, uint32 time);
+ Creature* GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask);
bool CanInteractWithNPCs(bool alive = true) const;
+ GameObject* GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes type) const;
bool ToggleAFK();
bool ToggleDND();
@@ -965,11 +864,14 @@ class TRINITY_DLL_SPEC Player : public Unit
std::string afkMsg;
std::string dndMsg;
+ uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair);
+
PlayerSocial *GetSocial() { return m_social; }
PlayerTaxi m_taxi;
- void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(),getLevel()); }
- bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_id = 0 , Creature* npc = NULL);
+ void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); }
+ bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = NULL, uint32 spellid = 0);
+ bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0);
// mount_id can be used in scripting calls
bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; }
void SetAcceptWhispers(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; }
@@ -985,6 +887,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void GiveXP(uint32 xp, Unit* victim);
void GiveLevel(uint32 level);
+
void InitStatsForLevel(bool reapplyMods = false);
// Played Time Stuff
@@ -1019,16 +922,10 @@ class TRINITY_DLL_SPEC Player : public Unit
int GetTimeInnEnter() const { return time_inn_enter; };
void UpdateInnerTime (int time) { time_inn_enter = time; };
+ Pet* GetPet() const;
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime);
void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false);
- void RemoveMiniPet();
- Pet* GetMiniPet();
- void SetMiniPet(Pet* pet) { m_miniPet = pet->GetGUID(); }
- void RemoveGuardians();
- bool HasGuardianWithEntry(uint32 entry);
- void AddGuardian(Pet* pet) { m_guardianPets.insert(pet->GetGUID()); }
- GuardianPetList const& GetGuardians() const { return m_guardianPets; }
- void Uncharm();
+ uint32 GetPhaseMaskForSpawn() const; // used for proper set phase for DB at GM-mode creature/GO spawn
void Say(const std::string& text, const uint32 language);
void Yell(const std::string& text, const uint32 language);
@@ -1047,9 +944,15 @@ class TRINITY_DLL_SPEC Player : public Unit
Item* GetItemByGuid( uint64 guid ) const;
Item* GetItemByPos( uint16 pos ) const;
Item* GetItemByPos( uint8 bag, uint8 slot ) const;
+ inline Item* GetUseableItemByPos( uint8 bag, uint8 slot ) const //Does additional check for disarmed weapons
+ {
+ if (!CanUseAttackType(GetAttackBySlot(slot)))
+ return NULL;
+ return GetItemByPos(bag, slot);
+ }
Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const;
Item* GetShield(bool useable = false) const;
- static uint32 GetAttackBySlot( uint8 slot ); // MAX_ATTACK if not weapon slot
+ static uint8 GetAttackBySlot( uint8 slot ); // MAX_ATTACK if not weapon slot
std::vector<Item *> &GetItemUpdateQueue() { return m_itemUpdateQueue; }
static bool IsInventoryPos( uint16 pos ) { return IsInventoryPos(pos >> 8,pos & 255); }
static bool IsInventoryPos( uint8 bag, uint8 slot );
@@ -1060,10 +963,13 @@ class TRINITY_DLL_SPEC Player : public Unit
static bool IsBankPos( uint8 bag, uint8 slot );
bool IsValidPos( uint16 pos ) { return IsBankPos(pos >> 8,pos & 255); }
bool IsValidPos( uint8 bag, uint8 slot );
- bool HasBankBagSlot( uint8 slot ) const;
+ uint8 GetBankBagSlotCount() const { return GetByteValue(PLAYER_BYTES_2, 2); }
+ void SetBankBagSlotCount(uint8 count) { SetByteValue(PLAYER_BYTES_2, 2, count); }
bool HasItemCount( uint32 item, uint32 count, bool inBankAlso = false ) const;
bool HasItemFitToSpellReqirements(SpellEntry const* spellInfo, Item const* ignoreItem = NULL);
- Item* GetItemOrItemWithGemEquipped( uint32 item ) const;
+ bool CanNoReagentCast(SpellEntry const* spellInfo) const;
+ bool HasItemOrGemWithIdEquipped( uint32 item, uint32 count, uint8 except_slot = NULL_SLOT) const;
+ bool HasItemOrGemWithLimitCategoryEquipped( uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const;
uint8 CanTakeMoreSimilarItems(Item* pItem) const { return _CanTakeMoreSimilarItems(pItem->GetEntry(),pItem->GetCount(),pItem); }
uint8 CanTakeMoreSimilarItems(uint32 entry, uint32 count) const { return _CanTakeMoreSimilarItems(entry,count,NULL); }
uint8 CanStoreNewItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = NULL ) const
@@ -1081,6 +987,9 @@ class TRINITY_DLL_SPEC Player : public Unit
uint8 CanStoreItems( Item **pItem,int count) const;
uint8 CanEquipNewItem( uint8 slot, uint16 &dest, uint32 item, bool swap ) const;
uint8 CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading = true ) const;
+
+ uint8 CanEquipUniqueItem( Item * pItem, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1 ) const;
+ uint8 CanEquipUniqueItem( ItemPrototype const* itemProto, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1 ) const;
uint8 CanUnequipItems( uint32 item, uint32 count ) const;
uint8 CanUnequipItem( uint16 src, bool swap ) const;
uint8 CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, Item *pItem, bool swap, bool not_loading = true ) const;
@@ -1094,6 +1003,8 @@ class TRINITY_DLL_SPEC Player : public Unit
Item* EquipItem( uint16 pos, Item *pItem, bool update );
void AutoUnequipOffhandIfNeed();
bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count);
+ void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast = false);
+ void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false) { AutoStoreLoot(NULL_BAG,NULL_SLOT,loot_id,store,broadcast); }
uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const;
uint8 _CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL ) const;
@@ -1135,12 +1046,16 @@ class TRINITY_DLL_SPEC Player : public Unit
void AddArmorProficiency(uint32 newflag) { m_ArmorProficiency |= newflag; }
uint32 GetWeaponProficiency() const { return m_WeaponProficiency; }
uint32 GetArmorProficiency() const { return m_ArmorProficiency; }
- bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; }
bool IsUseEquipedWeapon( bool mainhand ) const
{
// disarm applied only to mainhand weapon
return !IsInFeralForm() && (!mainhand || !HasFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISARMED) );
}
+ bool IsTwoHandUsed() const
+ {
+ Item* mainItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ return mainItem && mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip();
+ }
void SendNewItem( Item *item, uint32 count, bool received, bool created, bool broadcast = false );
bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot);
@@ -1154,7 +1069,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void UpdateItemDuration(uint32 time, bool realtimeonly=false);
void AddEnchantmentDurations(Item *item);
void RemoveEnchantmentDurations(Item *item);
- void RemoveAllEnchantments(EnchantmentSlot slot);
+ void RemoveArenaEnchantments(EnchantmentSlot slot);
void AddEnchantmentDuration(Item *item,EnchantmentSlot slot,uint32 duration);
void ApplyEnchantment(Item *item,EnchantmentSlot slot,bool apply, bool apply_dur = true, bool ignore_condition = false);
void ApplyEnchantment(Item *item,bool apply);
@@ -1171,6 +1086,8 @@ class TRINITY_DLL_SPEC Player : public Unit
/*** QUEST SYSTEM ***/
/*********************************************************/
+ uint32 GetQuestLevel( Quest const* pQuest ) const { return pQuest && pQuest->GetQuestLevel() ? pQuest->GetQuestLevel() : getLevel(); }
+
void PrepareQuestMenu( uint64 guid );
void SendPreparedQuest( uint64 guid );
bool IsActiveQuest( uint32 quest_id ) const;
@@ -1238,7 +1155,6 @@ class TRINITY_DLL_SPEC Player : public Unit
}
}
uint32 GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry);
- void AdjustQuestReqItemCount( Quest const* pQuest );
void AreaExploredOrEventHappens( uint32 questId );
void GroupEventHappens( uint32 questId, WorldObject const* pEventObject );
void ItemAddedQuestCheck( uint32 entry, uint32 count );
@@ -1247,9 +1163,10 @@ class TRINITY_DLL_SPEC Player : public Unit
void CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id );
void TalkedToCreature( uint32 entry, uint64 guid );
void MoneyChanged( uint32 value );
+ void ReputationChanged(FactionEntry const* factionEntry );
bool HasQuestForItem( uint32 itemid ) const;
- bool HasQuestForGO(int32 GOId);
- void UpdateForQuestsGO();
+ bool HasQuestForGO(int32 GOId) const;
+ void UpdateForQuestWorldObjects();
bool CanShareQuest(uint32 quest_id) const;
void SendQuestComplete( uint32 quest_id );
@@ -1275,6 +1192,7 @@ class TRINITY_DLL_SPEC Player : public Unit
/*********************************************************/
bool LoadFromDB(uint32 guid, SqlQueryHolder *holder);
+
bool MinimalLoadFromDB(QueryResult *result, uint32 guid);
static bool LoadValuesArrayFromDB(Tokens& data,uint64 guid);
static uint32 GetUInt32ValueFromArray(Tokens const& data, uint16 index);
@@ -1296,6 +1214,7 @@ class TRINITY_DLL_SPEC Player : public Unit
static void SetFloatValueInArray(Tokens& data,uint16 index, float value);
static void SetUInt32ValueInDB(uint16 index, uint32 value, uint64 guid);
static void SetFloatValueInDB(uint16 index, float value, uint64 guid);
+ static void Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair);
static void SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint32 zone,uint64 guid);
bool m_mailsLoaded;
@@ -1328,6 +1247,7 @@ class TRINITY_DLL_SPEC Player : public Unit
{
SetUInt32Value (PLAYER_FIELD_COINAGE, value);
MoneyChanged( value );
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED);
}
uint32 GetTutorialInt(uint32 intId )
@@ -1352,7 +1272,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void SetSelection(const uint64 &guid) { m_curSelection = guid; SetUInt64Value(UNIT_FIELD_TARGET, guid); }
uint8 GetComboPoints() { return m_comboPoints; }
- uint64 GetComboTarget() { return m_comboTarget; }
+ const uint64& GetComboTarget() const { return m_comboTarget; }
void AddComboPoints(Unit* target, int8 count);
void ClearComboPoints();
@@ -1388,10 +1308,7 @@ class TRINITY_DLL_SPEC Player : public Unit
Item* GetMItem(uint32 id)
{
ItemMap::const_iterator itr = mMitems.find(id);
- if (itr != mMitems.end())
- return itr->second;
-
- return NULL;
+ return itr != mMitems.end() ? itr->second : NULL;
}
void AddMItem(Item* it)
@@ -1403,30 +1320,30 @@ class TRINITY_DLL_SPEC Player : public Unit
bool RemoveMItem(uint32 id)
{
- ItemMap::iterator i = mMitems.find(id);
- if (i == mMitems.end())
- return false;
-
- mMitems.erase(i);
- return true;
+ return mMitems.erase(id) ? true : false;
}
void PetSpellInitialize();
void CharmSpellInitialize();
void PossessSpellInitialize();
+ void VehicleSpellInitialize();
+ void SendRemoveControlBar();
bool HasSpell(uint32 spell) const;
+ bool HasActiveSpell(uint32 spell) const; // show in spellbook
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;
bool IsSpellFitByClassAndRace( uint32 spell_id ) const;
+ bool IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const;
void SendProficiency(uint8 pr1, uint32 pr2);
void SendInitialSpells();
- bool addSpell(uint32 spell_id, bool active, bool learning = true, bool loading = false, uint16 slot_id=SPELL_WITHOUT_SLOT_ID, bool disabled = false);
- void learnSpell(uint32 spell_id);
- void removeSpell(uint32 spell_id, bool disabled = false);
+ bool addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled);
+ void learnSpell(uint32 spell_id, bool dependent);
+ void removeSpell(uint32 spell_id, bool disabled = false, bool update_action_bar_for_low_rank = false);
void resetSpells();
- void learnDefaultSpells(bool loading = false);
+ void learnDefaultSpells();
void learnQuestRewardedSpells();
void learnQuestRewardedSpells(Quest const* quest);
+ void learnSpellHighRank(uint32 spellid);
uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); }
void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS1,points); }
@@ -1434,6 +1351,17 @@ class TRINITY_DLL_SPEC Player : public Unit
uint32 resetTalentsCost() const;
void InitTalentForLevel();
+ void LearnTalent(uint32 talentId, uint32 talentRank);
+ void LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank);
+
+ uint32 CalculateTalentsPoints() const;
+
+ void InitGlyphsForLevel();
+ void SetGlyphSlot(uint8 slot, uint32 slottype) { SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot, slottype); }
+ uint32 GetGlyphSlot(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); }
+ void SetGlyph(uint8 slot, uint32 glyph) { SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph); }
+ uint32 GetGlyph(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot); }
+
uint32 GetFreePrimaryProffesionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS2); }
void SetFreePrimaryProffesions(uint16 profs) { SetUInt32Value(PLAYER_CHARACTER_POINTS2,profs); }
void InitPrimaryProffesions();
@@ -1442,8 +1370,6 @@ class TRINITY_DLL_SPEC Player : public Unit
PlayerSpellMap & GetSpellMap() { return m_spells; }
void AddSpellMod(SpellModifier* mod, bool apply);
- int32 GetTotalFlatMods(uint32 spellId, SpellModOp op);
- int32 GetTotalPctMods(uint32 spellId, SpellModOp op);
bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell = NULL);
template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell = NULL);
void RemoveSpellMods(Spell const* spell);
@@ -1459,14 +1385,18 @@ class TRINITY_DLL_SPEC Player : public Unit
time_t t = time(NULL);
return itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0;
}
+ void AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false );
void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);
- void SendCooldownEvent(SpellEntry const *spellInfo);
+ void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL);
void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs );
- void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); }
+ void RemoveSpellCooldown(uint32 spell_id, bool update = false);
+ void RemoveCategoryCooldown(uint32 cat);
void RemoveArenaSpellCooldowns();
void RemoveAllSpellCooldown();
void _LoadSpellCooldowns(QueryResult *result);
void _SaveSpellCooldowns();
+ void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; }
+ void UpdatePotionCooldown(Spell* spell = NULL);
void setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana)
{
@@ -1492,13 +1422,20 @@ class TRINITY_DLL_SPEC Player : public Unit
m_cinematic = cine;
}
- void addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc);
+ bool addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc);
void removeActionButton(uint8 button);
- void SendInitialActionButtons();
+ void SendInitialActionButtons() const;
PvPInfo pvpInfo;
+ void UpdatePvPState(bool onlyFFA = false);
+ void SetPvP(bool state)
+ {
+ Unit::SetPvP(state);
+ for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
+ (*itr)->SetPvP(state);
+ }
void UpdatePvP(bool state, bool ovrride=false);
- void UpdateZone(uint32 newZone);
+ void UpdateZone(uint32 newZone,uint32 newArea);
void UpdateArea(uint32 newArea);
void UpdateZoneDependentAuras( uint32 zone_id ); // zones
@@ -1548,6 +1485,7 @@ class TRINITY_DLL_SPEC Player : public Unit
static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot);
void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; }
uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; }
+ static void LeaveAllArenaTeams(uint64 guid);
void SetDifficulty(uint32 dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; }
uint8 GetDifficulty() { return m_dungeonDifficulty; }
@@ -1573,9 +1511,12 @@ class TRINITY_DLL_SPEC Player : public Unit
void UpdateArmor();
void UpdateMaxHealth();
void UpdateMaxPower(Powers power);
+ void ApplyFeralAPBonus(int32 amount, bool apply);
void UpdateAttackPowerAndDamage(bool ranged = false);
void UpdateShieldBlockValue();
void UpdateDamagePhysical(WeaponAttackType attType);
+ void ApplySpellDamageBonus(int32 amount, bool apply);
+ void ApplySpellHealingBonus(int32 amount, bool apply);
void UpdateSpellDamageAndHealingBonus();
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage);
@@ -1593,6 +1534,8 @@ class TRINITY_DLL_SPEC Player : public Unit
uint32 GetRangedCritDamageReduction(uint32 damage) const;
uint32 GetSpellCritDamageReduction(uint32 damage) const;
uint32 GetDotDamageReduction(uint32 damage) const;
+ uint32 GetBaseSpellDamageBonus() { return m_baseSpellDamage;}
+ uint32 GetBaseSpellHealingBonus() { return m_baseSpellHealing;}
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const;
void UpdateBlockPercentage();
@@ -1600,9 +1543,14 @@ class TRINITY_DLL_SPEC Player : public Unit
void UpdateAllCritPercentages();
void UpdateParryPercentage();
void UpdateDodgePercentage();
+ void UpdateMeleeHitChances();
+ void UpdateRangedHitChances();
+ void UpdateSpellHitChances();
+
void UpdateAllSpellCritChances();
void UpdateSpellCritChance(uint32 school);
void UpdateExpertise(WeaponAttackType attType);
+ void ApplyManaRegenBonus(int32 amount, bool apply);
void UpdateManaRegen();
const uint64& GetLootGUID() const { return m_lootGuid; }
@@ -1618,8 +1566,6 @@ class TRINITY_DLL_SPEC Player : public Unit
void SendDelayResponse(const uint32);
void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP);
- //Low Level Packets
- void PlaySound(uint32 Sound, bool OnlySelf);
//notifiers
void SendAttackSwingCantAttack();
void SendAttackSwingCancelAttack();
@@ -1662,6 +1608,7 @@ class TRINITY_DLL_SPEC Player : public Unit
uint32 DurabilityRepairAll(bool cost, float discountMod, bool guildBank);
uint32 DurabilityRepair(uint16 pos, bool cost, float discountMod, bool guildBank);
+ void UpdateMirrorTimers();
void StopMirrorTimers()
{
StopMirrorTimer(FATIGUE_TIMER);
@@ -1679,21 +1626,25 @@ class TRINITY_DLL_SPEC Player : public Unit
void UpdateDefense();
void UpdateWeaponSkill (WeaponAttackType attType);
- void UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence);
+ void UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, bool defence);
void SetSkill(uint32 id, uint16 currVal, uint16 maxVal);
- uint16 GetMaxSkillValue(uint32 skill) const; // max + perm. bonus
+ uint16 GetMaxSkillValue(uint32 skill) const; // max + perm. bonus + temp bonus
uint16 GetPureMaxSkillValue(uint32 skill) const; // max
uint16 GetSkillValue(uint32 skill) const; // skill value + perm. bonus + temp bonus
uint16 GetBaseSkillValue(uint32 skill) const; // skill value + perm. bonus
uint16 GetPureSkillValue(uint32 skill) const; // skill value
+ int16 GetSkillPermBonusValue(uint32 skill) const;
int16 GetSkillTempBonusValue(uint32 skill) const;
bool HasSkill(uint32 skill) const;
- void learnSkillRewardedSpells( uint32 id );
- void learnSkillRewardedSpells();
+ void learnSkillRewardedSpells(uint32 id, uint32 value);
- void SetDontMove(bool dontMove);
- bool GetDontMove() const { return m_dontMove; }
+ WorldLocation& GetTeleportDest() { return m_teleport_dest; }
+ bool IsBeingTeleported() const { return mSemaphoreTeleport_Near || mSemaphoreTeleport_Far; }
+ bool IsBeingTeleportedNear() const { return mSemaphoreTeleport_Near; }
+ bool IsBeingTeleportedFar() const { return mSemaphoreTeleport_Far; }
+ void SetSemaphoreTeleportNear(bool semphsetting) { mSemaphoreTeleport_Near = semphsetting; }
+ void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; }
void CheckExploreSystem(void);
@@ -1704,40 +1655,15 @@ class TRINITY_DLL_SPEC Player : public Unit
bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const;
bool RewardPlayerAndGroupAtKill(Unit* pVictim);
+ void RewardPlayerAndGroupAtEvent(uint32 creature_id,WorldObject* pRewardSource);
+ bool isHonorOrXPTarget(Unit* pVictim);
- FactionStateList m_factions;
- ForcedReactions m_forcedReactions;
- FactionStateList const& GetFactionStateList() { return m_factions; }
- uint32 GetDefaultReputationFlags(const FactionEntry *factionEntry) const;
- int32 GetBaseReputation(const FactionEntry *factionEntry) const;
- int32 GetReputation(uint32 faction_id) const;
- int32 GetReputation(const FactionEntry *factionEntry) const;
- ReputationRank GetReputationRank(uint32 faction) const;
- ReputationRank GetReputationRank(const FactionEntry *factionEntry) const;
- ReputationRank GetBaseReputationRank(const FactionEntry *factionEntry) const;
- ReputationRank ReputationToRank(int32 standing) const;
- const static int32 ReputationRank_Length[MAX_REPUTATION_RANK];
- const static int32 Reputation_Cap = 42999;
- const static int32 Reputation_Bottom = -42000;
- bool ModifyFactionReputation(uint32 FactionTemplateId, int32 DeltaReputation);
- bool ModifyFactionReputation(FactionEntry const* factionEntry, int32 standing);
- bool ModifyOneFactionReputation(FactionEntry const* factionEntry, int32 standing);
- bool SetFactionReputation(uint32 FactionTemplateId, int32 standing);
- bool SetFactionReputation(FactionEntry const* factionEntry, int32 standing);
- bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing);
- int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest);
+ ReputationMgr& GetReputationMgr() { return m_reputationMgr; }
+ ReputationMgr const& GetReputationMgr() const { return m_reputationMgr; }
+ ReputationRank GetReputationRank(uint32 faction_id) const;
void RewardReputation(Unit *pVictim, float rate);
void RewardReputation(Quest const *pQuest);
- void SetInitialFactions();
- void UpdateReputation() const;
- void SendFactionState(FactionState const* faction) const;
- void SendInitialReputations();
- FactionState const* GetFactionState( FactionEntry const* factionEntry) const;
- void SetFactionAtWar(FactionState* faction, bool atWar);
- void SetFactionInactive(FactionState* faction, bool inactive);
- void SetFactionVisible(FactionState* faction);
- void SetFactionVisibleForFactionTemplateId(uint32 FactionTemplateId);
- void SetFactionVisibleForFactionId(uint32 FactionId);
+
void UpdateSkillsForLevel();
void UpdateSkillsToMaxSkillsForLevel(); // for .levelup
void ModifySkillBonus(uint32 skillid,int32 val, bool talent);
@@ -1756,6 +1682,8 @@ class TRINITY_DLL_SPEC Player : public Unit
//End of PvP System
+ inline SpellCooldowns GetSpellCooldowns() const { return m_spellCooldowns; }
+
void SetDrunkValue(uint16 newDrunkValue, uint32 itemid=0);
uint16 GetDrunkValue() const { return m_drunk; }
static DrunkenState GetDrunkenstateByValue(uint16 value);
@@ -1770,6 +1698,8 @@ class TRINITY_DLL_SPEC Player : public Unit
void SetCanParry(bool value);
bool CanBlock() const { return m_canBlock; }
void SetCanBlock(bool value);
+ bool CanTitanGrip() const { return m_canTitanGrip ; }
+ void SetCanTitanGrip(bool value) { m_canTitanGrip = value; }
void SetRegularAttackTime();
void SetBaseModValue(BaseModGroup modGroup, BaseModType modType, float value) { m_auraBaseMod[modGroup][modType] = value; }
@@ -1781,8 +1711,8 @@ class TRINITY_DLL_SPEC Player : public Unit
void _RemoveAllStatBonuses();
void _ApplyWeaponDependentAuraMods(Item *item, WeaponAttackType attackType, bool apply);
- void _ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply);
- void _ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType attackType, Aura* aura, bool apply);
+ void _ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attackType, AuraEffect* aura, bool apply);
+ void _ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType attackType, AuraEffect* aura, bool apply);
void _ApplyItemMods(Item *item,uint8 slot,bool apply);
void _RemoveAllItemMods();
@@ -1798,12 +1728,13 @@ class TRINITY_DLL_SPEC Player : public Unit
void ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply, bool form_change = false);
void UpdateEquipSpellsAtFormChange();
void CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPrototype const * proto);
+ void CastItemUseSpell(Item *item,SpellCastTargets const& targets,uint8 cast_count, uint32 glyphIndex);
- void SendInitWorldStates(bool force = false, uint32 forceZoneId = 0);
+ void SendInitWorldStates(uint32 zone, uint32 area);
void SendUpdateWorldState(uint32 Field, uint32 Value);
void SendDirectMessage(WorldPacket *data);
- void SendAuraDurationsForTarget(Unit* target);
+ void SendAurasForTarget(Unit *target);
PlayerMenu* PlayerTalkClass;
std::vector<ItemSetEffect *> ItemSetEff;
@@ -1817,51 +1748,55 @@ class TRINITY_DLL_SPEC Player : public Unit
/*** BATTLEGROUND SYSTEM ***/
/*********************************************************/
- bool InBattleGround() const { return m_bgBattleGroundID != 0; }
- uint32 GetBattleGroundId() const { return m_bgBattleGroundID; }
+ bool InBattleGround() const { return m_bgBattleGroundID != 0; }
+ bool InArena() const;
+ uint32 GetBattleGroundId() const { return m_bgBattleGroundID; }
+ BattleGroundTypeId GetBattleGroundTypeId() const { return m_bgTypeID; }
BattleGround* GetBattleGround() const;
- bool InArena() const;
- static uint32 GetMinLevelForBattleGroundQueueId(uint32 queue_id);
- static uint32 GetMaxLevelForBattleGroundQueueId(uint32 queue_id);
- uint32 GetBattleGroundQueueIdFromLevel() const;
+
+ BGQueueIdBasedOnLevel GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const;
bool InBattleGroundQueue() const
{
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- if (m_bgBattleGroundQueueID[i].bgQueueType != 0)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
+ if (m_bgBattleGroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_NONE)
return true;
return false;
}
- uint32 GetBattleGroundQueueId(uint32 index) const { return m_bgBattleGroundQueueID[index].bgQueueType; }
- uint32 GetBattleGroundQueueIndex(uint32 bgQueueType) const
+ BattleGroundQueueTypeId GetBattleGroundQueueTypeId(uint32 index) const { return m_bgBattleGroundQueueID[index].bgQueueTypeId; }
+ uint32 GetBattleGroundQueueIndex(BattleGroundQueueTypeId bgQueueTypeId) const
{
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- if (m_bgBattleGroundQueueID[i].bgQueueType == bgQueueType)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
+ if (m_bgBattleGroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
return i;
return PLAYER_MAX_BATTLEGROUND_QUEUES;
}
- bool IsInvitedForBattleGroundQueueType(uint32 bgQueueType) const
+ bool IsInvitedForBattleGroundQueueType(BattleGroundQueueTypeId bgQueueTypeId) const
{
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- if (m_bgBattleGroundQueueID[i].bgQueueType == bgQueueType)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
+ if (m_bgBattleGroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
return m_bgBattleGroundQueueID[i].invitedToInstance != 0;
- return PLAYER_MAX_BATTLEGROUND_QUEUES;
+ return false;
}
- bool InBattleGroundQueueForBattleGroundQueueType(uint32 bgQueueType) const
+ bool InBattleGroundQueueForBattleGroundQueueType(BattleGroundQueueTypeId bgQueueTypeId) const
{
- return GetBattleGroundQueueIndex(bgQueueType) < PLAYER_MAX_BATTLEGROUND_QUEUES;
+ return GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES;
}
- void SetBattleGroundId(uint32 val) { m_bgBattleGroundID = val; }
- uint32 AddBattleGroundQueueId(uint32 val)
+ void SetBattleGroundId(uint32 val, BattleGroundTypeId bgTypeId)
+ {
+ m_bgBattleGroundID = val;
+ m_bgTypeID = bgTypeId;
+ }
+ uint32 AddBattleGroundQueueId(BattleGroundQueueTypeId val)
{
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
- if (m_bgBattleGroundQueueID[i].bgQueueType == 0 || m_bgBattleGroundQueueID[i].bgQueueType == val)
+ if (m_bgBattleGroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE || m_bgBattleGroundQueueID[i].bgQueueTypeId == val)
{
- m_bgBattleGroundQueueID[i].bgQueueType = val;
+ m_bgBattleGroundQueueID[i].bgQueueTypeId = val;
m_bgBattleGroundQueueID[i].invitedToInstance = 0;
return i;
}
@@ -1870,48 +1805,40 @@ class TRINITY_DLL_SPEC Player : public Unit
}
bool HasFreeBattleGroundQueueId()
{
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- if (m_bgBattleGroundQueueID[i].bgQueueType == 0)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
+ if (m_bgBattleGroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE)
return true;
return false;
}
- void RemoveBattleGroundQueueId(uint32 val)
+ void RemoveBattleGroundQueueId(BattleGroundQueueTypeId val)
{
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
- if (m_bgBattleGroundQueueID[i].bgQueueType == val)
+ if (m_bgBattleGroundQueueID[i].bgQueueTypeId == val)
{
- m_bgBattleGroundQueueID[i].bgQueueType = 0;
+ m_bgBattleGroundQueueID[i].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
m_bgBattleGroundQueueID[i].invitedToInstance = 0;
return;
}
}
}
- void SetInviteForBattleGroundQueueType(uint32 bgQueueType, uint32 instanceId)
+ void SetInviteForBattleGroundQueueType(BattleGroundQueueTypeId bgQueueTypeId, uint32 instanceId)
{
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- if (m_bgBattleGroundQueueID[i].bgQueueType == bgQueueType)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
+ if (m_bgBattleGroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
m_bgBattleGroundQueueID[i].invitedToInstance = instanceId;
}
bool IsInvitedForBattleGroundInstance(uint32 instanceId) const
{
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
if (m_bgBattleGroundQueueID[i].invitedToInstance == instanceId)
return true;
return false;
}
- uint32 GetBattleGroundEntryPointMap() const { return m_bgEntryPointMap; }
- float GetBattleGroundEntryPointX() const { return m_bgEntryPointX; }
- float GetBattleGroundEntryPointY() const { return m_bgEntryPointY; }
- float GetBattleGroundEntryPointZ() const { return m_bgEntryPointZ; }
- float GetBattleGroundEntryPointO() const { return m_bgEntryPointO; }
+ WorldLocation const& GetBattleGroundEntryPoint() const { return m_bgEntryPoint; }
void SetBattleGroundEntryPoint(uint32 Map, float PosX, float PosY, float PosZ, float PosO )
{
- m_bgEntryPointMap = Map;
- m_bgEntryPointX = PosX;
- m_bgEntryPointY = PosY;
- m_bgEntryPointZ = PosZ;
- m_bgEntryPointO = PosO;
+ m_bgEntryPoint = WorldLocation(Map,PosX,PosY,PosZ,PosO);
}
void SetBGTeam(uint32 team) { m_bgTeam = team; }
@@ -1923,9 +1850,11 @@ class TRINITY_DLL_SPEC Player : public Unit
void ReportedAfkBy(Player* reporter);
void ClearAfkReports() { m_bgAfkReporter.clear(); }
- bool GetBGAccessByLevel(uint32 bgTypeId) const;
- bool isAllowUseBattleGroundObject();
+ bool GetBGAccessByLevel(BattleGroundTypeId bgTypeId) const;
bool isTotalImmunity();
+ bool CanUseBattleGroundObject();
+ bool isTotalImmune();
+ bool CanCaptureTowerPoint();
/*********************************************************/
/*** OUTDOOR PVP SYSTEM ***/
@@ -1939,7 +1868,7 @@ class TRINITY_DLL_SPEC Player : public Unit
/*** REST SYSTEM ***/
/*********************************************************/
- bool isRested() const { return GetRestTime() >= 10000; }
+ bool isRested() const { return GetRestTime() >= 10*IN_MILISECONDS; }
uint32 GetXPRestBonus(uint32 xp);
uint32 GetRestTime() const { return m_restTime;};
void SetRestTime(uint32 v) { m_restTime = v;};
@@ -1948,7 +1877,7 @@ class TRINITY_DLL_SPEC Player : public Unit
/*** ENVIROMENTAL SYSTEM ***/
/*********************************************************/
- void EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 damage);
+ void EnvironmentalDamage(EnviromentalDamage type, uint32 damage);
/*********************************************************/
/*** FLOOD FILTER SYSTEM ***/
@@ -1961,38 +1890,31 @@ class TRINITY_DLL_SPEC Player : public Unit
/*********************************************************/
/*** VARIOUS SYSTEMS ***/
/*********************************************************/
- MovementInfo m_movementInfo;
- uint32 m_lastFallTime;
- float m_lastFallZ;
+ void UpdateFallInformationIfNeed(MovementInfo const& minfo,uint16 opcode);
+ Unit *m_mover;
+ WorldObject *m_seer;
void SetFallInformation(uint32 time, float z)
{
m_lastFallTime = time;
m_lastFallZ = z;
}
+ void HandleFall(MovementInfo const& movementInfo);
+
bool isMoving() const { return HasUnitMovementFlag(movementFlagsMask); }
bool isMovingOrTurning() const { return HasUnitMovementFlag(movementOrTurningFlagsMask); }
bool CanFly() const { return HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY); }
bool IsFlying() const { return HasUnitMovementFlag(MOVEMENTFLAG_FLYING); }
-
- void HandleDrowning();
- void HandleFallDamage(MovementInfo& movementInfo);
- void HandleFallUnderMap();
+ bool IsAllowUseFlyMountsHere() const;
void SetClientControl(Unit* target, uint8 allowMove);
- uint64 GetFarSight() const { return GetUInt64Value(PLAYER_FARSIGHT); }
- void SetFarSight(uint64 guid) { SetUInt64Value(PLAYER_FARSIGHT, guid); }
-
- // Transports
- Transport * GetTransport() const { return m_transport; }
- void SetTransport(Transport * t) { m_transport = t; }
-
- float GetTransOffsetX() const { return m_movementInfo.t_x; }
- float GetTransOffsetY() const { return m_movementInfo.t_y; }
- float GetTransOffsetZ() const { return m_movementInfo.t_z; }
- float GetTransOffsetO() const { return m_movementInfo.t_o; }
- uint32 GetTransTime() const { return m_movementInfo.t_time; }
+ void SetMover(Unit* target) { m_mover = target; }
+ void SetSeer(WorldObject *target) { m_seer = target; }
+ void SetViewpoint(WorldObject *target, bool apply);
+ WorldObject* GetViewpoint() const;
+ void StopCastingCharm();
+ void StopCastingBindSight();
uint32 GetSaveTimer() const { return m_nextSave; }
void SetSaveTimer(uint32 timer) { m_nextSave = timer; }
@@ -2011,6 +1933,7 @@ class TRINITY_DLL_SPEC Player : public Unit
float m_homebindX;
float m_homebindY;
float m_homebindZ;
+ void RelocateToHomebind() { SetMapId(m_homebindMapId); Relocate(m_homebindX,m_homebindY,m_homebindZ); }
// currently visible objects at player client
typedef std::set<uint64> ClientGUIDs;
@@ -2036,15 +1959,20 @@ class TRINITY_DLL_SPEC Player : public Unit
bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; }
void SetAtLoginFlag(AtLoginFlags f) { m_atLoginFlags |= f; }
+ uint32 GetAtLoginFlag() { return m_atLoginFlags; }
+ void SetPetAtLoginFlag(uint8 f) { m_atLoginFlags |= uint32(f<<AT_LOAD_PET_FLAGS); }
LookingForGroup m_lookingForGroup;
// Temporarily removed pet cache
uint32 GetTemporaryUnsummonedPetNumber() const { return m_temporaryUnsummonedPetNumber; }
void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; }
- uint32 GetOldPetSpell() const { return m_oldpetspell; }
- void SetOldPetSpell(uint32 petspell) { m_oldpetspell = petspell; }
+ void UnsummonPetTemporaryIfAny();
+ void ResummonPetTemporaryUnSummonedIfAny();
+ bool IsPetNeedBeTemporaryUnsummoned() const { return !IsInWorld() || !isAlive() || IsMounted() /*+in flight*/; }
+ void SendCinematicStart(uint32 CinematicSequenceId);
+ void SendMovieStart(uint32 MovieId);
/*********************************************************/
/*** INSTANCE SYSTEM ***/
@@ -2079,26 +2007,45 @@ class TRINITY_DLL_SPEC Player : public Unit
GroupReference& GetGroupRef() { return m_group; }
void SetGroup(Group *group, int8 subgroup = -1);
uint8 GetSubGroup() const { return m_group.getSubGroup(); }
- uint32 GetGroupUpdateFlag() { return m_groupUpdateMask; }
+ uint32 GetGroupUpdateFlag() const { return m_groupUpdateMask; }
void SetGroupUpdateFlag(uint32 flag) { m_groupUpdateMask |= flag; }
- uint64 GetAuraUpdateMask() { return m_auraUpdateMask; }
- void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); }
- void UnsetAuraUpdateMask(uint8 slot) { m_auraUpdateMask &= ~(uint64(1) << slot); }
+ const uint64& GetAuraUpdateMaskForRaid() const { return m_auraRaidUpdateMask; }
+ void SetAuraUpdateMaskForRaid(uint8 slot) { m_auraRaidUpdateMask |= (uint64(1) << slot); }
Player* GetNextRandomRaidMember(float radius);
PartyResult CanUninviteFromGroup() const;
+ // BattleGround Group System
+ void SetBattleGroundRaid(Group *group, int8 subgroup = -1);
+ void RemoveFromBattleGroundRaid();
+ Group * GetOriginalGroup() { return m_originalGroup.getTarget(); }
+ GroupReference& GetOriginalGroupRef() { return m_originalGroup; }
+ uint8 GetOriginalSubGroup() const { return m_originalGroup.getSubGroup(); }
+ void SetOriginalGroup(Group *group, int8 subgroup = -1);
GridReference<Player> &GetGridRef() { return m_gridRef; }
MapReference &GetMapRef() { return m_mapRef; }
bool isAllowedToLoot(Creature* creature);
- WorldLocation& GetTeleportDest() { return m_teleport_dest; }
-
DeclinedName const* GetDeclinedNames() const { return m_declinedname; }
+ uint8 GetRunesState() const { return m_runes->runeState; }
+ uint8 GetBaseRune(uint8 index) const { return m_runes->runes[index].BaseRune; }
+ uint8 GetCurrentRune(uint8 index) const { return m_runes->runes[index].CurrentRune; }
+ uint8 GetRuneCooldown(uint8 index) const { return m_runes->runes[index].Cooldown; }
+ void SetBaseRune(uint8 index, uint8 baseRune) { m_runes->runes[index].BaseRune = baseRune; }
+ void SetCurrentRune(uint8 index, uint8 currentRune) { m_runes->runes[index].CurrentRune = currentRune; }
+ void SetRuneCooldown(uint8 index, uint8 cooldown) { m_runes->runes[index].Cooldown = cooldown; m_runes->SetRuneState(index, (cooldown == 0) ? true : false); }
+ void ConvertRune(uint8 index, uint8 newType);
+ void ResyncRunes(uint8 count);
+ void AddRunePower(uint8 index);
+ void InitRunes();
+ AchievementMgr& GetAchievementMgr() { return m_achievementMgr; }
+ void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0);
bool HasTitle(uint32 bitIndex);
bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); }
void SetTitle(CharTitlesEntry const* title);
+ //bool isActiveObject() const { return true; }
+ bool canSeeSpellClickOn(Creature const* creature) const;
protected:
/*********************************************************/
@@ -2107,20 +2054,17 @@ class TRINITY_DLL_SPEC Player : public Unit
/* this variable is set to bg->m_InstanceID, when player is teleported to BG - (it is battleground's GUID)*/
uint32 m_bgBattleGroundID;
+ BattleGroundTypeId m_bgTypeID;
/*
this is an array of BG queues (BgTypeIDs) in which is player
*/
struct BgBattleGroundQueueID_Rec
{
- uint32 bgQueueType;
+ BattleGroundQueueTypeId bgQueueTypeId;
uint32 invitedToInstance;
};
BgBattleGroundQueueID_Rec m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES];
- uint32 m_bgEntryPointMap;
- float m_bgEntryPointX;
- float m_bgEntryPointY;
- float m_bgEntryPointZ;
- float m_bgEntryPointO;
+ WorldLocation m_bgEntryPoint;
std::set<uint32> m_bgAfkReporter;
uint8 m_bgAfkReportedCount;
@@ -2144,6 +2088,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void _LoadActions(QueryResult *result);
void _LoadAuras(QueryResult *result, uint32 timediff);
+ void _LoadGlyphAuras();
void _LoadBoundInstances(QueryResult *result);
void _LoadInventory(QueryResult *result, uint32 timediff);
void _LoadMailInit(QueryResult *resultUnread, QueryResult *resultDelivery);
@@ -2152,7 +2097,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void _LoadQuestStatus(QueryResult *result);
void _LoadDailyQuestStatus(QueryResult *result);
void _LoadGroup(QueryResult *result);
- void _LoadReputation(QueryResult *result);
+ void _LoadSkills();
void _LoadSpells(QueryResult *result);
void _LoadTutorials(QueryResult *result);
void _LoadFriendList(QueryResult *result);
@@ -2170,7 +2115,6 @@ class TRINITY_DLL_SPEC Player : public Unit
void _SaveMail();
void _SaveQuestStatus();
void _SaveDailyQuestStatus();
- void _SaveReputation();
void _SaveSpells();
void _SaveTutorials();
@@ -2180,13 +2124,11 @@ class TRINITY_DLL_SPEC Player : public Unit
/*********************************************************/
/*** ENVIRONMENTAL SYSTEM ***/
/*********************************************************/
- void HandleLava();
void HandleSobering();
- void StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue);
- void ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen);
+ void SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen);
void StopMirrorTimer(MirrorTimerType Type);
- uint8 m_isunderwater;
- bool m_isInWater;
+ void HandleDrowning(uint32 time_diff);
+ int32 getMaxTimer(MirrorTimerType timer);
/*********************************************************/
/*** HONOR SYSTEM ***/
@@ -2194,7 +2136,6 @@ class TRINITY_DLL_SPEC Player : public Unit
time_t m_lastHonorUpdateTime;
void outDebugValues() const;
- bool _removeSpell(uint16 spell_id);
uint64 m_lootGuid;
uint32 m_race;
@@ -2226,11 +2167,16 @@ class TRINITY_DLL_SPEC Player : public Unit
PlayerMails m_mail;
PlayerSpellMap m_spells;
- SpellCooldowns m_spellCooldowns;
+ uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
ActionButtonList m_actionButtons;
float m_auraBaseMod[BASEMOD_END][MOD_END];
+ int16 m_baseRatingValue[MAX_COMBAT_RATING];
+ uint16 m_baseSpellDamage;
+ uint16 m_baseSpellHealing;
+ uint16 m_baseFeralAP;
+ uint16 m_baseManaRegen;
SpellModList m_spellMods[MAX_SPELLMOD];
int32 m_SpellModRemoveCount;
@@ -2247,8 +2193,6 @@ class TRINITY_DLL_SPEC Player : public Unit
typedef std::list<Channel*> JoinedChannelsList;
JoinedChannelsList m_channels;
- bool m_dontMove;
-
int m_cinematic;
Player *pTrader;
@@ -2264,8 +2208,6 @@ class TRINITY_DLL_SPEC Player : public Unit
bool m_DailyQuestChanged;
time_t m_lastDailyQuestTime;
- uint32 m_regenTimer;
- uint32 m_breathTimer;
uint32 m_drunkTimer;
uint16 m_drunk;
uint32 m_weaponChangeTimer;
@@ -2283,8 +2225,10 @@ class TRINITY_DLL_SPEC Player : public Unit
uint32 m_ArmorProficiency;
bool m_canParry;
bool m_canBlock;
+ bool m_canTitanGrip;
uint8 m_swingErrorMsg;
float m_ammoDPS;
+
////////////////////Rest System/////////////////////
int time_inn_enter;
uint32 inn_pos_mapid;
@@ -2295,28 +2239,20 @@ class TRINITY_DLL_SPEC Player : public Unit
RestType rest_type;
////////////////////Rest System/////////////////////
- // Transports
- Transport * m_transport;
-
uint32 m_resetTalentsCost;
time_t m_resetTalentsTime;
uint32 m_usedTalentCount;
+ uint32 m_questRewardTalentCount;
// Social
PlayerSocial *m_social;
// Groups
GroupReference m_group;
+ GroupReference m_originalGroup;
Group *m_groupInvite;
uint32 m_groupUpdateMask;
- uint64 m_auraUpdateMask;
-
- // Temporarily removed pet cache
- uint32 m_temporaryUnsummonedPetNumber;
- uint32 m_oldpetspell;
-
- uint64 m_miniPet;
- GuardianPetList m_guardianPets;
+ uint64 m_auraRaidUpdateMask;
// Player summoning
time_t m_summon_expire;
@@ -2325,12 +2261,8 @@ class TRINITY_DLL_SPEC Player : public Unit
float m_summon_y;
float m_summon_z;
- // Far Teleport
- WorldLocation m_teleport_dest;
-
- bool m_farsightVision;
-
DeclinedName *m_declinedname;
+ Runes *m_runes;
private:
// internal common parts for CanStore/StoreItem functions
uint8 _CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem ) const;
@@ -2338,11 +2270,37 @@ class TRINITY_DLL_SPEC Player : public Unit
uint8 _CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool merge, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot ) const;
Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update );
+ void UpdateKnownCurrencies(uint32 itemId, bool apply);
+ int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest);
+ void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData );
+
GridReference<Player> m_gridRef;
MapReference m_mapRef;
void UpdateCharmedAI();
UnitAI *i_AI;
+
+ uint32 m_lastFallTime;
+ float m_lastFallZ;
+
+ int32 m_MirrorTimer[MAX_TIMERS];
+ uint8 m_MirrorTimerFlags;
+ uint8 m_MirrorTimerFlagsLast;
+ bool m_isInWater;
+
+ // Current teleport data
+ WorldLocation m_teleport_dest;
+ bool mSemaphoreTeleport_Near;
+ bool mSemaphoreTeleport_Far;
+
+ // Temporary removed pet cache
+ uint32 m_temporaryUnsummonedPetNumber;
+ uint32 m_oldpetspell;
+
+ AchievementMgr m_achievementMgr;
+ ReputationMgr m_reputationMgr;
+
+ SpellCooldowns m_spellCooldowns;
};
void AddItemsSetItem(Player*player,Item *item);
@@ -2378,7 +2336,6 @@ template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T &bas
if (mod->charges > 0 )
{
- if( !(spellInfo->SpellFamilyName == 8 && spellInfo->SpellFamilyFlags & 0x200000000LL) )
--mod->charges;
if (mod->charges == 0)
{
diff --git a/src/game/PlayerDump.cpp b/src/game/PlayerDump.cpp
index b061b63a06a..5218d9c4a54 100644
--- a/src/game/PlayerDump.cpp
+++ b/src/game/PlayerDump.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@
#include "ObjectMgr.h"
// Character Dump tables
-#define DUMP_TABLE_COUNT 18
+#define DUMP_TABLE_COUNT 20
struct DumpTable
{
@@ -36,24 +36,27 @@ struct DumpTable
static DumpTable dumpTables[DUMP_TABLE_COUNT] =
{
- { "characters", DTT_CHARACTER },
- { "character_queststatus", DTT_CHAR_TABLE },
- { "character_reputation", DTT_CHAR_TABLE },
- { "character_spell", DTT_CHAR_TABLE },
- { "character_spell_cooldown", DTT_CHAR_TABLE },
- { "character_action", DTT_CHAR_TABLE },
- { "character_aura", DTT_CHAR_TABLE },
- { "character_homebind", DTT_CHAR_TABLE },
- { "character_inventory", DTT_INVENTORY },
- { "mail", DTT_MAIL },
- { "mail_items", DTT_MAIL_ITEM },
- { "item_instance", DTT_ITEM },
- { "character_gifts", DTT_ITEM_GIFT },
- { "item_text", DTT_ITEM_TEXT },
- { "character_pet", DTT_PET },
- { "pet_aura", DTT_PET_TABLE },
- { "pet_spell", DTT_PET_TABLE },
- { "pet_spell_cooldown", DTT_PET_TABLE },
+ { "characters", DTT_CHARACTER },
+ { "character_achievement", DTT_CHAR_TABLE },
+ { "character_achievement_progress", DTT_CHAR_TABLE },
+ { "character_queststatus", DTT_CHAR_TABLE },
+ { "character_reputation", DTT_CHAR_TABLE },
+ { "character_spell", DTT_CHAR_TABLE },
+ { "character_spell_cooldown", DTT_CHAR_TABLE },
+ { "character_action", DTT_CHAR_TABLE },
+ { "character_aura", DTT_CHAR_TABLE },
+ { "character_homebind", DTT_CHAR_TABLE },
+// { "character_ticket", DTT_CHAR_TABLE },
+ { "character_inventory", DTT_INVENTORY },
+ { "mail", DTT_MAIL },
+ { "mail_items", DTT_MAIL_ITEM },
+ { "item_instance", DTT_ITEM },
+ { "character_gifts", DTT_ITEM_GIFT },
+ { "item_text", DTT_ITEM_TEXT },
+ { "character_pet", DTT_PET },
+ { "pet_aura", DTT_PET_TABLE },
+ { "pet_spell", DTT_PET_TABLE },
+ { "pet_spell_cooldown", DTT_PET_TABLE },
};
// Low level functions
@@ -90,7 +93,7 @@ bool findnth(std::string &str, int n, std::string::size_type &s, std::string::si
if (e == std::string::npos) return false;
} while(str[e-1] == '\\');
- for(int i = 1; i < n; i++)
+ for(int i = 1; i < n; ++i)
{
do
{
@@ -154,7 +157,7 @@ bool changetoknth(std::string &str, int n, const char *with, bool insert = false
uint32 registerNewGuid(uint32 oldGuid, std::map<uint32, uint32> &guidMap, uint32 hiGuid)
{
- std::map<uint32, uint32>::iterator itr = guidMap.find(oldGuid);
+ std::map<uint32, uint32>::const_iterator itr = guidMap.find(oldGuid);
if(itr != guidMap.end())
return itr->second;
@@ -195,7 +198,7 @@ std::string CreateDumpString(char const* tableName, QueryResult *result)
std::ostringstream ss;
ss << "INSERT INTO "<< _TABLE_SIM_ << tableName << _TABLE_SIM_ << " VALUES (";
Field *fields = result->Fetch();
- for(uint32 i = 0; i < result->GetFieldCount(); i++)
+ for(uint32 i = 0; i < result->GetFieldCount(); ++i)
{
if (i == 0) ss << "'";
else ss << ", '";
@@ -329,7 +332,39 @@ void PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tabl
std::string PlayerDumpWriter::GetDump(uint32 guid)
{
std::string dump;
- for(int i = 0; i < DUMP_TABLE_COUNT; i++)
+
+ dump += "IMPORTANT NOTE: This sql queries not created for apply directly, use '.pdump load' command in console or client chat instead.\n";
+ dump += "IMPORTANT NOTE: NOT APPLY ITS DIRECTLY to character DB or you will DAMAGE and CORRUPT character DB\n\n";
+
+ // revision check guard
+ QueryResult* result = CharacterDatabase.Query("SELECT * FROM character_db_version LIMIT 1");
+ if(result)
+ {
+ QueryResult::FieldNames const& namesMap = result->GetFieldNames();
+ std::string reqName;
+ for(QueryResult::FieldNames::const_iterator itr = namesMap.begin(); itr != namesMap.end(); ++itr)
+ {
+ if(itr->second.substr(0,9)=="required_")
+ {
+ reqName = itr->second;
+ break;
+ }
+ }
+
+ if(!reqName.empty())
+ {
+ // this will fail at wrong character DB version
+ dump += "UPDATE character_db_version SET "+reqName+" = 1 WHERE FALSE;\n\n";
+ }
+ else
+ sLog.outError("Table 'character_db_version' not have revision guard field, revision guard query not added to pdump.");
+
+ delete result;
+ }
+ else
+ sLog.outError("Character DB not have 'character_db_version' table, revision guard query not added to pdump.");
+
+ for(int i = 0; i < DUMP_TABLE_COUNT; ++i)
DumpTable(dump, guid, dumpTables[i].name, dumpTables[i].name, dumpTables[i].type);
// TODO: Add instance/group..
@@ -436,9 +471,23 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
std::string line; line.assign(buf);
// skip empty strings
- if(line.find_first_not_of(" \t\n\r\7")==std::string::npos)
+ size_t nw_pos = line.find_first_not_of(" \t\n\r\7");
+ if(nw_pos==std::string::npos)
+ continue;
+
+ // skip NOTE
+ if(line.substr(nw_pos,15)=="IMPORTANT NOTE:")
continue;
+ // add required_ check
+ if(line.substr(nw_pos,41)=="UPDATE character_db_version SET required_")
+ {
+ if(!CharacterDatabase.Execute(line.c_str()))
+ ROLLBACK(DUMP_FILE_BROKEN);
+
+ continue;
+ }
+
// determine table name and load type
std::string tn = gettablename(line);
if(tn.empty())
@@ -449,7 +498,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
DumpTableType type;
uint8 i;
- for(i = 0; i < DUMP_TABLE_COUNT; i++)
+ for(i = 0; i < DUMP_TABLE_COUNT; ++i)
{
if (tn == dumpTables[i].name)
{
diff --git a/src/game/PlayerDump.h b/src/game/PlayerDump.h
index 211a000103d..e3dfd192efb 100644
--- a/src/game/PlayerDump.h
+++ b/src/game/PlayerDump.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
#ifndef _PLAYER_DUMP_H
#define _PLAYER_DUMP_H
+
#include <string>
#include <map>
#include <set>
@@ -28,10 +29,10 @@ enum DumpTableType
{
DTT_CHARACTER, // // characters
- DTT_CHAR_TABLE, // // character_action, character_aura, character_homebind,
- // character_queststatus, character_reputation,
- // character_spell, character_spell_cooldown, character_ticket,
- // character_tutorial
+ DTT_CHAR_TABLE, // // character_achievement, character_achievement_progress,
+ // character_action, character_aura, character_homebind,
+ // character_queststatus, character_reputation, character_spell,
+ // character_spell_cooldown, character_ticket, character_tutorial
DTT_INVENTORY, // -> item guids collection // character_inventory
diff --git a/src/game/PointMovementGenerator.cpp b/src/game/PointMovementGenerator.cpp
index 5f7f7ca7c13..c972683ce0b 100644
--- a/src/game/PointMovementGenerator.cpp
+++ b/src/game/PointMovementGenerator.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,16 +22,17 @@
#include "Errors.h"
#include "Creature.h"
#include "CreatureAI.h"
-#include "MapManager.h"
#include "DestinationHolderImp.h"
+#include "World.h"
//----- Point Movement Generator
template<class T>
void PointMovementGenerator<T>::Initialize(T &unit)
{
unit.StopMoving();
+ unit.clearUnitState(UNIT_STAT_MOVING);
Traveller<T> traveller(unit);
- i_destinationHolder.SetDestination(traveller,i_x,i_y,i_z);
+ i_destinationHolder.SetDestination(traveller,i_x,i_y,i_z, !unit.hasUnitState(UNIT_STAT_JUMPING));
if (unit.GetTypeId() == TYPEID_UNIT && ((Creature*)&unit)->canFly())
unit.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
@@ -69,7 +70,7 @@ template<class T>
void PointMovementGenerator<T>:: Finalize(T &unit)
{
if(unit.hasUnitState(UNIT_STAT_CHARGING))
- unit.clearUnitState(UNIT_STAT_CHARGING);
+ unit.clearUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING);
else if(arrived)
MovementInform(unit);
}
@@ -92,3 +93,11 @@ template void PointMovementGenerator<Player>::Finalize(Player&);
template void PointMovementGenerator<Creature>::Initialize(Creature&);
template bool PointMovementGenerator<Creature>::Update(Creature&, const uint32 &diff);
template void PointMovementGenerator<Creature>::Finalize(Creature&);
+
+void AssistanceMovementGenerator::Finalize(Unit &unit)
+{
+ ((Creature*)&unit)->SetNoCallAssistance(false);
+ ((Creature*)&unit)->CallAssistance();
+ if (unit.isAlive())
+ unit.GetMotionMaster()->MoveSeekAssistanceDistract(sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
+}
diff --git a/src/game/PointMovementGenerator.h b/src/game/PointMovementGenerator.h
index 5f1bf33c348..baeb8b26dbd 100644
--- a/src/game/PointMovementGenerator.h
+++ b/src/game/PointMovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,11 +45,23 @@ class TRINITY_DLL_SPEC PointMovementGenerator
bool GetDestination(float& x, float& y, float& z) const { x=i_x; y=i_y; z=i_z; return true; }
private:
- TimeTracker i_nextMoveTime;
- float i_x,i_y,i_z;
uint32 id;
+ float i_x,i_y,i_z;
+ TimeTracker i_nextMoveTime;
DestinationHolder< Traveller<T> > i_destinationHolder;
bool arrived;
};
+
+class MANGOS_DLL_SPEC AssistanceMovementGenerator
+: public PointMovementGenerator<Creature>
+{
+ public:
+ AssistanceMovementGenerator(float _x, float _y, float _z) :
+ PointMovementGenerator<Creature>(0, _x, _y, _z) {}
+
+ MovementGeneratorType GetMovementGeneratorType() { return ASSISTANCE_MOTION_TYPE; }
+ void Finalize(Unit &);
+};
+
#endif
diff --git a/src/game/PoolHandler.cpp b/src/game/PoolHandler.cpp
new file mode 100644
index 00000000000..753b6a249e6
--- /dev/null
+++ b/src/game/PoolHandler.cpp
@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "PoolHandler.h"
+#include "ObjectMgr.h"
+#include "ProgressBar.h"
+#include "Log.h"
+#include "MapManager.h"
+#include "Policies/SingletonImp.h"
+
+INSTANTIATE_SINGLETON_1(PoolHandler);
+
+////////////////////////////////////////////////////////////
+// Methods of template class PoolGroup
+
+template <class T>
+PoolGroup<T>::PoolGroup()
+{
+ Spawned = 0;
+}
+
+// Method to add a gameobject/creature guid to the proper list depending on pool type and chance value
+template <class T>
+void PoolGroup<T>::AddEntry(PoolObject& poolitem, uint32 maxentries)
+{
+ if (poolitem.chance != 0 && maxentries == 1)
+ ExplicitlyChanced.push_back(poolitem);
+ else
+ EqualChanced.push_back(poolitem);
+}
+
+// Method to check the chances are proper in this object pool
+template <class T>
+bool PoolGroup<T>::CheckPool(void)
+{
+ if (EqualChanced.size() == 0)
+ {
+ float chance = 0;
+ for (uint32 i=0; i<ExplicitlyChanced.size(); ++i)
+ chance += ExplicitlyChanced[i].chance;
+ if (chance != 100 && chance != 0)
+ return false;
+ }
+ return true;
+}
+
+// Method that tell if the gameobject, creature or pool is spawned currently
+template <class T>
+bool PoolGroup<T>::IsSpawnedObject(uint32 guid)
+{
+ for (uint32 i=0; i<ExplicitlyChanced.size(); ++i)
+ if (ExplicitlyChanced[i].guid == guid)
+ return ExplicitlyChanced[i].spawned;
+ for (uint32 i=0; i<EqualChanced.size(); ++i)
+ if (EqualChanced[i].guid == guid)
+ return EqualChanced[i].spawned;
+ return false;
+}
+
+// Method that return a guid of a rolled creature or gameobject
+// Note: Copy from loot system because it's very similar and only few things change
+template <class T>
+uint32 PoolGroup<T>::RollOne(void)
+{
+ if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked
+ {
+ float roll = rand_chance();
+
+ for (uint32 i=0; i<ExplicitlyChanced.size(); ++i)
+ {
+ roll -= ExplicitlyChanced[i].chance;
+ if (roll < 0)
+ return ExplicitlyChanced[i].guid;
+ }
+ }
+ if (!EqualChanced.empty())
+ return EqualChanced[irand(0, EqualChanced.size()-1)].guid;
+
+ return 0; // None found
+}
+
+// Main method to despawn a creature or gameobject in a pool
+// If no guid is passed, the pool is just removed (event end case)
+// If guid is filled, cache will be used and no removal will occur, it just fill the cache
+template<class T>
+void PoolGroup<T>::DespawnObject(uint32 guid)
+{
+ for (int i=0; i<EqualChanced.size(); ++i)
+ {
+ if (EqualChanced[i].spawned)
+ {
+ if (!guid || EqualChanced[i].guid == guid)
+ {
+ if (guid)
+ CacheValue = EqualChanced[i].guid;
+ else
+ Despawn1Object(EqualChanced[i].guid);
+
+ EqualChanced[i].spawned = false;
+ Spawned--;
+ }
+ }
+ }
+}
+
+// Method that is actualy doing the removal job on one creature
+template<>
+void PoolGroup<Creature>::Despawn1Object(uint32 guid)
+{
+ if (CreatureData const* data = objmgr.GetCreatureData(guid))
+ {
+ objmgr.RemoveCreatureFromGrid(guid, data);
+
+ if (Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL))
+ {
+ pCreature->CleanupsBeforeDelete();
+ pCreature->AddObjectToRemoveList();
+ }
+ }
+}
+
+// Same on one gameobject
+template<>
+void PoolGroup<GameObject>::Despawn1Object(uint32 guid)
+{
+ if (GameObjectData const* data = objmgr.GetGOData(guid))
+ {
+ objmgr.RemoveGameobjectFromGrid(guid, data);
+
+ if (GameObject* pGameobject = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL))
+ pGameobject->AddObjectToRemoveList();
+ }
+}
+
+// Same on one pool
+template<>
+void PoolGroup<Pool>::Despawn1Object(uint32 child_pool_id)
+{
+ poolhandler.DespawnPool(child_pool_id);
+}
+
+// Method for a pool only to remove any found record causing a circular dependency loop
+template<>
+void PoolGroup<Pool>::RemoveOneRelation(uint16 child_pool_id)
+{
+ for (PoolObjectList::iterator itr = ExplicitlyChanced.begin(); itr != ExplicitlyChanced.end(); ++itr)
+ {
+ if(itr->guid == child_pool_id)
+ {
+ ExplicitlyChanced.erase(itr);
+ break;
+ }
+ }
+ for (PoolObjectList::iterator itr = EqualChanced.begin(); itr != EqualChanced.end(); ++itr)
+ {
+ if(itr->guid == child_pool_id)
+ {
+ EqualChanced.erase(itr);
+ break;
+ }
+ }
+}
+
+// Method that Spawn 1+ creatures or gameobject
+// if cache is false (initialization or event start), X creatures are spawned with X <= limit (< if limit higher that the number of creatures in pool)
+// if cache is true, this means only one has to be spawned (or respawned if the rolled one is same as cached one)
+template <class T>
+void PoolGroup<T>::SpawnObject(uint32 limit, bool cache)
+{
+ if (limit == 1) // This is the only case where explicit chance is used
+ {
+ uint32 roll = RollOne();
+ if (cache && CacheValue != roll)
+ Despawn1Object(CacheValue);
+ CacheValue = Spawn1Object(roll);
+ }
+ else if (limit < EqualChanced.size() && Spawned < limit)
+ {
+ std::vector<uint32> IndexList;
+ for (int i=0; i<EqualChanced.size(); ++i)
+ if (!EqualChanced[i].spawned)
+ IndexList.push_back(i);
+
+ while (Spawned < limit && IndexList.size() > 0)
+ {
+ uint32 roll = urand(1, IndexList.size()) - 1;
+ uint32 index = IndexList[roll];
+ if (!cache || (cache && EqualChanced[index].guid != CacheValue))
+ {
+ if (cache)
+ Despawn1Object(CacheValue);
+ EqualChanced[index].spawned = Spawn1Object(EqualChanced[index].guid);
+ }
+ else
+ EqualChanced[index].spawned = ReSpawn1Object(EqualChanced[index].guid);
+
+ if (EqualChanced[index].spawned)
+ ++Spawned; // limited group use the Spawned variable to store the number of actualy spawned creatures
+ std::vector<uint32>::iterator itr = IndexList.begin()+roll;
+ IndexList.erase(itr);
+ }
+ CacheValue = 0;
+ }
+ else // Not enough objects in pool, so spawn all
+ {
+ for (int i=0; i<EqualChanced.size(); ++i)
+ EqualChanced[i].spawned = Spawn1Object(EqualChanced[i].guid);
+ }
+}
+
+// Method that is actualy doing the spawn job on 1 creature
+template <>
+bool PoolGroup<Creature>::Spawn1Object(uint32 guid)
+{
+ CreatureData const* data = objmgr.GetCreatureData(guid);
+ if (data)
+ {
+ objmgr.AddCreatureToGrid(guid, data);
+
+ // Spawn if necessary (loaded grids only)
+ Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(data->mapid));
+ // We use spawn coords to spawn
+ if (!map->Instanceable() && !map->IsRemovalGrid(data->posX, data->posY))
+ {
+ Creature* pCreature = new Creature;
+ //sLog.outDebug("Spawning creature %u",guid);
+ if (!pCreature->LoadFromDB(guid, map))
+ {
+ delete pCreature;
+ }
+ else
+ {
+ map->Add(pCreature);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+// Same for 1 gameobject
+template <>
+bool PoolGroup<GameObject>::Spawn1Object(uint32 guid)
+{
+ GameObjectData const* data = objmgr.GetGOData(guid);
+ if (data)
+ {
+ objmgr.AddGameobjectToGrid(guid, data);
+ // Spawn if necessary (loaded grids only)
+ // this base map checked as non-instanced and then only existed
+ Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(data->mapid));
+ // We use current coords to unspawn, not spawn coords since creature can have changed grid
+ if (!map->Instanceable() && !map->IsRemovalGrid(data->posX, data->posY))
+ {
+ GameObject* pGameobject = new GameObject;
+ //sLog.outDebug("Spawning gameobject %u", guid);
+ if (!pGameobject->LoadFromDB(guid, map))
+ {
+ delete pGameobject;
+ }
+ else
+ {
+ if (pGameobject->isSpawnedByDefault())
+ map->Add(pGameobject);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+// Same for 1 pool
+template <>
+bool PoolGroup<Pool>::Spawn1Object(uint32 child_pool_id)
+{
+ poolhandler.SpawnPool(child_pool_id);
+ return true;
+}
+
+// Method that does the respawn job on the specified creature
+template <>
+bool PoolGroup<Creature>::ReSpawn1Object(uint32 guid)
+{
+ CreatureData const* data = objmgr.GetCreatureData(guid);
+ if (data)
+ {
+ if (Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL))
+ pCreature->GetMap()->Add(pCreature);
+ return true;
+ }
+ return false;
+}
+
+// Same for 1 gameobject
+template <>
+bool PoolGroup<GameObject>::ReSpawn1Object(uint32 guid)
+{
+ GameObjectData const* data = objmgr.GetGOData(guid);
+ if (data)
+ {
+ if (GameObject* pGameobject = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL))
+ pGameobject->GetMap()->Add(pGameobject);
+ return true;
+ }
+ return false;
+}
+
+// Nothing to do for a child Pool
+template <>
+bool PoolGroup<Pool>::ReSpawn1Object(uint32 /*guid*/)
+{
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+// Methods of class PoolHandler
+
+PoolHandler::PoolHandler()
+{
+ isSystemInit = false;
+}
+
+void PoolHandler::LoadFromDB()
+{
+ QueryResult *result = WorldDatabase.Query("SELECT MAX(entry) FROM pool_template");
+ if (!result)
+ {
+ sLog.outString(">> Table pool_template is empty.");
+ sLog.outString();
+ return;
+ }
+ else
+ {
+ Field *fields = result->Fetch();
+ max_pool_id = fields[0].GetUInt16();
+ delete result;
+ }
+
+ mPoolTemplate.resize(max_pool_id + 1);
+
+ result = WorldDatabase.Query("SELECT entry,max_limit FROM pool_template");
+ if (!result)
+ {
+ mPoolTemplate.clear();
+ sLog.outString(">> Table pool_template is empty:");
+ sLog.outString();
+ return;
+ }
+
+ uint32 count = 0;
+
+ barGoLink bar(result->GetRowCount());
+ do
+ {
+ ++count;
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ uint16 pool_id = fields[0].GetUInt16();
+
+ PoolTemplateData& pPoolTemplate = mPoolTemplate[pool_id];
+ pPoolTemplate.MaxLimit = fields[1].GetUInt32();
+
+ } while (result->NextRow());
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u objects pools", count );
+ delete result;
+
+ // Creatures
+
+ mPoolCreatureGroups.resize(max_pool_id + 1);
+ mCreatureSearchMap.clear();
+ // 1 2 3
+ result = WorldDatabase.Query("SELECT guid, pool_entry, chance FROM pool_creature");
+
+ count = 0;
+ if (!result)
+ {
+ barGoLink bar2(1);
+ bar2.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u creatures in pools", count );
+ }
+ else
+ {
+
+ barGoLink bar2(result->GetRowCount());
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar2.step();
+
+ uint32 guid = fields[0].GetUInt32();
+ uint16 pool_id = fields[1].GetUInt16();
+ float chance = fields[2].GetFloat();
+
+ CreatureData const* data = objmgr.GetCreatureData(guid);
+ if (!data)
+ {
+ sLog.outErrorDb("`pool_creature` has a non existing creature spawn (GUID: %u) defined for pool id (%u), skipped.", guid, pool_id );
+ continue;
+ }
+ if (pool_id > max_pool_id)
+ {
+ sLog.outErrorDb("`pool_creature` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.",pool_id);
+ continue;
+ }
+ if (chance < 0 || chance > 100)
+ {
+ sLog.outErrorDb("`pool_creature` has an invalid chance (%f) for creature guid (%u) in pool id (%i), skipped.", chance, guid, pool_id);
+ continue;
+ }
+ PoolTemplateData *pPoolTemplate = &mPoolTemplate[pool_id];
+ ++count;
+
+ PoolObject plObject = PoolObject(guid, chance);
+ PoolGroup<Creature>& cregroup = mPoolCreatureGroups[pool_id];
+ cregroup.AddEntry(plObject, pPoolTemplate->MaxLimit);
+ SearchPair p(guid, pool_id);
+ mCreatureSearchMap.insert(p);
+
+ } while (result->NextRow());
+ sLog.outString();
+ sLog.outString( ">> Loaded %u creatures in pools", count );
+ delete result;
+ }
+
+ // Gameobjects
+
+ mPoolGameobjectGroups.resize(max_pool_id + 1);
+ mGameobjectSearchMap.clear();
+ // 1 2 3
+ result = WorldDatabase.Query("SELECT guid, pool_entry, chance FROM pool_gameobject");
+
+ count = 0;
+ if (!result)
+ {
+ barGoLink bar2(1);
+ bar2.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u gameobject in pools", count );
+ }
+ else
+ {
+
+ barGoLink bar2(result->GetRowCount());
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar2.step();
+
+ uint32 guid = fields[0].GetUInt32();
+ uint16 pool_id = fields[1].GetUInt16();
+ float chance = fields[2].GetFloat();
+
+ GameObjectData const* data = objmgr.GetGOData(guid);
+ if (!data)
+ {
+ sLog.outErrorDb("`pool_gameobject` has a non existing gameobject spawn (GUID: %u) defined for pool id (%u), skipped.", guid, pool_id );
+ continue;
+ }
+ GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(data->id);
+ if (goinfo->type != GAMEOBJECT_TYPE_CHEST &&
+ goinfo->type != GAMEOBJECT_TYPE_GOOBER &&
+ goinfo->type != GAMEOBJECT_TYPE_FISHINGHOLE)
+ {
+ sLog.outErrorDb("`pool_gameobject` has a not lootable gameobject spawn (GUID: %u, type: %u) defined for pool id (%u), skipped.", guid, goinfo->type, pool_id );
+ continue;
+ }
+ if (pool_id > max_pool_id)
+ {
+ sLog.outErrorDb("`pool_gameobject` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.",pool_id);
+ continue;
+ }
+ if (chance < 0 || chance > 100)
+ {
+ sLog.outErrorDb("`pool_gameobject` has an invalid chance (%f) for gameobject guid (%u) in pool id (%i), skipped.", chance, guid, pool_id);
+ continue;
+ }
+ PoolTemplateData *pPoolTemplate = &mPoolTemplate[pool_id];
+
+ ++count;
+
+ PoolObject plObject = PoolObject(guid, chance);
+ PoolGroup<GameObject>& gogroup = mPoolGameobjectGroups[pool_id];
+ gogroup.AddEntry(plObject, pPoolTemplate->MaxLimit);
+ SearchPair p(guid, pool_id);
+ mGameobjectSearchMap.insert(p);
+
+ } while( result->NextRow() );
+ sLog.outString();
+ sLog.outString( ">> Loaded %u gameobject in pools", count );
+ delete result;
+ }
+
+ // Pool of pools
+ mPoolPoolGroups.resize(max_pool_id + 1);
+ // 1 2 3
+ result = WorldDatabase.Query("SELECT pool_id, mother_pool, chance FROM pool_pool");
+
+ count = 0;
+ if( !result )
+ {
+ barGoLink bar2(1);
+ bar2.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u pools in pools", count );
+ }
+ else
+ {
+
+ barGoLink bar2( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar2.step();
+
+ uint16 child_pool_id = fields[0].GetUInt16();
+ uint16 mother_pool_id = fields[1].GetUInt16();
+ float chance = fields[2].GetFloat();
+
+ if (mother_pool_id > max_pool_id)
+ {
+ sLog.outErrorDb("`pool_pool` mother_pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.",mother_pool_id);
+ continue;
+ }
+ if (child_pool_id > max_pool_id)
+ {
+ sLog.outErrorDb("`pool_pool` included pool_id (%i) is out of range compared to max pool id in `pool_template`, skipped.",child_pool_id);
+ continue;
+ }
+ if (mother_pool_id == child_pool_id)
+ {
+ sLog.outErrorDb("`pool_pool` pool_id (%i) includes itself, dead-lock detected, skipped.",child_pool_id);
+ continue;
+ }
+ if (chance < 0 || chance > 100)
+ {
+ sLog.outErrorDb("`pool_pool` has an invalid chance (%f) for pool id (%u) in mother pool id (%i), skipped.", chance, child_pool_id, mother_pool_id);
+ continue;
+ }
+ PoolTemplateData *pPoolTemplateMother = &mPoolTemplate[mother_pool_id];
+
+ ++count;
+
+ PoolObject plObject = PoolObject(child_pool_id, chance);
+ PoolGroup<Pool>& plgroup = mPoolPoolGroups[mother_pool_id];
+ plgroup.AddEntry(plObject, pPoolTemplateMother->MaxLimit);
+ SearchPair p(child_pool_id, mother_pool_id);
+ mPoolSearchMap.insert(p);
+
+ } while( result->NextRow() );
+
+ // Now check for circular reference
+ for(uint16 i=0; i<max_pool_id; ++i)
+ {
+ std::set<uint16> checkedPools;
+ for(SearchMap::iterator poolItr = mPoolSearchMap.find(i); poolItr != mPoolSearchMap.end(); poolItr = mPoolSearchMap.find(poolItr->second))
+ {
+ checkedPools.insert(poolItr->first);
+ if(checkedPools.find(poolItr->second) != checkedPools.end())
+ {
+ std::ostringstream ss;
+ ss<< "The pool(s) ";
+ for (std::set<uint16>::const_iterator itr=checkedPools.begin(); itr!=checkedPools.end(); ++itr)
+ ss << *itr << " ";
+ ss << "create(s) a circular reference, which can cause the server to freeze.\nRemoving the last link between mother pool "
+ << poolItr->first << " and child pool " << poolItr->second;
+ sLog.outErrorDb(ss.str().c_str());
+ mPoolPoolGroups[poolItr->second].RemoveOneRelation(poolItr->first);
+ mPoolSearchMap.erase(poolItr);
+ --count;
+ break;
+ }
+ }
+ }
+ sLog.outString();
+ sLog.outString( ">> Loaded %u pools in mother pools", count );
+ delete result;
+ }
+}
+
+// The initialize method will spawn all pools not in an event and not in another pool, this is why there is 2 left joins with 2 null checks
+void PoolHandler::Initialize()
+{
+ QueryResult *result = WorldDatabase.Query("SELECT DISTINCT pool_template.entry FROM pool_template LEFT JOIN game_event_pool ON pool_template.entry=game_event_pool.pool_entry LEFT JOIN pool_pool ON pool_template.entry=pool_pool.pool_id WHERE game_event_pool.pool_entry IS NULL AND pool_pool.pool_id IS NULL");
+ uint32 count=0;
+ if (result)
+ {
+ do
+ {
+ Field *fields = result->Fetch();
+ uint16 pool_entry = fields[0].GetUInt16();
+ if (!CheckPool(pool_entry))
+ {
+ sLog.outErrorDb("Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", pool_entry);
+ continue;
+ }
+ SpawnPool(pool_entry);
+ count++;
+ } while (result->NextRow());
+ delete result;
+ }
+
+ sLog.outBasic("Pool handling system initialized, %u pools spawned.", count);
+ isSystemInit = true;
+}
+
+// Call to spawn a pool, if cache if true the method will spawn only if cached entry is different
+// If it's same, the gameobject/creature is respawned only (added back to map)
+void PoolHandler::SpawnPool(uint16 pool_id, bool cache)
+{
+ if (!mPoolPoolGroups[pool_id].isEmpty())
+ mPoolPoolGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache);
+ if (!mPoolGameobjectGroups[pool_id].isEmpty())
+ mPoolGameobjectGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache);
+ if (!mPoolCreatureGroups[pool_id].isEmpty())
+ mPoolCreatureGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache);
+}
+
+// Call to despawn a pool, all gameobjects/creatures in this pool are removed
+void PoolHandler::DespawnPool(uint16 pool_id)
+{
+ if (!mPoolPoolGroups[pool_id].isEmpty())
+ mPoolPoolGroups[pool_id].DespawnObject();
+ if (!mPoolGameobjectGroups[pool_id].isEmpty())
+ mPoolGameobjectGroups[pool_id].DespawnObject();
+ if (!mPoolCreatureGroups[pool_id].isEmpty())
+ mPoolCreatureGroups[pool_id].DespawnObject();
+}
+
+// Call to update the pool when a gameobject/creature part of pool [pool_id] is ready to respawn
+// Here we cache only the creature/gameobject whose guid is passed as parameter
+// Then the spawn pool call will use this cache to decide
+void PoolHandler::UpdatePool(uint16 pool_id, uint32 guid, uint32 type)
+{
+ uint16 motherpoolid = IsPartOfAPool(pool_id, 0);
+
+ if (motherpoolid)
+ mPoolPoolGroups[motherpoolid].DespawnObject(pool_id);
+ else if (type == TYPEID_GAMEOBJECT && !mPoolGameobjectGroups[pool_id].isEmpty())
+ mPoolGameobjectGroups[pool_id].DespawnObject(guid);
+ else if (type != TYPEID_GAMEOBJECT && !mPoolCreatureGroups[pool_id].isEmpty())
+ mPoolCreatureGroups[pool_id].DespawnObject(guid);
+
+ if (motherpoolid)
+ SpawnPool(motherpoolid, true);
+ else
+ SpawnPool(pool_id, true);
+}
+
+// Method that tell if the gameobject/creature is part of a pool and return the pool id if yes
+uint16 PoolHandler::IsPartOfAPool(uint32 guid, uint32 type)
+{
+ if (type == 0) // pool of pool
+ {
+ SearchMap::const_iterator itr = mPoolSearchMap.find(guid);
+ if (itr != mPoolSearchMap.end())
+ return itr->second;
+ }
+ else if (type == TYPEID_GAMEOBJECT)
+ {
+ SearchMap::const_iterator itr = mGameobjectSearchMap.find(guid);
+ if (itr != mGameobjectSearchMap.end())
+ return itr->second;
+ }
+ else // creature
+ {
+ SearchMap::const_iterator itr = mCreatureSearchMap.find(guid);
+ if (itr != mCreatureSearchMap.end())
+ return itr->second;
+ }
+ return 0;
+}
+
+// Method that check chance integrity of the creatures and gameobjects in this pool
+bool PoolHandler::CheckPool(uint16 pool_id)
+{
+ return pool_id <= max_pool_id &&
+ mPoolGameobjectGroups[pool_id].CheckPool() &&
+ mPoolCreatureGroups[pool_id].CheckPool() &&
+ mPoolPoolGroups[pool_id].CheckPool();
+}
+
+// Method that tell if a creature or gameobject in pool_id is spawned currently
+bool PoolHandler::IsSpawnedObject(uint16 pool_id, uint32 guid, uint32 type)
+{
+ if (pool_id > max_pool_id)
+ return false;
+ if (type == 0)
+ return mPoolPoolGroups[pool_id].IsSpawnedObject(guid);
+ else if (type == TYPEID_GAMEOBJECT)
+ return mPoolGameobjectGroups[pool_id].IsSpawnedObject(guid);
+ else
+ return mPoolCreatureGroups[pool_id].IsSpawnedObject(guid);
+}
diff --git a/src/game/PoolHandler.h b/src/game/PoolHandler.h
new file mode 100644
index 00000000000..35e18c2d58c
--- /dev/null
+++ b/src/game/PoolHandler.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MANGOS_POOLHANDLER_H
+#define MANGOS_POOLHANDLER_H
+
+#include "Platform/Define.h"
+#include "Policies/Singleton.h"
+#include "Creature.h"
+#include "GameObject.h"
+
+struct PoolTemplateData
+{
+ uint32 MaxLimit;
+};
+
+struct PoolObject
+{
+ uint32 guid;
+ float chance;
+ bool spawned;
+ PoolObject(uint32 _guid, float _chance): guid(_guid), chance(fabs(_chance)), spawned(false) {}
+};
+
+template <class T>
+class PoolGroup
+{
+ public:
+ PoolGroup();
+ ~PoolGroup() {};
+ bool isEmpty() { return ExplicitlyChanced.size()==0 && EqualChanced.size()==0; }
+ void AddEntry(PoolObject& poolitem, uint32 maxentries);
+ bool CheckPool(void);
+ uint32 RollOne(void);
+ bool IsSpawnedObject(uint32 guid);
+ void DespawnObject(uint32 guid=0);
+ void Despawn1Object(uint32 guid);
+ void SpawnObject(uint32 limit, bool cache=false);
+ bool Spawn1Object(uint32 guid);
+ bool ReSpawn1Object(uint32 guid);
+ void RemoveOneRelation(uint16 child_pool_id);
+ private:
+ typedef std::vector<PoolObject> PoolObjectList;
+ uint32 CacheValue; // Store the guid of the removed creature/gameobject during a pool update
+ PoolObjectList ExplicitlyChanced;
+ PoolObjectList EqualChanced;
+ uint32 Spawned; // Used to know the number of spawned objects
+};
+
+class Pool // for Pool of Pool case
+{
+};
+
+class PoolHandler
+{
+ public:
+ PoolHandler();
+ ~PoolHandler() {};
+ void LoadFromDB();
+ uint16 IsPartOfAPool(uint32 guid, uint32 type);
+ bool IsSpawnedObject(uint16 pool_id, uint32 guid, uint32 type);
+ bool CheckPool(uint16 pool_id);
+ void SpawnPool(uint16 pool_id, bool cache=false);
+ void DespawnPool(uint16 pool_id);
+ void UpdatePool(uint16 pool_id, uint32 guid, uint32 type);
+ void Initialize();
+
+ protected:
+ bool isSystemInit;
+ uint16 max_pool_id;
+ typedef std::vector<PoolTemplateData> PoolTemplateDataMap;
+ typedef std::vector<PoolGroup<Creature> > PoolGroupCreatureMap;
+ typedef std::vector<PoolGroup<GameObject> > PoolGroupGameObjectMap;
+ typedef std::vector<PoolGroup<Pool> > PoolGroupPoolMap;
+ typedef std::pair<uint32, uint16> SearchPair;
+ typedef std::map<uint32, uint16> SearchMap;
+
+ PoolTemplateDataMap mPoolTemplate;
+ PoolGroupCreatureMap mPoolCreatureGroups;
+ PoolGroupGameObjectMap mPoolGameobjectGroups;
+ PoolGroupPoolMap mPoolPoolGroups;
+ SearchMap mCreatureSearchMap;
+ SearchMap mGameobjectSearchMap;
+ SearchMap mPoolSearchMap;
+
+};
+
+#define poolhandler MaNGOS::Singleton<PoolHandler>::Instance()
+#endif
diff --git a/src/game/QueryHandler.cpp b/src/game/QueryHandler.cpp
index 6a99703dbc4..bdb02913f59 100644
--- a/src/game/QueryHandler.cpp
+++ b/src/game/QueryHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,8 +31,8 @@
#include "Player.h"
#include "UpdateMask.h"
#include "NPCHandler.h"
-#include "ObjectAccessor.h"
#include "Pet.h"
+#include "MapManager.h"
void WorldSession::SendNameQueryOpcode(Player *p)
{
@@ -102,20 +102,20 @@ void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult *result, uint32
WorldPacket data( SMSG_NAME_QUERY_RESPONSE, (8+1+4+4+4+10) );
data << MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER);
data << name;
- data << (uint8)0;
- data << (uint32)(field & 0xFF);
- data << (uint32)((field >> 16) & 0xFF);
- data << (uint32)((field >> 8) & 0xFF);
+ data << uint8(0);
+ data << uint32(field & 0xFF);
+ data << uint32((field >> 16) & 0xFF);
+ data << uint32((field >> 8) & 0xFF);
// if the first declined name field (3) is empty, the rest must be too
if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && fields[3].GetCppString() != "")
{
- data << (uint8)1; // is declined
+ data << uint8(1); // is declined
for(int i = 3; i < MAX_DECLINED_NAME_CASES+3; ++i)
data << fields[i].GetCppString();
}
else
- data << (uint8)0; // is declined
+ data << uint8(0); // is declined
session->SendPacket( &data );
delete result;
@@ -123,7 +123,7 @@ void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult *result, uint32
void WorldSession::HandleNameQueryOpcode( WorldPacket & recv_data )
{
- CHECK_PACKET_SIZE(recv_data,8);
+ CHECK_PACKET_SIZE(recv_data, 8);
uint64 guid;
@@ -176,24 +176,22 @@ void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data )
sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name, entry);
// guess size
WorldPacket data( SMSG_CREATURE_QUERY_RESPONSE, 100 );
- data << (uint32)entry; // creature entry
+ data << uint32(entry); // creature entry
data << Name;
data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty
data << SubName;
data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0
- data << (uint32)ci->type_flags; // flags wdbFeild7=wad flags1
- data << (uint32)ci->type;
- data << (uint32)ci->family; // family wdbFeild9
- data << (uint32)ci->rank; // rank wdbFeild10
- data << (uint32)0; // unknown wdbFeild11
- data << (uint32)ci->PetSpellDataId; // Id from CreatureSpellData.dbc wdbField12
+ data << uint32(ci->type_flags); // flags wdbFeild7=wad flags1
+ data << uint32(ci->type);
+ data << uint32(ci->family); // family wdbFeild9
+ data << uint32(ci->rank); // rank wdbFeild10
+ data << uint32(ci->PetSpellDataId); // Id from CreatureSpellData.dbc wdbField12
data << (uint32)ci->Modelid_A1; // Modelid_A1
data << (uint32)ci->Modelid_A2; // Modelid_A2
data << (uint32)ci->Modelid_H1; // Modelid_H1
data << (uint32)ci->Modelid_H2; // Modelid_H2
- data << (float)1.0f; // unk
- data << (float)1.0f; // unk
- data << (uint8)ci->RacialLeader;
+ data << float(ci->unk17); // unk
+ data << uint8(ci->RacialLeader);
SendPacket( &data );
sLog.outDebug( "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE " );
}
@@ -207,7 +205,7 @@ void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data )
WorldPacket data( SMSG_CREATURE_QUERY_RESPONSE, 4 );
data << uint32(entry | 0x80000000);
SendPacket( &data );
- sLog.outDebug( "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE " );
+ sLog.outDebug( "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE " );
}
}
@@ -224,9 +222,11 @@ void WorldSession::HandleGameObjectQueryOpcode( WorldPacket & recv_data )
{
std::string Name;
+ std::string IconName;
std::string CastBarCaption;
Name = info->name;
+ IconName = info->IconName;
CastBarCaption = info->castBarCaption;
int loc_idx = GetSessionDbLocaleIndex();
@@ -243,15 +243,16 @@ void WorldSession::HandleGameObjectQueryOpcode( WorldPacket & recv_data )
}
sLog.outDetail("WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name, entryID);
WorldPacket data ( SMSG_GAMEOBJECT_QUERY_RESPONSE, 150 );
- data << entryID;
- data << (uint32)info->type;
- data << (uint32)info->displayId;
+ data << uint32(entryID);
+ data << uint32(info->type);
+ data << uint32(info->displayId);
data << Name;
data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4
- data << uint8(0); // 2.0.3, string
+ data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword)
data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting")
- data << uint8(0); // 2.0.3, probably string
- data.append(info->raw.data,24);
+ data << uint8(0); // 2.0.3, string
+ data.append(info->raw.data, 24);
+ data << float(info->size); // go size
SendPacket( &data );
sLog.outDebug( "WORLD: Sent CMSG_GAMEOBJECT_QUERY " );
}
@@ -276,20 +277,43 @@ void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recv_data*/)
Corpse *corpse = GetPlayer()->GetCorpse();
- uint8 found = 1;
if(!corpse)
- found = 0;
+ {
+ WorldPacket data(MSG_CORPSE_QUERY, 1);
+ data << uint8(0); // corpse not found
+ SendPacket(&data);
+ return;
+ }
- WorldPacket data(MSG_CORPSE_QUERY, (1+found*(5*4)));
- data << uint8(found);
- if(found)
+ int32 mapid = corpse->GetMapId();
+ float x = corpse->GetPositionX();
+ float y = corpse->GetPositionY();
+ float z = corpse->GetPositionZ();
+ int32 corpsemapid = _player->GetMapId();
+
+ if(Map *map = MapManager::Instance().FindMap(corpse->GetMapId(), corpse->GetInstanceId()))
{
- data << corpse->GetMapId();
- data << corpse->GetPositionX();
- data << corpse->GetPositionY();
- data << corpse->GetPositionZ();
- data << _player->GetMapId();
+ if(map->IsDungeon())
+ {
+ if(!map->GetEntrancePos(mapid, x, y))
+ return;
+
+ Map *entrance_map = MapManager::Instance().GetMap(mapid, _player);
+ if(!entrance_map)
+ return;
+
+ z = entrance_map->GetHeight(x, y, MAX_HEIGHT);
+ corpsemapid = corpse->GetMapId();
+ }
}
+
+ WorldPacket data(MSG_CORPSE_QUERY, 1+(5*4));
+ data << uint8(1); // corpse found
+ data << int32(mapid);
+ data << float(x);
+ data << float(y);
+ data << float(z);
+ data << int32(corpsemapid);
SendPacket(&data);
}
@@ -299,8 +323,6 @@ void WorldSession::HandleNpcTextQueryOpcode( WorldPacket & recv_data )
uint32 textID;
uint64 guid;
- GossipText *pGossip;
- std::string GossipStr;
recv_data >> textID;
sLog.outDetail("WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID);
@@ -308,7 +330,7 @@ void WorldSession::HandleNpcTextQueryOpcode( WorldPacket & recv_data )
recv_data >> guid;
GetPlayer()->SetUInt64Value(UNIT_FIELD_TARGET, guid);
- pGossip = objmgr.GetGossipText(textID);
+ GossipText const* pGossip = objmgr.GetGossipText(textID);
WorldPacket data( SMSG_NPC_TEXT_UPDATE, 100 ); // guess size
data << textID;
@@ -332,7 +354,7 @@ void WorldSession::HandleNpcTextQueryOpcode( WorldPacket & recv_data )
else
{
std::string Text_0[8], Text_1[8];
- for (int i=0;i<8;i++)
+ for (int i=0;i<8;++i)
{
Text_0[i]=pGossip->Options[i].Text_0;
Text_1[i]=pGossip->Options[i].Text_1;
@@ -344,7 +366,7 @@ void WorldSession::HandleNpcTextQueryOpcode( WorldPacket & recv_data )
NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID);
if (nl)
{
- for (int i=0;i<8;i++)
+ for (int i=0;i<8;++i)
{
if (nl->Text_0[i].size() > loc_idx && !nl->Text_0[i][loc_idx].empty())
Text_0[i]=nl->Text_0[i][loc_idx];
@@ -354,7 +376,7 @@ void WorldSession::HandleNpcTextQueryOpcode( WorldPacket & recv_data )
}
}
- for (int i=0; i<8; i++)
+ for (int i=0; i<8; ++i)
{
data << pGossip->Options[i].Probability;
@@ -370,14 +392,11 @@ void WorldSession::HandleNpcTextQueryOpcode( WorldPacket & recv_data )
data << pGossip->Options[i].Language;
- data << pGossip->Options[i].Emotes[0]._Delay;
- data << pGossip->Options[i].Emotes[0]._Emote;
-
- data << pGossip->Options[i].Emotes[1]._Delay;
- data << pGossip->Options[i].Emotes[1]._Emote;
-
- data << pGossip->Options[i].Emotes[2]._Delay;
- data << pGossip->Options[i].Emotes[2]._Emote;
+ for(int j = 0; j < 3; ++j)
+ {
+ data << pGossip->Options[i].Emotes[j]._Delay;
+ data << pGossip->Options[i].Emotes[j]._Emote;
+ }
}
}
diff --git a/src/game/QuestDef.cpp b/src/game/QuestDef.cpp
index 3e190d67220..8099bf40e88 100644
--- a/src/game/QuestDef.cpp
+++ b/src/game/QuestDef.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,88 +44,87 @@ Quest::Quest(Field * questRecord)
QuestFlags = questRecord[17].GetUInt16();
uint32 SpecialFlags = questRecord[18].GetUInt16();
CharTitleId = questRecord[19].GetUInt32();
- PrevQuestId = questRecord[20].GetInt32();
- NextQuestId = questRecord[21].GetInt32();
- ExclusiveGroup = questRecord[22].GetInt32();
- NextQuestInChain = questRecord[23].GetUInt32();
- SrcItemId = questRecord[24].GetUInt32();
- SrcItemCount = questRecord[25].GetUInt32();
- SrcSpell = questRecord[26].GetUInt32();
- Title = questRecord[27].GetCppString();
- Details = questRecord[28].GetCppString();
- Objectives = questRecord[29].GetCppString();
- OfferRewardText = questRecord[30].GetCppString();
- RequestItemsText = questRecord[31].GetCppString();
- EndText = questRecord[32].GetCppString();
+ PlayersSlain = questRecord[20].GetUInt32();
+ BonusTalents = questRecord[21].GetUInt32();
+ PrevQuestId = questRecord[22].GetInt32();
+ NextQuestId = questRecord[23].GetInt32();
+ ExclusiveGroup = questRecord[24].GetInt32();
+ NextQuestInChain = questRecord[25].GetUInt32();
+ SrcItemId = questRecord[26].GetUInt32();
+ SrcItemCount = questRecord[27].GetUInt32();
+ SrcSpell = questRecord[28].GetUInt32();
+ Title = questRecord[29].GetCppString();
+ Details = questRecord[30].GetCppString();
+ Objectives = questRecord[31].GetCppString();
+ OfferRewardText = questRecord[32].GetCppString();
+ RequestItemsText = questRecord[33].GetCppString();
+ EndText = questRecord[34].GetCppString();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ObjectiveText[i] = questRecord[33+i].GetCppString();
+ ObjectiveText[i] = questRecord[35+i].GetCppString();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ReqItemId[i] = questRecord[37+i].GetUInt32();
+ ReqItemId[i] = questRecord[39+i].GetUInt32();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ReqItemCount[i] = questRecord[41+i].GetUInt32();
+ ReqItemCount[i] = questRecord[43+i].GetUInt32();
for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
- ReqSourceId[i] = questRecord[45+i].GetUInt32();
+ ReqSourceId[i] = questRecord[47+i].GetUInt32();
for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
- ReqSourceCount[i] = questRecord[49+i].GetUInt32();
-
- for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
- ReqSourceRef[i] = questRecord[53+i].GetUInt32();
+ ReqSourceCount[i] = questRecord[51+i].GetUInt32();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ReqCreatureOrGOId[i] = questRecord[57+i].GetInt32();
+ ReqCreatureOrGOId[i] = questRecord[55+i].GetInt32();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ReqCreatureOrGOCount[i] = questRecord[61+i].GetUInt32();
+ ReqCreatureOrGOCount[i] = questRecord[59+i].GetUInt32();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ReqSpell[i] = questRecord[65+i].GetUInt32();
+ ReqSpell[i] = questRecord[63+i].GetUInt32();
for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- RewChoiceItemId[i] = questRecord[69+i].GetUInt32();
+ RewChoiceItemId[i] = questRecord[67+i].GetUInt32();
for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- RewChoiceItemCount[i] = questRecord[75+i].GetUInt32();
+ RewChoiceItemCount[i] = questRecord[73+i].GetUInt32();
for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
- RewItemId[i] = questRecord[81+i].GetUInt32();
+ RewItemId[i] = questRecord[79+i].GetUInt32();
for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
- RewItemCount[i] = questRecord[85+i].GetUInt32();
+ RewItemCount[i] = questRecord[83+i].GetUInt32();
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
- RewRepFaction[i] = questRecord[89+i].GetUInt32();
+ RewRepFaction[i] = questRecord[87+i].GetUInt32();
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
- RewRepValue[i] = questRecord[94+i].GetInt32();
-
- RewHonorableKills = questRecord[99].GetUInt32();
- RewOrReqMoney = questRecord[100].GetInt32();
- RewMoneyMaxLevel = questRecord[101].GetUInt32();
- RewSpell = questRecord[102].GetUInt32();
- RewSpellCast = questRecord[103].GetUInt32();
- RewMailTemplateId = questRecord[104].GetUInt32();
- RewMailDelaySecs = questRecord[105].GetUInt32();
- PointMapId = questRecord[106].GetUInt32();
- PointX = questRecord[107].GetFloat();
- PointY = questRecord[108].GetFloat();
- PointOpt = questRecord[109].GetUInt32();
+ RewRepValue[i] = questRecord[92+i].GetInt32();
+
+ RewHonorableKills = questRecord[97].GetUInt32();
+ RewOrReqMoney = questRecord[98].GetInt32();
+ RewMoneyMaxLevel = questRecord[99].GetUInt32();
+ RewSpell = questRecord[100].GetUInt32();
+ RewSpellCast = questRecord[101].GetUInt32();
+ RewMailTemplateId = questRecord[102].GetUInt32();
+ RewMailDelaySecs = questRecord[103].GetUInt32();
+ PointMapId = questRecord[104].GetUInt32();
+ PointX = questRecord[105].GetFloat();
+ PointY = questRecord[106].GetFloat();
+ PointOpt = questRecord[107].GetUInt32();
for (int i = 0; i < QUEST_EMOTE_COUNT; ++i)
- DetailsEmote[i] = questRecord[110+i].GetUInt32();
+ DetailsEmote[i] = questRecord[108+i].GetUInt32();
- IncompleteEmote = questRecord[114].GetUInt32();
- CompleteEmote = questRecord[115].GetUInt32();
+ IncompleteEmote = questRecord[112].GetUInt32();
+ CompleteEmote = questRecord[113].GetUInt32();
for (int i = 0; i < QUEST_EMOTE_COUNT; ++i)
- OfferRewardEmote[i] = questRecord[116+i].GetInt32();
+ OfferRewardEmote[i] = questRecord[114+i].GetInt32();
- QuestStartScript = questRecord[120].GetUInt32();
- QuestCompleteScript = questRecord[121].GetUInt32();
+ QuestStartScript = questRecord[118].GetUInt32();
+ QuestCompleteScript = questRecord[119].GetUInt32();
QuestFlags |= SpecialFlags << 16;
@@ -134,7 +133,7 @@ Quest::Quest(Field * questRecord)
m_rewitemscount = 0;
m_rewchoiceitemscount = 0;
- for (int i=0; i < QUEST_OBJECTIVES_COUNT; i++)
+ for (int i=0; i < QUEST_OBJECTIVES_COUNT; ++i)
{
if ( ReqItemId[i] )
++m_reqitemscount;
@@ -142,13 +141,13 @@ Quest::Quest(Field * questRecord)
++m_reqCreatureOrGOcount;
}
- for (int i=0; i < QUEST_REWARDS_COUNT; i++)
+ for (int i=0; i < QUEST_REWARDS_COUNT; ++i)
{
if ( RewItemId[i] )
++m_rewitemscount;
}
- for (int i=0; i < QUEST_REWARD_CHOICES_COUNT; i++)
+ for (int i=0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
{
if (RewChoiceItemId[i])
++m_rewchoiceitemscount;
@@ -164,18 +163,20 @@ uint32 Quest::XPValue( Player *pPlayer ) const
uint32 pLevel = pPlayer->getLevel();
uint32 qLevel = QuestLevel;
float fullxp = 0;
- if (qLevel >= 65)
+ if (qLevel >= 15)
fullxp = RewMoneyMaxLevel / 6.0f;
- else if (qLevel == 64)
+ else if (qLevel == 14)
fullxp = RewMoneyMaxLevel / 4.8f;
- else if (qLevel == 63)
- fullxp = RewMoneyMaxLevel / 3.6f;
- else if (qLevel == 62)
+ else if (qLevel == 13)
+ fullxp = RewMoneyMaxLevel / 3.666f;
+ else if (qLevel == 12)
fullxp = RewMoneyMaxLevel / 2.4f;
- else if (qLevel == 61)
+ else if (qLevel == 11)
fullxp = RewMoneyMaxLevel / 1.2f;
- else if (qLevel > 0 && qLevel <= 60)
+ else if (qLevel >= 1 && qLevel <= 10)
fullxp = RewMoneyMaxLevel / 0.6f;
+ else if (qLevel == 0)
+ fullxp = RewMoneyMaxLevel;
if( pLevel <= qLevel + 5 )
return (uint32)fullxp;
diff --git a/src/game/QuestDef.h b/src/game/QuestDef.h
index 7b447c611c2..242c10bf48f 100644
--- a/src/game/QuestDef.h
+++ b/src/game/QuestDef.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,30 +44,33 @@ class ObjectMgr;
enum QuestFailedReasons
{
INVALIDREASON_DONT_HAVE_REQ = 0,
- INVALIDREASON_QUEST_FAILED_LOW_LEVEL = 1, //You are not high enough level for that quest.
- INVALIDREASON_QUEST_FAILED_WRONG_RACE = 6, //That quest is not available to your race.
- INVALIDREASON_QUEST_ALREADY_DONE = 7, //You have completed that quest.
- INVALIDREASON_QUEST_ONLY_ONE_TIMED = 12, //You can only be on one timed quest at a time.
- INVALIDREASON_QUEST_ALREADY_ON = 13, //You are already on that quest
- INVALIDREASON_QUEST_FAILED_EXPANSION = 16, //This quest requires an expansion enabled account.
- INVALIDREASON_QUEST_ALREADY_ON2 = 18, //You are already on that quest
- INVALIDREASON_QUEST_FAILED_MISSING_ITEMS = 21, //You don't have the required items with you. Check storage.
- INVALIDREASON_QUEST_FAILED_NOT_ENOUGH_MONEY = 23, //You don't have enough money for that quest.
- INVALIDREASON_DAILY_QUESTS_REMAINING = 26, //You have already completed 10 daily quests today
- INVALIDREASON_QUEST_FAILED_CAIS = 27, //You cannot complete quests once you have reached tired time
+ INVALIDREASON_QUEST_FAILED_LOW_LEVEL = 1, // You are not high enough level for that quest.
+ INVALIDREASON_QUEST_FAILED_WRONG_RACE = 6, // That quest is not available to your race.
+ INVALIDREASON_QUEST_ALREADY_DONE = 7, // You have completed that quest.
+ INVALIDREASON_QUEST_ONLY_ONE_TIMED = 12, // You can only be on one timed quest at a time.
+ INVALIDREASON_QUEST_ALREADY_ON = 13, // You are already on that quest.
+ INVALIDREASON_QUEST_FAILED_EXPANSION = 16, // This quest requires an expansion enabled account.
+ INVALIDREASON_QUEST_ALREADY_ON2 = 18, // You are already on that quest.
+ INVALIDREASON_QUEST_FAILED_MISSING_ITEMS = 21, // You don't have the required items with you. Check storage.
+ INVALIDREASON_QUEST_FAILED_NOT_ENOUGH_MONEY = 23, // You don't have enough money for that quest.
+ INVALIDREASON_DAILY_QUESTS_REMAINING = 26, // You have already completed 25 daily quests today.
+ INVALIDREASON_QUEST_FAILED_CAIS = 27, // You cannot complete quests once you have reached tired time.
+ INVALIDREASON_DAILY_QUEST_COMPLETED_TODAY = 29 // You have completed that daily quest today.
};
enum QuestShareMessages
{
- QUEST_PARTY_MSG_SHARING_QUEST = 0,
- QUEST_PARTY_MSG_CANT_TAKE_QUEST = 1,
- QUEST_PARTY_MSG_ACCEPT_QUEST = 2,
- QUEST_PARTY_MSG_REFUSE_QUEST = 3,
- QUEST_PARTY_MSG_TOO_FAR = 4,
- QUEST_PARTY_MSG_BUSY = 5,
- QUEST_PARTY_MSG_LOG_FULL = 6,
- QUEST_PARTY_MSG_HAVE_QUEST = 7,
- QUEST_PARTY_MSG_FINISH_QUEST = 8,
+ QUEST_PARTY_MSG_SHARING_QUEST = 0,
+ QUEST_PARTY_MSG_CANT_TAKE_QUEST = 1,
+ QUEST_PARTY_MSG_ACCEPT_QUEST = 2,
+ QUEST_PARTY_MSG_DECLINE_QUEST = 3,
+ QUEST_PARTY_MSG_BUSY = 4,
+ QUEST_PARTY_MSG_LOG_FULL = 5,
+ QUEST_PARTY_MSG_HAVE_QUEST = 6,
+ QUEST_PARTY_MSG_FINISH_QUEST = 7,
+ QUEST_PARTY_MSG_CANT_BE_SHARED_TODAY = 8,
+ QUEST_PARTY_MSG_SHARING_TIMER_EXPIRED = 9,
+ QUEST_PARTY_MSG_NOT_IN_PARTY = 10
};
enum __QuestTradeSkill
@@ -122,7 +125,7 @@ enum __QuestFlags
//QUEST_FLAGS_NONE2 = 0x00000010, // Not used currently
QUEST_FLAGS_EPIC = 0x00000020, // Not used currently: Unsure of content
QUEST_FLAGS_RAID = 0x00000040, // Not used currently
- QUEST_FLAGS_TBC = 0x00000080, // Not used currently: Available if TBC expension enabled only
+ QUEST_FLAGS_TBC = 0x00000080, // Not used currently: Available if TBC expansion enabled only
QUEST_FLAGS_UNK2 = 0x00000100, // Not used currently: _DELIVER_MORE Quest needs more than normal _q-item_ drops from mobs
QUEST_FLAGS_HIDDEN_REWARDS = 0x00000200, // Items and money rewarded only sent in SMSG_QUESTGIVER_OFFER_REWARD (not in SMSG_QUESTGIVER_QUEST_DETAILS or in client quest log(SMSG_QUEST_QUERY_RESPONSE))
QUEST_FLAGS_AUTO_REWARDED = 0x00000400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side.
@@ -190,6 +193,8 @@ class Quest
int32 GetExclusiveGroup() const { return ExclusiveGroup; }
uint32 GetNextQuestInChain() const { return NextQuestInChain; }
uint32 GetCharTitleId() const { return CharTitleId; }
+ uint32 GetPlayersSlain() const { return PlayersSlain; }
+ uint32 GetBonusTalents() const { return BonusTalents; }
uint32 GetSrcItemId() const { return SrcItemId; }
uint32 GetSrcItemCount() const { return SrcItemCount; }
uint32 GetSrcSpell() const { return SrcSpell; }
@@ -226,7 +231,6 @@ class Quest
uint32 ReqItemCount[QUEST_OBJECTIVES_COUNT];
uint32 ReqSourceId[QUEST_SOURCE_ITEM_IDS_COUNT];
uint32 ReqSourceCount[QUEST_SOURCE_ITEM_IDS_COUNT];
- uint32 ReqSourceRef[QUEST_SOURCE_ITEM_IDS_COUNT];
int32 ReqCreatureOrGOId[QUEST_OBJECTIVES_COUNT]; // >0 Creature <0 Gameobject
uint32 ReqCreatureOrGOCount[QUEST_OBJECTIVES_COUNT];
uint32 ReqSpell[QUEST_OBJECTIVES_COUNT];
@@ -277,6 +281,8 @@ class Quest
uint32 LimitTime;
uint32 QuestFlags;
uint32 CharTitleId;
+ uint32 PlayersSlain;
+ uint32 BonusTalents;
int32 PrevQuestId;
int32 NextQuestId;
int32 ExclusiveGroup;
diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp
index c447b170d4c..65f001aa2f2 100644
--- a/src/game/QuestHandler.cpp
+++ b/src/game/QuestHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -91,7 +91,7 @@ void WorldSession::HandleQuestgiverHelloOpcode( WorldPacket & recv_data )
sLog.outDebug ("WORLD: Received CMSG_QUESTGIVER_HELLO npc = %u", GUID_LOPART(guid));
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_NONE);
+ Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_NONE);
if (!pCreature)
{
sLog.outDebug ("WORLD: HandleQuestgiverHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.",
@@ -101,7 +101,7 @@ void WorldSession::HandleQuestgiverHelloOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
// Stop the npc if moving
pCreature->StopMoving();
@@ -178,9 +178,9 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode( WorldPacket & recv_data )
// destroy not required for quest finish quest starting item
bool destroyItem = true;
- for(int i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
+ for(int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
{
- if ((qInfo->ReqItemId[i] == ((Item*)pObject)->GetEntry()) && (((Item*)pObject)->GetProto()->MaxCount != 0))
+ if ((qInfo->ReqItemId[i] == ((Item*)pObject)->GetEntry()) && (((Item*)pObject)->GetProto()->MaxCount > 0))
{
destroyItem = false;
break;
@@ -374,6 +374,8 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recv_data)
}
_player->SetQuestSlot(slot, 0);
+
+ _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED, 1);
}
}
@@ -451,12 +453,6 @@ void WorldSession::HandleQuestPushToParty(WorldPacket& recvPacket)
_player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_SHARING_QUEST);
- if( _player->GetDistance( pPlayer ) > 10 )
- {
- _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_TOO_FAR );
- continue;
- }
-
if( !pPlayer->SatisfyQuestStatus( pQuest, false ) )
{
_player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_HAVE_QUEST );
@@ -586,7 +582,7 @@ uint32 WorldSession::getDialogStatus(Player *pPlayer, Object* questgiver, uint32
{
if ( pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded))
result2 = DIALOG_STATUS_REWARD_REP;
- else if (pPlayer->getLevel() <= pQuest->GetQuestLevel() + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF) )
+ else if (pPlayer->getLevel() <= pPlayer->GetQuestLevel(pQuest) + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF) )
{
if (pQuest->HasFlag(QUEST_FLAGS_DAILY))
result2 = DIALOG_STATUS_AVAILABLE_REP;
@@ -620,14 +616,15 @@ void WorldSession::HandleQuestgiverStatusQueryMultipleOpcode(WorldPacket& /*recv
WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4);
data << uint32(count); // placeholder
- for(Player::ClientGUIDs::iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr)
+ for(Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr)
{
uint8 questStatus = DIALOG_STATUS_NONE;
uint8 defstatus = DIALOG_STATUS_NONE;
- if(IS_CREATURE_GUID(*itr))
+ if (IS_CREATURE_OR_PET_GUID(*itr))
{
- Creature *questgiver = ObjectAccessor::GetCreature(*_player, *itr);
+ // need also pet quests case support
+ Creature *questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(),*itr);
if(!questgiver || questgiver->IsHostileTo(_player))
continue;
if(!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER))
@@ -642,7 +639,7 @@ void WorldSession::HandleQuestgiverStatusQueryMultipleOpcode(WorldPacket& /*recv
}
else if(IS_GAMEOBJECT_GUID(*itr))
{
- GameObject *questgiver = ObjectAccessor::GetGameObject(*_player, *itr);
+ GameObject *questgiver = GetPlayer()->GetMap()->GetGameObject(*itr);
if(!questgiver)
continue;
if(questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER)
diff --git a/src/game/RandomMovementGenerator.cpp b/src/game/RandomMovementGenerator.cpp
index ffa82467fd0..93e10ad6115 100644
--- a/src/game/RandomMovementGenerator.cpp
+++ b/src/game/RandomMovementGenerator.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
#include "DestinationHolderImp.h"
#include "Map.h"
#include "Util.h"
+#include "CreatureGroups.h"
#define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
@@ -57,6 +58,9 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
bool is_water_ok = creature.canSwim();
bool is_air_ok = creature.canFly();
+ for(uint32 i = 0;; ++i)
+ {
+
const float angle = rand_norm()*(M_PI*2);
const float range = rand_norm()*wander_distance;
const float distanceX = range * cos(angle);
@@ -71,6 +75,12 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y);
+ if(i == 5)
+ {
+ nz = Z;
+ break;
+ }
+
if (is_air_ok) // 3D system above ground and above water (flying mode)
{
const float distanceZ = rand_norm() * sqrtf(dist)/2; // Limit height change
@@ -78,12 +88,13 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
float wz = map->GetWaterLevel(nx, ny);
if (tz >= nz || wz >= nz)
- return; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
+ continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
}
//else if (is_water_ok) // 3D system under water and above ground (swimming mode)
else // 2D only
{
dist = dist>=100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
+
// The fastest way to get an accurate result 90% of the time.
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
nz = map->GetHeight(nx,ny,Z+dist-2.0f,false); // Map check
@@ -94,11 +105,14 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
{
nz = map->GetHeight(nx,ny,Z+dist-2.0f,true); // Vmap Higher
if (fabs(nz-Z)>dist)
- return; // let's forget this bad coords where a z cannot be find and retry at next tick
+ continue; // let's forget this bad coords where a z cannot be find and retry at next tick
}
}
}
+ break;
+ }
+
Traveller<Creature> traveller(creature);
creature.SetOrientation(creature.GetAngle(nx,ny));
i_destinationHolder.SetDestination(traveller, nx, ny, nz);
@@ -114,6 +128,12 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(),5000+i_destinationHolder.GetTotalTravelTime()));
creature.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE);
}
+
+ //Call for creature group update
+ if(creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
+ {
+ creature.GetFormation()->LeaderMoveTo(nx, ny, nz);
+ }
}
template<>
@@ -123,7 +143,8 @@ RandomMovementGenerator<Creature>::Initialize(Creature &creature)
if(!creature.isAlive())
return;
- wander_distance = creature.GetRespawnRadius();
+ if(!wander_distance)
+ wander_distance = creature.GetRespawnRadius();
if (creature.canFly())
creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
@@ -174,7 +195,7 @@ RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff
creature.SetUnitMovementFlags(irand(0,RUNNING_CHANCE_RANDOMMV) > 0 ? MOVEMENTFLAG_WALK_MODE : MOVEMENTFLAG_NONE);
_setRandomLocation(creature);
}
- else if(creature.isPet() && creature.GetOwner() && creature.GetDistance(creature.GetOwner()) > PET_FOLLOW_DIST+2.5f)
+ else if(creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(),PET_FOLLOW_DIST+2.5f))
{
creature.SetUnitMovementFlags(MOVEMENTFLAG_NONE);
_setRandomLocation(creature);
diff --git a/src/game/RandomMovementGenerator.h b/src/game/RandomMovementGenerator.h
index a7105284ac6..20afe23d375 100644
--- a/src/game/RandomMovementGenerator.h
+++ b/src/game/RandomMovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/ReactorAI.cpp b/src/game/ReactorAI.cpp
index f9fe0abfdc2..35d0be3611f 100644
--- a/src/game/ReactorAI.cpp
+++ b/src/game/ReactorAI.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,78 +41,19 @@ ReactorAI::MoveInLineOfSight(Unit *)
{
}
-bool
-ReactorAI::IsVisible(Unit *) const
-{
- return false;
-}
-
void
ReactorAI::UpdateAI(const uint32 /*time_diff*/)
{
- // update i_victimGuid if i_creature.getVictim() !=0 and changed
+ // update i_victimGuid if m_creature->getVictim() !=0 and changed
if(!UpdateVictim())
return;
- i_victimGuid = i_creature.getVictim()->GetGUID();
-
- if( i_creature.isAttackReady() )
+ if( m_creature->isAttackReady() )
{
- if( i_creature.IsWithinMeleeRange(i_creature.getVictim()))
+ if( m_creature->IsWithinMeleeRange(m_creature->getVictim()))
{
- i_creature.AttackerStateUpdate(i_creature.getVictim());
- i_creature.resetAttackTimer();
+ m_creature->AttackerStateUpdate(m_creature->getVictim());
+ m_creature->resetAttackTimer();
}
}
}
-
-void
-ReactorAI::EnterEvadeMode()
-{
- if( !i_creature.isAlive() )
- {
- DEBUG_LOG("Creature stoped attacking cuz his dead [guid=%u]", i_creature.GetGUIDLow());
- i_creature.GetMotionMaster()->MovementExpired();
- i_creature.GetMotionMaster()->MoveIdle();
- i_victimGuid = 0;
- i_creature.CombatStop();
- i_creature.DeleteThreatList();
- return;
- }
-
- Unit* victim = ObjectAccessor::GetUnit(i_creature, i_victimGuid );
-
- if( !victim )
- {
- DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", i_creature.GetGUIDLow());
- }
- else if( victim->HasStealthAura() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", i_creature.GetGUIDLow());
- }
- else if( victim->isInFlight() )
- {
- DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", i_creature.GetGUIDLow());
- }
- else
- {
- DEBUG_LOG("Creature stopped attacking due to target %s [guid=%u]", victim->isAlive() ? "out run him" : "is dead", i_creature.GetGUIDLow());
- }
-
- i_creature.RemoveAllAuras();
- i_creature.DeleteThreatList();
- i_victimGuid = 0;
- i_creature.CombatStop();
- i_creature.SetLootRecipient(NULL);
- i_creature.ResetDamageByPlayers();
-
- if(!i_creature.GetCharmerOrOwner())
- {
- // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
- if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
- i_creature.GetMotionMaster()->MoveTargetedHome();
- }
- else if (i_creature.GetOwner() && i_creature.GetOwner()->isAlive())
- i_creature.GetMotionMaster()->MoveFollow(i_creature.GetOwner(),PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
-}
-
diff --git a/src/game/ReactorAI.h b/src/game/ReactorAI.h
index a1c99707736..c20c01154f5 100644
--- a/src/game/ReactorAI.h
+++ b/src/game/ReactorAI.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -29,18 +29,12 @@ class TRINITY_DLL_DECL ReactorAI : public CreatureAI
{
public:
- ReactorAI(Creature *c) : CreatureAI(c), i_creature(*c), i_victimGuid(0) {}
+ explicit ReactorAI(Creature *c) : CreatureAI(c) {}
void MoveInLineOfSight(Unit *);
- void EnterEvadeMode();
- bool IsVisible(Unit *) const;
void UpdateAI(const uint32);
static int Permissible(const Creature *);
-
- private:
- Creature &i_creature;
- uint64 i_victimGuid;
};
#endif
diff --git a/src/game/ReputationMgr.cpp b/src/game/ReputationMgr.cpp
new file mode 100644
index 00000000000..62b9504daff
--- /dev/null
+++ b/src/game/ReputationMgr.cpp
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ReputationMgr.h"
+#include "DBCStores.h"
+#include "Player.h"
+#include "WorldPacket.h"
+
+const int32 ReputationMgr::PointsInRank[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000};
+
+ReputationRank ReputationMgr::ReputationToRank(int32 standing)
+{
+ int32 limit = Reputation_Cap + 1;
+ for (int i = MAX_REPUTATION_RANK-1; i >= MIN_REPUTATION_RANK; --i)
+ {
+ limit -= PointsInRank[i];
+ if (standing >= limit )
+ return ReputationRank(i);
+ }
+ return MIN_REPUTATION_RANK;
+}
+
+int32 ReputationMgr::GetReputation(uint32 faction_id) const
+{
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry(faction_id);
+
+ if (!factionEntry)
+ {
+ sLog.outError("ReputationMgr::GetReputation: Can't get reputation of %s for unknown faction (faction id) #%u.",m_player->GetName(), faction_id);
+ return 0;
+ }
+
+ return GetReputation(factionEntry);
+}
+
+int32 ReputationMgr::GetBaseReputation(FactionEntry const* factionEntry) const
+{
+ if (!factionEntry)
+ return 0;
+
+ uint32 raceMask = m_player->getRaceMask();
+ uint32 classMask = m_player->getClassMask();
+ for (int i=0; i < 4; i++)
+ {
+ if( (factionEntry->BaseRepRaceMask[i] & raceMask) &&
+ (factionEntry->BaseRepClassMask[i]==0 ||
+ (factionEntry->BaseRepClassMask[i] & classMask) ) )
+ return factionEntry->BaseRepValue[i];
+ }
+
+ // in faction.dbc exist factions with (RepListId >=0, listed in character reputation list) with all BaseRepRaceMask[i]==0
+ return 0;
+}
+
+int32 ReputationMgr::GetReputation(FactionEntry const* factionEntry) const
+{
+ // Faction without recorded reputation. Just ignore.
+ if(!factionEntry)
+ return 0;
+
+ if(FactionState const* state = GetState(factionEntry))
+ return GetBaseReputation(factionEntry) + state->Standing;
+
+ return 0;
+}
+
+ReputationRank ReputationMgr::GetRank(FactionEntry const* factionEntry) const
+{
+ int32 reputation = GetReputation(factionEntry);
+ return ReputationToRank(reputation);
+}
+
+ReputationRank ReputationMgr::GetBaseRank(FactionEntry const* factionEntry) const
+{
+ int32 reputation = GetBaseReputation(factionEntry);
+ return ReputationToRank(reputation);
+}
+
+void ReputationMgr::ApplyForceReaction( uint32 faction_id,ReputationRank rank,bool apply )
+{
+ if(apply)
+ m_forcedReactions[faction_id] = rank;
+ else
+ m_forcedReactions.erase(faction_id);
+}
+
+uint32 ReputationMgr::GetDefaultStateFlags(FactionEntry const* factionEntry) const
+{
+ if (!factionEntry)
+ return 0;
+
+ uint32 raceMask = m_player->getRaceMask();
+ uint32 classMask = m_player->getClassMask();
+ for (int i=0; i < 4; i++)
+ {
+ if( (factionEntry->BaseRepRaceMask[i] & raceMask) &&
+ (factionEntry->BaseRepClassMask[i]==0 ||
+ (factionEntry->BaseRepClassMask[i] & classMask) ) )
+ return factionEntry->ReputationFlags[i];
+ }
+ return 0;
+}
+
+void ReputationMgr::SendForceReactions()
+{
+ WorldPacket data;
+ data.Initialize(SMSG_SET_FORCED_REACTIONS, 4+m_forcedReactions.size()*(4+4));
+ data << uint32(m_forcedReactions.size());
+ for(ForcedReactions::const_iterator itr = m_forcedReactions.begin(); itr != m_forcedReactions.end(); ++itr)
+ {
+ data << uint32(itr->first); // faction_id (Faction.dbc)
+ data << uint32(itr->second); // reputation rank
+ }
+ m_player->SendDirectMessage(&data);
+}
+
+void ReputationMgr::SendState(FactionState const* faction) const
+{
+ if(faction->Flags & FACTION_FLAG_VISIBLE) //If faction is visible then update it
+ {
+ WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0
+ data << (float) 0; // unk 2.4.0
+ data << (uint8) 0; // wotlk 8634
+ data << (uint32) 1; // count
+ // for
+ data << (uint32) faction->ReputationListID;
+ data << (uint32) faction->Standing;
+ // end for
+ m_player->SendDirectMessage(&data);
+ }
+}
+
+void ReputationMgr::SendInitialReputations()
+{
+ WorldPacket data(SMSG_INITIALIZE_FACTIONS, (4+128*5));
+ data << uint32 (0x00000080);
+
+ RepListID a = 0;
+
+ for (FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
+ {
+ // fill in absent fields
+ for (; a != itr->first; a++)
+ {
+ data << uint8 (0x00);
+ data << uint32 (0x00000000);
+ }
+
+ // fill in encountered data
+ data << uint8 (itr->second.Flags);
+ data << uint32 (itr->second.Standing);
+
+ ++a;
+ }
+
+ // fill in absent fields
+ for (; a != 128; a++)
+ {
+ data << uint8 (0x00);
+ data << uint32 (0x00000000);
+ }
+
+ m_player->SendDirectMessage(&data);
+}
+
+void ReputationMgr::SendStates() const
+{
+ for(FactionStateList::const_iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
+ SendState(&(itr->second));
+}
+
+void ReputationMgr::SendVisible(FactionState const* faction) const
+{
+ if(m_player->GetSession()->PlayerLoading())
+ return;
+
+ // make faction visible in reputation list at client
+ WorldPacket data(SMSG_SET_FACTION_VISIBLE, 4);
+ data << faction->ReputationListID;
+ m_player->SendDirectMessage(&data);
+}
+
+void ReputationMgr::Initilize()
+{
+ m_factions.clear();
+ m_visibleFactionCount = 0;
+ m_honoredFactionCount = 0;
+ m_reveredFactionCount = 0;
+ m_exaltedFactionCount = 0;
+
+ for(unsigned int i = 1; i < sFactionStore.GetNumRows(); i++)
+ {
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry(i);
+
+ if( factionEntry && (factionEntry->reputationListID >= 0))
+ {
+ FactionState newFaction;
+ newFaction.ID = factionEntry->ID;
+ newFaction.ReputationListID = factionEntry->reputationListID;
+ newFaction.Standing = 0;
+ newFaction.Flags = GetDefaultStateFlags(factionEntry);
+ newFaction.Changed = true;
+
+ if( newFaction.Flags & FACTION_FLAG_VISIBLE )
+ ++m_visibleFactionCount;
+
+ UpdateRankCounters(REP_HOSTILE,GetBaseRank(factionEntry));
+
+ m_factions[newFaction.ReputationListID] = newFaction;
+ }
+ }
+}
+
+bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental)
+{
+ SimpleFactionsList const* flist = GetFactionTeamList(factionEntry->ID);
+ if (flist)
+ {
+ bool res = false;
+ for (SimpleFactionsList::const_iterator itr = flist->begin();itr != flist->end();++itr)
+ {
+ FactionEntry const *factionEntryCalc = sFactionStore.LookupEntry(*itr);
+ if(factionEntryCalc)
+ res = SetOneFactionReputation(factionEntryCalc, standing, incremental);
+ }
+ return res;
+ }
+ else
+ return SetOneFactionReputation(factionEntry, standing, incremental);
+}
+
+bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental)
+{
+ FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID);
+ if (itr != m_factions.end())
+ {
+ int32 BaseRep = GetBaseReputation(factionEntry);
+
+ if(incremental)
+ standing += itr->second.Standing + BaseRep;
+
+ if (standing > Reputation_Cap)
+ standing = Reputation_Cap;
+ else if (standing < Reputation_Bottom)
+ standing = Reputation_Bottom;
+
+ ReputationRank old_rank = ReputationToRank(itr->second.Standing + BaseRep);
+ ReputationRank new_rank = ReputationToRank(standing);
+
+ itr->second.Standing = standing - BaseRep;
+ itr->second.Changed = true;
+
+ SetVisible(&itr->second);
+
+ if(new_rank <= REP_HOSTILE)
+ SetAtWar(&itr->second,true);
+
+ SendState(&itr->second);
+
+ UpdateRankCounters(old_rank, new_rank);
+
+ m_player->ReputationChanged(factionEntry);
+ m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS, factionEntry->ID);
+ m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID);
+ m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION,factionEntry->ID);
+ m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION,factionEntry->ID);
+ m_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION,factionEntry->ID);
+
+ return true;
+ }
+ return false;
+}
+
+void ReputationMgr::SetVisible(FactionTemplateEntry const*factionTemplateEntry)
+{
+ if(!factionTemplateEntry->faction)
+ return;
+
+ if(FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->faction))
+ SetVisible(factionEntry);
+}
+
+void ReputationMgr::SetVisible(FactionEntry const *factionEntry)
+{
+ if(factionEntry->reputationListID < 0)
+ return;
+
+ FactionStateList::iterator itr = m_factions.find(factionEntry->reputationListID);
+ if (itr == m_factions.end())
+ return;
+
+ SetVisible(&itr->second);
+}
+
+void ReputationMgr::SetVisible(FactionState* faction)
+{
+ // always invisible or hidden faction can't be make visible
+ if(faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN))
+ return;
+
+ // already set
+ if(faction->Flags & FACTION_FLAG_VISIBLE)
+ return;
+
+ faction->Flags |= FACTION_FLAG_VISIBLE;
+ faction->Changed = true;
+
+ ++m_visibleFactionCount;
+
+ SendVisible(faction);
+}
+
+void ReputationMgr::SetAtWar( RepListID repListID, bool on )
+{
+ FactionStateList::iterator itr = m_factions.find(repListID);
+ if (itr == m_factions.end())
+ return;
+
+ // always invisible or hidden faction can't change war state
+ if(itr->second.Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN) )
+ return;
+
+ SetAtWar(&itr->second,on);
+}
+
+void ReputationMgr::SetAtWar(FactionState* faction, bool atWar)
+{
+ // not allow declare war to own faction
+ if(atWar && (faction->Flags & FACTION_FLAG_PEACE_FORCED) )
+ return;
+
+ // already set
+ if(((faction->Flags & FACTION_FLAG_AT_WAR) != 0) == atWar)
+ return;
+
+ if( atWar )
+ faction->Flags |= FACTION_FLAG_AT_WAR;
+ else
+ faction->Flags &= ~FACTION_FLAG_AT_WAR;
+
+ faction->Changed = true;
+}
+
+void ReputationMgr::SetInactive( RepListID repListID, bool on )
+{
+ FactionStateList::iterator itr = m_factions.find(repListID);
+ if (itr == m_factions.end())
+ return;
+
+ SetInactive(&itr->second,on);
+}
+
+void ReputationMgr::SetInactive(FactionState* faction, bool inactive)
+{
+ // always invisible or hidden faction can't be inactive
+ if(inactive && ((faction->Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN)) || !(faction->Flags & FACTION_FLAG_VISIBLE) ) )
+ return;
+
+ // already set
+ if(((faction->Flags & FACTION_FLAG_INACTIVE) != 0) == inactive)
+ return;
+
+ if(inactive)
+ faction->Flags |= FACTION_FLAG_INACTIVE;
+ else
+ faction->Flags &= ~FACTION_FLAG_INACTIVE;
+
+ faction->Changed = true;
+}
+
+void ReputationMgr::LoadFromDB(QueryResult *result)
+{
+ // Set initial reputations (so everything is nifty before DB data load)
+ Initilize();
+
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'",GetGUIDLow());
+
+ if(result)
+ {
+ do
+ {
+ Field *fields = result->Fetch();
+
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry(fields[0].GetUInt32());
+ if( factionEntry && (factionEntry->reputationListID >= 0))
+ {
+ FactionState* faction = &m_factions[factionEntry->reputationListID];
+
+ // update standing to current
+ faction->Standing = int32(fields[1].GetUInt32());
+
+ // update counters
+ int32 BaseRep = GetBaseReputation(factionEntry);
+ ReputationRank old_rank = ReputationToRank(BaseRep);
+ ReputationRank new_rank = ReputationToRank(BaseRep + faction->Standing);
+ UpdateRankCounters(old_rank,new_rank);
+
+ uint32 dbFactionFlags = fields[2].GetUInt32();
+
+ if( dbFactionFlags & FACTION_FLAG_VISIBLE )
+ SetVisible(faction); // have internal checks for forced invisibility
+
+ if( dbFactionFlags & FACTION_FLAG_INACTIVE)
+ SetInactive(faction,true); // have internal checks for visibility requirement
+
+ if( dbFactionFlags & FACTION_FLAG_AT_WAR ) // DB at war
+ SetAtWar(faction,true); // have internal checks for FACTION_FLAG_PEACE_FORCED
+ else // DB not at war
+ {
+ // allow remove if visible (and then not FACTION_FLAG_INVISIBLE_FORCED or FACTION_FLAG_HIDDEN)
+ if( faction->Flags & FACTION_FLAG_VISIBLE )
+ SetAtWar(faction,false); // have internal checks for FACTION_FLAG_PEACE_FORCED
+ }
+
+ // set atWar for hostile
+ if(GetRank(factionEntry) <= REP_HOSTILE)
+ SetAtWar(faction,true);
+
+ // reset changed flag if values similar to saved in DB
+ if(faction->Flags==dbFactionFlags)
+ faction->Changed = false;
+ }
+ }
+ while( result->NextRow() );
+
+ delete result;
+ }
+}
+
+void ReputationMgr::SaveToDB()
+{
+ for(FactionStateList::iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr)
+ {
+ if (itr->second.Changed)
+ {
+ CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u' AND faction='%u'", m_player->GetGUIDLow(), itr->second.ID);
+ CharacterDatabase.PExecute("INSERT INTO character_reputation (guid,faction,standing,flags) VALUES ('%u', '%u', '%i', '%u')", m_player->GetGUIDLow(), itr->second.ID, itr->second.Standing, itr->second.Flags);
+ itr->second.Changed = false;
+ }
+ }
+}
+
+void ReputationMgr::UpdateRankCounters( ReputationRank old_rank, ReputationRank new_rank )
+{
+ if(old_rank >= REP_EXALTED)
+ --m_exaltedFactionCount;
+ if(old_rank >= REP_REVERED)
+ --m_reveredFactionCount;
+ if(old_rank >= REP_HONORED)
+ --m_honoredFactionCount;
+
+ if(new_rank >= REP_EXALTED)
+ ++m_exaltedFactionCount;
+ if(new_rank >= REP_REVERED)
+ ++m_reveredFactionCount;
+ if(new_rank >= REP_HONORED)
+ ++m_honoredFactionCount;
+} \ No newline at end of file
diff --git a/src/game/ReputationMgr.h b/src/game/ReputationMgr.h
new file mode 100644
index 00000000000..b81634119df
--- /dev/null
+++ b/src/game/ReputationMgr.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __MANGOS_REPUTATION_MGR_H
+#define __MANGOS_REPUTATION_MGR_H
+
+#include "Common.h"
+#include "SharedDefines.h"
+#include "DBCStructure.h"
+#include <map>
+
+enum FactionFlags
+{
+ FACTION_FLAG_VISIBLE = 0x01, // makes visible in client (set or can be set at interaction with target of this faction)
+ FACTION_FLAG_AT_WAR = 0x02, // enable AtWar-button in client. player controlled (except opposition team always war state), Flag only set on initial creation
+ FACTION_FLAG_HIDDEN = 0x04, // hidden faction from reputation pane in client (player can gain reputation, but this update not sent to client)
+ FACTION_FLAG_INVISIBLE_FORCED = 0x08, // always overwrite FACTION_FLAG_VISIBLE and hide faction in rep.list, used for hide opposite team factions
+ FACTION_FLAG_PEACE_FORCED = 0x10, // always overwrite FACTION_FLAG_AT_WAR, used for prevent war with own team factions
+ FACTION_FLAG_INACTIVE = 0x20, // player controlled, state stored in characters.data ( CMSG_SET_FACTION_INACTIVE )
+ FACTION_FLAG_RIVAL = 0x40 // flag for the two competing outland factions
+};
+
+typedef uint32 RepListID;
+struct FactionState
+{
+ uint32 ID;
+ RepListID ReputationListID;
+ uint32 Flags;
+ int32 Standing;
+ bool Changed;
+};
+
+typedef std::map<RepListID,FactionState> FactionStateList;
+typedef std::pair<FactionStateList::const_iterator,FactionStateList::const_iterator> FactionStateListPair;
+
+typedef std::map<uint32,ReputationRank> ForcedReactions;
+
+class Player;
+class QueryResult;
+
+class ReputationMgr
+{
+ public: // constructors and global modifiers
+ explicit ReputationMgr(Player* owner) : m_player(owner),
+ m_visibleFactionCount(0), m_honoredFactionCount(0), m_reveredFactionCount(0), m_exaltedFactionCount(0) {}
+ ~ReputationMgr() {}
+
+ void SaveToDB();
+ void LoadFromDB(QueryResult *result);
+ public: // statics
+ static const int32 PointsInRank[MAX_REPUTATION_RANK];
+ static const int32 Reputation_Cap = 42999;
+ static const int32 Reputation_Bottom = -42000;
+
+ static ReputationRank ReputationToRank(int32 standing);
+ public: // accessors
+ uint8 GetVisibleFactionCount() const { return m_visibleFactionCount; }
+ uint8 GetHonoredFactionCount() const { return m_honoredFactionCount; }
+ uint8 GetReveredFactionCount() const { return m_reveredFactionCount; }
+ uint8 GetExaltedFactionCount() const { return m_exaltedFactionCount; }
+
+ FactionStateList const& GetStateList() const { return m_factions; }
+
+ FactionState const* GetState(FactionEntry const* factionEntry) const
+ {
+ return factionEntry->reputationListID >= 0 ? GetState(factionEntry->reputationListID) : NULL;
+ }
+
+ FactionState const* GetState(RepListID id) const
+ {
+ FactionStateList::const_iterator repItr = m_factions.find (id);
+ return repItr != m_factions.end() ? &repItr->second : NULL;
+ }
+
+ int32 GetReputation(uint32 faction_id) const;
+ int32 GetReputation(FactionEntry const* factionEntry) const;
+ int32 GetBaseReputation(FactionEntry const* factionEntry) const;
+
+ ReputationRank GetRank(FactionEntry const* factionEntry) const;
+ ReputationRank GetBaseRank(FactionEntry const* factionEntry) const;
+
+ ReputationRank const* GetForcedRankIfAny(FactionTemplateEntry const* factionTemplateEntry) const
+ {
+ ForcedReactions::const_iterator forceItr = m_forcedReactions.find(factionTemplateEntry->faction);
+ return forceItr != m_forcedReactions.end() ? &forceItr->second : NULL;
+ }
+
+ public: // modifiers
+ bool SetReputation(FactionEntry const* factionEntry, int32 standing)
+ {
+ return SetReputation(factionEntry, standing, false);
+ }
+ bool ModifyReputation(FactionEntry const* factionEntry, int32 standing)
+ {
+ return SetReputation(factionEntry, standing, true);
+ }
+
+ void SetVisible(FactionTemplateEntry const* factionTemplateEntry);
+ void SetVisible(FactionEntry const* factionEntry);
+ void SetAtWar(RepListID repListID, bool on);
+ void SetInactive(RepListID repListID, bool on);
+
+ void ApplyForceReaction(uint32 faction_id,ReputationRank rank,bool apply);
+
+ public: // senders
+ void SendInitialReputations();
+ void SendForceReactions();
+ void SendState(FactionState const* faction) const;
+ void SendStates() const;
+
+ private: // internal helper functions
+ void Initilize();
+ uint32 GetDefaultStateFlags(const FactionEntry *factionEntry) const;
+ bool SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental);
+ bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental);
+ void SetVisible(FactionState* faction);
+ void SetAtWar(FactionState* faction, bool atWar);
+ void SetInactive(FactionState* faction, bool inactive);
+ void SendVisible(FactionState const* faction) const;
+ void UpdateRankCounters( ReputationRank old_rank, ReputationRank new_rank );
+ private:
+ Player* m_player;
+ FactionStateList m_factions;
+ ForcedReactions m_forcedReactions;
+ uint8 m_visibleFactionCount :8;
+ uint8 m_honoredFactionCount :8;
+ uint8 m_reveredFactionCount :8;
+ uint8 m_exaltedFactionCount :8;
+};
+
+#endif
diff --git a/src/game/ScriptCalls.cpp b/src/game/ScriptCalls.cpp
index 5f3b8a96b0d..fec1afb08ae 100644
--- a/src/game/ScriptCalls.cpp
+++ b/src/game/ScriptCalls.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -78,8 +78,10 @@ bool LoadScriptingModule(char const* libName)
||!(testScript->scriptAreaTrigger =(scriptCallAreaTrigger )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"AreaTrigger" ))
||!(testScript->ItemQuestAccept =(scriptCallItemQuestAccept )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ItemQuestAccept" ))
||!(testScript->GOQuestAccept =(scriptCallGOQuestAccept )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"GOQuestAccept" ))
- ||!(testScript->ReceiveEmote =(scriptCallReceiveEmote )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ReceiveEmote" ))
||!(testScript->ItemUse =(scriptCallItemUse )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ItemUse" ))
+ ||!(testScript->EffectDummyGameObj =(scriptCallEffectDummyGameObj )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyGameObj" ))
+ ||!(testScript->EffectDummyCreature =(scriptCallEffectDummyCreature )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyCreature" ))
+ ||!(testScript->EffectDummyItem =(scriptCallEffectDummyItem )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyItem" ))
||!(testScript->GetAI =(scriptCallGetAI )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"GetAI" ))
||!(testScript->CreateInstanceData =(scriptCallCreateInstanceData )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"CreateInstanceData" ))
)
@@ -90,7 +92,8 @@ bool LoadScriptingModule(char const* libName)
return false;
}
- printf("Scripts Library %s was successfully loaded.\n",name.c_str());
+ sLog.outString();
+ sLog.outString( ">>> Scripts Library %s was successfully loaded.\n", name.c_str() );
//heh we are still there :P we have a valid library
//we reload script
diff --git a/src/game/ScriptCalls.h b/src/game/ScriptCalls.h
index 68f6c5dac01..4e23f9f576d 100644
--- a/src/game/ScriptCalls.h
+++ b/src/game/ScriptCalls.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,8 +58,10 @@ typedef bool(TRINITY_IMPORT * scriptCallAreaTrigger)( Player *player, AreaTrigge
typedef bool(TRINITY_IMPORT * scriptCallItemQuestAccept)(Player *player, Item *, Quest const*);
typedef bool(TRINITY_IMPORT * scriptCallGOQuestAccept)(Player *player, GameObject *, Quest const*);
typedef bool(TRINITY_IMPORT * scriptCallGOChooseReward)(Player *player, GameObject *, Quest const*, uint32 opt );
-typedef bool(TRINITY_IMPORT * scriptCallReceiveEmote) ( Player *player, Creature *_Creature, uint32 emote );
typedef bool(TRINITY_IMPORT * scriptCallItemUse) (Player *player, Item *_Item, SpellCastTargets const& targets);
+typedef bool(TRINITY_IMPORT * scriptCallEffectDummyGameObj) (Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget);
+typedef bool(TRINITY_IMPORT * scriptCallEffectDummyCreature) (Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget);
+typedef bool(TRINITY_IMPORT * scriptCallEffectDummyItem) (Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget);
typedef CreatureAI* (TRINITY_IMPORT * scriptCallGetAI) ( Creature *_Creature );
typedef InstanceData* (TRINITY_IMPORT * scriptCallCreateInstanceData) (Map *map);
@@ -86,8 +88,10 @@ typedef struct
scriptCallAreaTrigger scriptAreaTrigger;
scriptCallItemQuestAccept ItemQuestAccept;
scriptCallGOQuestAccept GOQuestAccept;
- scriptCallReceiveEmote ReceiveEmote;
scriptCallItemUse ItemUse;
+ scriptCallEffectDummyGameObj EffectDummyGameObj;
+ scriptCallEffectDummyCreature EffectDummyCreature;
+ scriptCallEffectDummyItem EffectDummyItem;
scriptCallGetAI GetAI;
scriptCallCreateInstanceData CreateInstanceData;
diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h
index 15009304c70..052d98f56c8 100644
--- a/src/game/SharedDefines.h
+++ b/src/game/SharedDefines.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -88,7 +88,8 @@ enum Classes
#define CLASSMASK_ALL_PLAYABLE \
((1<<(CLASS_WARRIOR-1))|(1<<(CLASS_PALADIN-1))|(1<<(CLASS_HUNTER-1))| \
(1<<(CLASS_ROGUE-1)) |(1<<(CLASS_PRIEST-1)) |(1<<(CLASS_SHAMAN-1))| \
- (1<<(CLASS_MAGE-1)) |(1<<(CLASS_WARLOCK-1))|(1<<(CLASS_DRUID-1)) )
+ (1<<(CLASS_MAGE-1)) |(1<<(CLASS_WARLOCK-1))|(1<<(CLASS_DRUID-1)) | \
+ (1<<(CLASS_DEATH_KNIGHT-1)) )
#define CLASSMASK_WAND_USERS ((1<<(CLASS_PRIEST-1))|(1<<(CLASS_MAGE-1))|(1<<(CLASS_WARLOCK-1)))
@@ -134,12 +135,13 @@ enum Powers
POWER_FOCUS = 2,
POWER_ENERGY = 3,
POWER_HAPPINESS = 4,
- POWER_RUNES = 5,
+ POWER_RUNE = 5,
+ POWER_RUNIC_POWER = 6,
+ MAX_POWERS = 7,
+ POWER_ALL = 127, // default for class?
POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value)
};
-#define MAX_POWERS 5 // not count POWER_RUNES for now
-
enum SpellSchools
{
SPELL_SCHOOL_NORMAL = 0,
@@ -199,10 +201,11 @@ enum ItemQualities
ITEM_QUALITY_RARE = 3, //BLUE
ITEM_QUALITY_EPIC = 4, //PURPLE
ITEM_QUALITY_LEGENDARY = 5, //ORANGE
- ITEM_QUALITY_ARTIFACT = 6 //LIGHT YELLOW
+ ITEM_QUALITY_ARTIFACT = 6, //LIGHT YELLOW
+ ITEM_QUALITY_HEIRLOOM = 7
};
-#define MAX_ITEM_QUALITY 7
+#define MAX_ITEM_QUALITY 8
enum SpellCategory
{
@@ -215,16 +218,16 @@ enum SpellCategory
// ***********************************
#define SPELL_ATTR_UNK0 0x00000001 // 0
-#define SPELL_ATTR_RANGED 0x00000002 // 1 All ranged abilities have this flag
-#define SPELL_ATTR_ON_NEXT_SWING_1 0x00000004 // 2 on next swing
-#define SPELL_ATTR_UNK3 0x00000008 // 3 not set in 2.4.2
+#define SPELL_ATTR_REQ_AMMO 0x00000002 // 1
+#define SPELL_ATTR_ON_NEXT_SWING 0x00000004 // 2 on next swing
+#define SPELL_ATTR_UNK3 0x00000008 // 3 not set in 3.0.3
#define SPELL_ATTR_UNK4 0x00000010 // 4
#define SPELL_ATTR_UNK5 0x00000020 // 5 trade spells?
#define SPELL_ATTR_PASSIVE 0x00000040 // 6 Passive spell
#define SPELL_ATTR_UNK7 0x00000080 // 7 visible?
#define SPELL_ATTR_UNK8 0x00000100 // 8
#define SPELL_ATTR_UNK9 0x00000200 // 9
-#define SPELL_ATTR_ON_NEXT_SWING_2 0x00000400 // 10 on next swing 2
+#define SPELL_ATTR_UNK10 0x00000400 // 10 on next swing 2
#define SPELL_ATTR_UNK11 0x00000800 // 11
#define SPELL_ATTR_DAYTIME_ONLY 0x00001000 // 12 only useable at daytime, not set in 2.4.2
#define SPELL_ATTR_NIGHT_ONLY 0x00002000 // 13 only useable at night, not set in 2.4.2
@@ -237,33 +240,32 @@ enum SpellCategory
#define SPELL_ATTR_STOP_ATTACK_TARGET 0x00100000 // 20 Stop attack after use this spell (and not begin attack if use)
#define SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK 0x00200000 // 21 Cannot be dodged/parried/blocked
#define SPELL_ATTR_UNK22 0x00400000 // 22 shoot spells
-#define SPELL_ATTR_UNK23 0x00800000 // 23 castable while dead?
+#define SPELL_ATTR_CASTABLE_WHILE_DEAD 0x00800000 // 23 castable while dead?
#define SPELL_ATTR_CASTABLE_WHILE_MOUNTED 0x01000000 // 24 castable while mounted
#define SPELL_ATTR_DISABLED_WHILE_ACTIVE 0x02000000 // 25 Activate and start cooldown after aura fade or remove summoned creature or go
-#define SPELL_ATTR_UNK26 0x04000000 // 26 Aura ignore immune?
+#define SPELL_ATTR_UNK26 0x04000000 // 26 Aura
#define SPELL_ATTR_CASTABLE_WHILE_SITTING 0x08000000 // 27 castable while sitting
#define SPELL_ATTR_CANT_USED_IN_COMBAT 0x10000000 // 28 Cannot be used in combat
#define SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY 0x20000000 // 29 unaffected by invulnerability (hmm possible not...)
#define SPELL_ATTR_BREAKABLE_BY_DAMAGE 0x40000000 // 30 breakable by damage?
#define SPELL_ATTR_CANT_CANCEL 0x80000000 // 31 positive aura can't be canceled
-
-#define SPELL_ATTR_EX_UNK0 0x00000001 // 0
+#define SPELL_ATTR_EX_DISMISS_PET 0x00000001 // 0 dismiss pet and not allow to summon new one?
#define SPELL_ATTR_EX_DRAIN_ALL_POWER 0x00000002 // 1 use all power (Only paladin Lay of Hands and Bunyanize)
-#define SPELL_ATTR_EX_CHANNELED_1 0x00000004 // 2 channeled 1
+#define SPELL_ATTR_EX_CHANNELED_1 0x00000004 // 2 channeled target
#define SPELL_ATTR_EX_UNK3 0x00000008 // 3
-#define SPELL_ATTR_EX_UNK4 0x00000010 // 4
+#define SPELL_ATTR_EX_UNK4 0x00000010 // 4 stealth and whirlwind
#define SPELL_ATTR_EX_NOT_BREAK_STEALTH 0x00000020 // 5 Not break stealth
-#define SPELL_ATTR_EX_CHANNELED_2 0x00000040 // 6 channeled 2
+#define SPELL_ATTR_EX_CHANNELED_2 0x00000040 // 6 channeled self
#define SPELL_ATTR_EX_NEGATIVE 0x00000080 // 7
#define SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET 0x00000100 // 8 Spell req target not to be in combat state
-#define SPELL_ATTR_EX_UNK9 0x00000200 // 9
-#define SPELL_ATTR_EX_UNK10 0x00000400 // 10
-#define SPELL_ATTR_EX_UNK11 0x00000800 // 11
+#define SPELL_ATTR_EX_UNK9 0x00000200 // 9 melee spells
+#define SPELL_ATTR_EX_NO_INITIAL_AGGRO 0x00000400 // 10 no generates threat on cast 100%?
+#define SPELL_ATTR_EX_UNK11 0x00000800 // 11 aura
#define SPELL_ATTR_EX_UNK12 0x00001000 // 12
#define SPELL_ATTR_EX_UNK13 0x00002000 // 13
#define SPELL_ATTR_EX_UNK14 0x00004000 // 14
#define SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY 0x00008000 // 15 remove auras on immunity
-#define SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE 0x00010000 // 16 unaffected by school immunity
+#define SPELL_ATTR_EX_UNK16 0x00010000 // 16 on immuniy
#define SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET 0x00020000 // 17
#define SPELL_ATTR_EX_UNK18 0x00040000 // 18
#define SPELL_ATTR_EX_UNK19 0x00080000 // 19
@@ -272,7 +274,7 @@ enum SpellCategory
#define SPELL_ATTR_EX_REQ_COMBO_POINTS2 0x00400000 // 22 Req combo points on target
#define SPELL_ATTR_EX_UNK23 0x00800000 // 23
#define SPELL_ATTR_EX_UNK24 0x01000000 // 24 Req fishing pole??
-#define SPELL_ATTR_EX_UNK25 0x02000000 // 25 not set in 2.4.2
+#define SPELL_ATTR_EX_UNK25 0x02000000 // 25
#define SPELL_ATTR_EX_UNK26 0x04000000 // 26
#define SPELL_ATTR_EX_UNK27 0x08000000 // 27
#define SPELL_ATTR_EX_UNK28 0x10000000 // 28
@@ -282,35 +284,35 @@ enum SpellCategory
#define SPELL_ATTR_EX2_UNK0 0x00000001 // 0
#define SPELL_ATTR_EX2_UNK1 0x00000002 // 1
-#define SPELL_ATTR_EX2_UNK2 0x00000004 // 2 boss spells?
+#define SPELL_ATTR_EX2_CANT_REFLECTED 0x00000004 // 2 ? used for detect can or not spell reflected
#define SPELL_ATTR_EX2_UNK3 0x00000008 // 3
#define SPELL_ATTR_EX2_UNK4 0x00000010 // 4
-#define SPELL_ATTR_EX2_UNK5 0x00000020 // 5
+#define SPELL_ATTR_EX2_AUTOREPEAT_FLAG 0x00000020 // 5
#define SPELL_ATTR_EX2_UNK6 0x00000040 // 6
#define SPELL_ATTR_EX2_UNK7 0x00000080 // 7
-#define SPELL_ATTR_EX2_UNK8 0x00000100 // 8 not set in 2.4.2
+#define SPELL_ATTR_EX2_UNK8 0x00000100 // 8 not set in 3.0.3
#define SPELL_ATTR_EX2_UNK9 0x00000200 // 9
#define SPELL_ATTR_EX2_UNK10 0x00000400 // 10
#define SPELL_ATTR_EX2_HEALTH_FUNNEL 0x00000800 // 11
#define SPELL_ATTR_EX2_UNK12 0x00001000 // 12
-#define SPELL_ATTR_EX2_UNK13 0x00002000 // 13
+#define SPELL_ATTR_EX2_UNK13 0x00002000 // 13 Items enchanted by spells with this flag preserve the enchant to arenas
#define SPELL_ATTR_EX2_UNK14 0x00004000 // 14
-#define SPELL_ATTR_EX2_UNK15 0x00008000 // 15 not set in 2.4.2
+#define SPELL_ATTR_EX2_UNK15 0x00008000 // 15 not set in 3.0.3
#define SPELL_ATTR_EX2_TAME_BEAST 0x00010000 // 16
#define SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT 0x00020000 // 17 Hunters Shot and Stings only have this flag
#define SPELL_ATTR_EX2_UNK18 0x00040000 // 18 Only Revive pet - possible req dead pet
#define SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT 0x00080000 // 19 does not necessarly need shapeshift
#define SPELL_ATTR_EX2_UNK20 0x00100000 // 20
-#define SPELL_ATTR_EX2_UNK21 0x00200000 // 21
-#define SPELL_ATTR_EX2_UNK22 0x00400000 // 22
+#define SPELL_ATTR_EX2_DAMAGE_REDUCED_SHIELD 0x00200000 // 21 for ice blocks, pala immunity buffs, priest absorb shields, but used also for other spells -> not sure!
+#define SPELL_ATTR_EX2_UNK22 0x00400000 // 22 spell can trigger even if triggered
#define SPELL_ATTR_EX2_UNK23 0x00800000 // 23 Only mage Arcane Concentration have this flag
#define SPELL_ATTR_EX2_UNK24 0x01000000 // 24
#define SPELL_ATTR_EX2_UNK25 0x02000000 // 25
#define SPELL_ATTR_EX2_UNK26 0x04000000 // 26 unaffected by school immunity
#define SPELL_ATTR_EX2_UNK27 0x08000000 // 27
-#define SPELL_ATTR_EX2_UNK28 0x10000000 // 28
+#define SPELL_ATTR_EX2_UNK28 0x10000000 // 28 no breaks stealth if it fails??
#define SPELL_ATTR_EX2_CANT_CRIT 0x20000000 // 29 Spell can't crit
-#define SPELL_ATTR_EX2_UNK30 0x40000000 // 30
+#define SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER 0x40000000 // 30 spell can trigger even if triggered
#define SPELL_ATTR_EX2_FOOD 0x80000000 // 31 food, well-fed, and a few others
#define SPELL_ATTR_EX3_UNK0 0x00000001 // 0
@@ -322,24 +324,24 @@ enum SpellCategory
#define SPELL_ATTR_EX3_UNK6 0x00000040 // 6
#define SPELL_ATTR_EX3_UNK7 0x00000080 // 7
#define SPELL_ATTR_EX3_PLAYERS_ONLY 0x00000100 // 8 Player only?
-#define SPELL_ATTR_EX3_UNK9 0x00000200 // 9
+#define SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2 0x00000200 // 9 triggered from effect?
#define SPELL_ATTR_EX3_MAIN_HAND 0x00000400 // 10 Main hand weapon required
#define SPELL_ATTR_EX3_BATTLEGROUND 0x00000800 // 11 Can casted only on battleground
#define SPELL_ATTR_EX3_UNK12 0x00001000 // 12
#define SPELL_ATTR_EX3_UNK13 0x00002000 // 13
#define SPELL_ATTR_EX3_UNK14 0x00004000 // 14 "Honorless Target" only this spells have this flag
#define SPELL_ATTR_EX3_UNK15 0x00008000 // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag
-#define SPELL_ATTR_EX3_UNK16 0x00010000 // 16
-#define SPELL_ATTR_EX3_NO_INITIAL_AGGRO 0x00020000 // 17 no initial aggro
+#define SPELL_ATTR_EX3_UNK16 0x00010000 // 16 no triggers effects that trigger on casting a spell??
+#define SPELL_ATTR_EX3_UNK17 0x00020000 // 17 no triggers effects that trigger on casting a spell??
#define SPELL_ATTR_EX3_UNK18 0x00040000 // 18
-#define SPELL_ATTR_EX3_UNK19 0x00080000 // 19
+#define SPELL_ATTR_EX3_UNK19 0x00080000 // 19 spells triggered by spell with this flag can't proc caster auras and can proc from triggered (swings too - 20178)
#define SPELL_ATTR_EX3_DEATH_PERSISTENT 0x00100000 // 20 Death persistent spells
#define SPELL_ATTR_EX3_UNK21 0x00200000 // 21
#define SPELL_ATTR_EX3_REQ_WAND 0x00400000 // 22 Req wand
#define SPELL_ATTR_EX3_UNK23 0x00800000 // 23
#define SPELL_ATTR_EX3_REQ_OFFHAND 0x01000000 // 24 Req offhand weapon
-#define SPELL_ATTR_EX3_UNK25 0x02000000 // 25
-#define SPELL_ATTR_EX3_UNK26 0x04000000 // 26
+#define SPELL_ATTR_EX3_UNK25 0x02000000 // 25 no cause spell pushback ?
+#define SPELL_ATTR_EX3_CAN_PROC_TRIGGERED 0x04000000 // 26
#define SPELL_ATTR_EX3_UNK27 0x08000000 // 27
#define SPELL_ATTR_EX3_UNK28 0x10000000 // 28
#define SPELL_ATTR_EX3_UNK29 0x20000000 // 29
@@ -350,9 +352,9 @@ enum SpellCategory
#define SPELL_ATTR_EX4_UNK1 0x00000002 // 1 proc on finishing move?
#define SPELL_ATTR_EX4_UNK2 0x00000004 // 2
#define SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST 0x00000008 // 3
-#define SPELL_ATTR_EX4_UNK4 0x00000010 // 4
+#define SPELL_ATTR_EX4_UNK4 0x00000010 // 4 This will no longer cause guards to attack on use??
#define SPELL_ATTR_EX4_UNK5 0x00000020 // 5
-#define SPELL_ATTR_EX4_UNK6 0x00000040 // 6
+#define SPELL_ATTR_EX4_NOT_STEALABLE 0x00000040 // 6 although such auras might be dispellable, they cannot be stolen
#define SPELL_ATTR_EX4_UNK7 0x00000080 // 7
#define SPELL_ATTR_EX4_UNK8 0x00000100 // 8
#define SPELL_ATTR_EX4_UNK9 0x00000200 // 9
@@ -388,7 +390,7 @@ enum SpellCategory
#define SPELL_ATTR_EX5_UNK6 0x00000040 // 6
#define SPELL_ATTR_EX5_UNK7 0x00000080 // 7
#define SPELL_ATTR_EX5_UNK8 0x00000100 // 8
-#define SPELL_ATTR_EX5_UNK9 0x00000200 // 9
+#define SPELL_ATTR_EX5_START_PERIODIC_AT_APPLY 0x00000200 // 9 begin periodic tick at aura apply
#define SPELL_ATTR_EX5_UNK10 0x00000400 // 10
#define SPELL_ATTR_EX5_UNK11 0x00000800 // 11
#define SPELL_ATTR_EX5_UNK12 0x00001000 // 12
@@ -413,37 +415,39 @@ enum SpellCategory
#define SPELL_ATTR_EX5_UNK31 0x80000000 // 31 Forces all nearby enemies to focus attacks caster
#define SPELL_ATTR_EX6_UNK0 0x00000001 // 0 Only Move spell have this flag
-#define SPELL_ATTR_EX6_UNK1 0x00000002 // 1 not set in 2.4.2
+#define SPELL_ATTR_EX6_UNK1 0x00000002 // 1 not set in 3.0.3
#define SPELL_ATTR_EX6_UNK2 0x00000004 // 2
#define SPELL_ATTR_EX6_UNK3 0x00000008 // 3
-#define SPELL_ATTR_EX6_UNK4 0x00000010 // 4 not set in 2.4.2
+#define SPELL_ATTR_EX6_UNK4 0x00000010 // 4
#define SPELL_ATTR_EX6_UNK5 0x00000020 // 5
#define SPELL_ATTR_EX6_UNK6 0x00000040 // 6
#define SPELL_ATTR_EX6_UNK7 0x00000080 // 7
#define SPELL_ATTR_EX6_UNK8 0x00000100 // 8
-#define SPELL_ATTR_EX6_UNK9 0x00000200 // 9 not set in 2.4.2
+#define SPELL_ATTR_EX6_UNK9 0x00000200 // 9
#define SPELL_ATTR_EX6_UNK10 0x00000400 // 10
#define SPELL_ATTR_EX6_UNK11 0x00000800 // 11
-#define SPELL_ATTR_EX6_UNK12 0x00001000 // 12 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK13 0x00002000 // 13 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK14 0x00004000 // 14 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK15 0x00008000 // 15 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK16 0x00010000 // 16 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK17 0x00020000 // 17 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK18 0x00040000 // 18 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK19 0x00080000 // 19 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK20 0x00100000 // 20 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK21 0x00200000 // 21 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK22 0x00400000 // 22 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK23 0x00800000 // 23 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK24 0x01000000 // 24 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK25 0x02000000 // 25 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK26 0x04000000 // 26 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK27 0x08000000 // 27 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK28 0x10000000 // 28 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK29 0x20000000 // 29 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK30 0x40000000 // 30 not set in 2.4.2
-#define SPELL_ATTR_EX6_UNK31 0x80000000 // 31 not set in 2.4.2
+#define SPELL_ATTR_EX6_UNK12 0x00001000 // 12
+#define SPELL_ATTR_EX6_UNK13 0x00002000 // 13
+#define SPELL_ATTR_EX6_UNK14 0x00004000 // 14
+#define SPELL_ATTR_EX6_UNK15 0x00008000 // 15 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK16 0x00010000 // 16
+#define SPELL_ATTR_EX6_UNK17 0x00020000 // 17
+#define SPELL_ATTR_EX6_UNK18 0x00040000 // 18
+#define SPELL_ATTR_EX6_UNK19 0x00080000 // 19
+#define SPELL_ATTR_EX6_UNK20 0x00100000 // 20
+#define SPELL_ATTR_EX6_UNK21 0x00200000 // 21
+#define SPELL_ATTR_EX6_UNK22 0x00400000 // 22
+#define SPELL_ATTR_EX6_UNK23 0x00800000 // 23 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK24 0x01000000 // 24 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK25 0x02000000 // 25 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK26 0x04000000 // 26 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK27 0x08000000 // 27 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK28 0x10000000 // 28 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK29 0x20000000 // 29 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK30 0x40000000 // 30 not set in 3.0.3
+#define SPELL_ATTR_EX6_UNK31 0x80000000 // 31 not set in 3.0.3
+
+#define MAX_GLYPH_SLOT_INDEX 6
enum SheathTypes
{
@@ -562,11 +566,11 @@ enum SpellEffects
SPELL_EFFECT_DISPEL = 38,
SPELL_EFFECT_LANGUAGE = 39,
SPELL_EFFECT_DUAL_WIELD = 40,
- SPELL_EFFECT_SUMMON_WILD = 41,
- SPELL_EFFECT_SUMMON_GUARDIAN = 42,
+ SPELL_EFFECT_JUMP = 41,
+ SPELL_EFFECT_JUMP2 = 42,
SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER= 43,
SPELL_EFFECT_SKILL_STEP = 44,
- SPELL_EFFECT_UNDEFINED_45 = 45,
+ SPELL_EFFECT_ADD_HONOR = 45,
SPELL_EFFECT_SPAWN = 46,
SPELL_EFFECT_TRADE_SKILL = 47,
SPELL_EFFECT_STEALTH = 48,
@@ -586,16 +590,16 @@ enum SpellEffects
SPELL_EFFECT_POWER_BURN = 62,
SPELL_EFFECT_THREAT = 63,
SPELL_EFFECT_TRIGGER_SPELL = 64,
- SPELL_EFFECT_HEALTH_FUNNEL = 65,
- SPELL_EFFECT_POWER_FUNNEL = 66,
+ SPELL_EFFECT_APPLY_AREA_AURA_RAID = 65,
+ SPELL_EFFECT_CREATE_MANA_GEM = 66,
SPELL_EFFECT_HEAL_MAX_HEALTH = 67,
SPELL_EFFECT_INTERRUPT_CAST = 68,
SPELL_EFFECT_DISTRACT = 69,
SPELL_EFFECT_PULL = 70,
SPELL_EFFECT_PICKPOCKET = 71,
SPELL_EFFECT_ADD_FARSIGHT = 72,
- SPELL_EFFECT_SUMMON_POSSESSED = 73,
- SPELL_EFFECT_SUMMON_TOTEM = 74,
+ SPELL_EFFECT_UNTRAIN_TALENTS = 73,
+ SPELL_EFFECT_APPLY_GLYPH = 74,
SPELL_EFFECT_HEAL_MECHANICAL = 75,
SPELL_EFFECT_SUMMON_OBJECT_WILD = 76,
SPELL_EFFECT_SCRIPT_EFFECT = 77,
@@ -608,17 +612,17 @@ enum SpellEffects
SPELL_EFFECT_STUCK = 84,
SPELL_EFFECT_SUMMON_PLAYER = 85,
SPELL_EFFECT_ACTIVATE_OBJECT = 86,
- SPELL_EFFECT_SUMMON_TOTEM_SLOT1 = 87,
- SPELL_EFFECT_SUMMON_TOTEM_SLOT2 = 88,
- SPELL_EFFECT_SUMMON_TOTEM_SLOT3 = 89,
- SPELL_EFFECT_SUMMON_TOTEM_SLOT4 = 90,
+ SPELL_EFFECT_WMO_DAMAGE = 87,
+ SPELL_EFFECT_WMO_REPAIR = 88,
+ SPELL_EFFECT_WMO_CHANGE = 89,
+ SPELL_EFFECT_KILL_CREDIT = 90,
SPELL_EFFECT_THREAT_ALL = 91,
SPELL_EFFECT_ENCHANT_HELD_ITEM = 92,
SPELL_EFFECT_SUMMON_PHANTASM = 93, //unused
SPELL_EFFECT_SELF_RESURRECT = 94,
SPELL_EFFECT_SKINNING = 95,
SPELL_EFFECT_CHARGE = 96,
- SPELL_EFFECT_SUMMON_CRITTER = 97,
+ SPELL_EFFECT_97 = 97,
SPELL_EFFECT_KNOCK_BACK = 98,
SPELL_EFFECT_DISENCHANT = 99,
SPELL_EFFECT_INEBRIATE = 100,
@@ -633,7 +637,7 @@ enum SpellEffects
SPELL_EFFECT_SUMMON_DEAD_PET = 109,
SPELL_EFFECT_DESTROY_ALL_TOTEMS = 110,
SPELL_EFFECT_DURABILITY_DAMAGE = 111,
- SPELL_EFFECT_SUMMON_DEMON = 112,
+ SPELL_EFFECT_112 = 112,
SPELL_EFFECT_RESURRECT_NEW = 113,
SPELL_EFFECT_ATTACK_ME = 114,
SPELL_EFFECT_DURABILITY_DAMAGE_PCT = 115,
@@ -655,19 +659,19 @@ enum SpellEffects
SPELL_EFFECT_131 = 131,
SPELL_EFFECT_132 = 132,
SPELL_EFFECT_UNLEARN_SPECIALIZATION = 133,
- SPELL_EFFECT_KILL_CREDIT = 134,
+ SPELL_EFFECT_KILL_CREDIT2 = 134,
SPELL_EFFECT_135 = 135,
SPELL_EFFECT_HEAL_PCT = 136,
SPELL_EFFECT_ENERGIZE_PCT = 137,
SPELL_EFFECT_138 = 138,
- SPELL_EFFECT_139 = 139,
+ SPELL_EFFECT_CLEAR_QUEST = 139,
SPELL_EFFECT_FORCE_CAST = 140,
SPELL_EFFECT_141 = 141,
SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE = 142,
SPELL_EFFECT_APPLY_AREA_AURA_OWNER = 143,
SPELL_EFFECT_KNOCK_BACK_2 = 144,
SPELL_EFFECT_145 = 145,
- SPELL_EFFECT_146 = 146,
+ SPELL_EFFECT_ACTIVATE_RUNE = 146,
SPELL_EFFECT_QUEST_FAIL = 147,
SPELL_EFFECT_148 = 148,
SPELL_EFFECT_149 = 149,
@@ -675,7 +679,201 @@ enum SpellEffects
SPELL_EFFECT_TRIGGER_SPELL_2 = 151,
SPELL_EFFECT_152 = 152,
SPELL_EFFECT_153 = 153,
- TOTAL_SPELL_EFFECTS = 154
+ SPELL_EFFECT_154 = 154,
+ SPELL_EFFECT_TITAN_GRIP = 155,
+ SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC = 156,
+ SPELL_EFFECT_CREATE_ITEM_2 = 157,
+ SPELL_EFFECT_MILLING = 158,
+ SPELL_EFFECT_ALLOW_RENAME_PET = 159,
+ TOTAL_SPELL_EFFECTS = 160
+};
+
+enum SpellCastResult
+{
+ SPELL_FAILED_AFFECTING_COMBAT = 0,
+ SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1,
+ SPELL_FAILED_ALREADY_AT_FULL_MANA = 2,
+ SPELL_FAILED_ALREADY_AT_FULL_POWER = 3,
+ SPELL_FAILED_ALREADY_BEING_TAMED = 4,
+ SPELL_FAILED_ALREADY_HAVE_CHARM = 5,
+ SPELL_FAILED_ALREADY_HAVE_SUMMON = 6,
+ SPELL_FAILED_ALREADY_OPEN = 7,
+ SPELL_FAILED_AURA_BOUNCED = 8,
+ SPELL_FAILED_AUTOTRACK_INTERRUPTED = 9,
+ SPELL_FAILED_BAD_IMPLICIT_TARGETS = 10,
+ SPELL_FAILED_BAD_TARGETS = 11,
+ SPELL_FAILED_CANT_BE_CHARMED = 12,
+ SPELL_FAILED_CANT_BE_DISENCHANTED = 13,
+ SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 14,
+ SPELL_FAILED_CANT_BE_MILLED = 15,
+ SPELL_FAILED_CANT_BE_PROSPECTED = 16,
+ SPELL_FAILED_CANT_CAST_ON_TAPPED = 17,
+ SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 18,
+ SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 19,
+ SPELL_FAILED_CANT_STEALTH = 20,
+ SPELL_FAILED_CASTER_AURASTATE = 21,
+ SPELL_FAILED_CASTER_DEAD = 22,
+ SPELL_FAILED_CHARMED = 23,
+ SPELL_FAILED_CHEST_IN_USE = 24,
+ SPELL_FAILED_CONFUSED = 25,
+ SPELL_FAILED_DONT_REPORT = 26,
+ SPELL_FAILED_EQUIPPED_ITEM = 27,
+ SPELL_FAILED_EQUIPPED_ITEM_CLASS = 28,
+ SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 29,
+ SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 30,
+ SPELL_FAILED_ERROR = 31,
+ SPELL_FAILED_FIZZLE = 32,
+ SPELL_FAILED_FLEEING = 33,
+ SPELL_FAILED_FOOD_LOWLEVEL = 34,
+ SPELL_FAILED_HIGHLEVEL = 35,
+ SPELL_FAILED_HUNGER_SATIATED = 36,
+ SPELL_FAILED_IMMUNE = 37,
+ SPELL_FAILED_INCORRECT_AREA = 38,
+ SPELL_FAILED_INTERRUPTED = 39,
+ SPELL_FAILED_INTERRUPTED_COMBAT = 40,
+ SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 41,
+ SPELL_FAILED_ITEM_GONE = 42,
+ SPELL_FAILED_ITEM_NOT_FOUND = 43,
+ SPELL_FAILED_ITEM_NOT_READY = 44,
+ SPELL_FAILED_LEVEL_REQUIREMENT = 45,
+ SPELL_FAILED_LINE_OF_SIGHT = 46,
+ SPELL_FAILED_LOWLEVEL = 47,
+ SPELL_FAILED_LOW_CASTLEVEL = 48,
+ SPELL_FAILED_MAINHAND_EMPTY = 49,
+ SPELL_FAILED_MOVING = 50,
+ SPELL_FAILED_NEED_AMMO = 51,
+ SPELL_FAILED_NEED_AMMO_POUCH = 52,
+ SPELL_FAILED_NEED_EXOTIC_AMMO = 53,
+ SPELL_FAILED_NEED_MORE_ITEMS = 54,
+ SPELL_FAILED_NOPATH = 55,
+ SPELL_FAILED_NOT_BEHIND = 56,
+ SPELL_FAILED_NOT_FISHABLE = 57,
+ SPELL_FAILED_NOT_FLYING = 58,
+ SPELL_FAILED_NOT_HERE = 59,
+ SPELL_FAILED_NOT_INFRONT = 60,
+ SPELL_FAILED_NOT_IN_CONTROL = 61,
+ SPELL_FAILED_NOT_KNOWN = 62,
+ SPELL_FAILED_NOT_MOUNTED = 63,
+ SPELL_FAILED_NOT_ON_TAXI = 64,
+ SPELL_FAILED_NOT_ON_TRANSPORT = 65,
+ SPELL_FAILED_NOT_READY = 66,
+ SPELL_FAILED_NOT_SHAPESHIFT = 67,
+ SPELL_FAILED_NOT_STANDING = 68,
+ SPELL_FAILED_NOT_TRADEABLE = 69,
+ SPELL_FAILED_NOT_TRADING = 70,
+ SPELL_FAILED_NOT_UNSHEATHED = 71,
+ SPELL_FAILED_NOT_WHILE_GHOST = 72,
+ SPELL_FAILED_NOT_WHILE_LOOTING = 73,
+ SPELL_FAILED_NO_AMMO = 74,
+ SPELL_FAILED_NO_CHARGES_REMAIN = 75,
+ SPELL_FAILED_NO_CHAMPION = 76,
+ SPELL_FAILED_NO_COMBO_POINTS = 77,
+ SPELL_FAILED_NO_DUELING = 78,
+ SPELL_FAILED_NO_ENDURANCE = 79,
+ SPELL_FAILED_NO_FISH = 80,
+ SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 81,
+ SPELL_FAILED_NO_MOUNTS_ALLOWED = 82,
+ SPELL_FAILED_NO_PET = 83,
+ SPELL_FAILED_NO_POWER = 84,
+ SPELL_FAILED_NOTHING_TO_DISPEL = 85,
+ SPELL_FAILED_NOTHING_TO_STEAL = 86,
+ SPELL_FAILED_ONLY_ABOVEWATER = 87,
+ SPELL_FAILED_ONLY_DAYTIME = 88,
+ SPELL_FAILED_ONLY_INDOORS = 89,
+ SPELL_FAILED_ONLY_MOUNTED = 90,
+ SPELL_FAILED_ONLY_NIGHTTIME = 91,
+ SPELL_FAILED_ONLY_OUTDOORS = 92,
+ SPELL_FAILED_ONLY_SHAPESHIFT = 93,
+ SPELL_FAILED_ONLY_STEALTHED = 94,
+ SPELL_FAILED_ONLY_UNDERWATER = 95,
+ SPELL_FAILED_OUT_OF_RANGE = 96,
+ SPELL_FAILED_PACIFIED = 97,
+ SPELL_FAILED_POSSESSED = 98,
+ SPELL_FAILED_REAGENTS = 99,
+ SPELL_FAILED_REQUIRES_AREA = 100,
+ SPELL_FAILED_REQUIRES_SPELL_FOCUS = 101,
+ SPELL_FAILED_ROOTED = 102,
+ SPELL_FAILED_SILENCED = 103,
+ SPELL_FAILED_SPELL_IN_PROGRESS = 104,
+ SPELL_FAILED_SPELL_LEARNED = 105,
+ SPELL_FAILED_SPELL_UNAVAILABLE = 106,
+ SPELL_FAILED_STUNNED = 107,
+ SPELL_FAILED_TARGETS_DEAD = 108,
+ SPELL_FAILED_TARGET_AFFECTING_COMBAT = 109,
+ SPELL_FAILED_TARGET_AURASTATE = 110,
+ SPELL_FAILED_TARGET_DUELING = 111,
+ SPELL_FAILED_TARGET_ENEMY = 112,
+ SPELL_FAILED_TARGET_ENRAGED = 113,
+ SPELL_FAILED_TARGET_FRIENDLY = 114,
+ SPELL_FAILED_TARGET_IN_COMBAT = 115,
+ SPELL_FAILED_TARGET_IS_PLAYER = 116,
+ SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 117,
+ SPELL_FAILED_TARGET_NOT_DEAD = 118,
+ SPELL_FAILED_TARGET_NOT_IN_PARTY = 119,
+ SPELL_FAILED_TARGET_NOT_LOOTED = 120,
+ SPELL_FAILED_TARGET_NOT_PLAYER = 121,
+ SPELL_FAILED_TARGET_NO_POCKETS = 122,
+ SPELL_FAILED_TARGET_NO_WEAPONS = 123,
+ SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 124,
+ SPELL_FAILED_TARGET_UNSKINNABLE = 125,
+ SPELL_FAILED_THIRST_SATIATED = 126,
+ SPELL_FAILED_TOO_CLOSE = 127,
+ SPELL_FAILED_TOO_MANY_OF_ITEM = 128,
+ SPELL_FAILED_TOTEM_CATEGORY = 129,
+ SPELL_FAILED_TOTEMS = 130,
+ SPELL_FAILED_TRY_AGAIN = 131,
+ SPELL_FAILED_UNIT_NOT_BEHIND = 132,
+ SPELL_FAILED_UNIT_NOT_INFRONT = 133,
+ SPELL_FAILED_WRONG_PET_FOOD = 134,
+ SPELL_FAILED_NOT_WHILE_FATIGUED = 135,
+ SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 136,
+ SPELL_FAILED_NOT_WHILE_TRADING = 137,
+ SPELL_FAILED_TARGET_NOT_IN_RAID = 138,
+ SPELL_FAILED_TARGET_FREEFORALL = 139,
+ SPELL_FAILED_NO_EDIBLE_CORPSES = 140,
+ SPELL_FAILED_ONLY_BATTLEGROUNDS = 141,
+ SPELL_FAILED_TARGET_NOT_GHOST = 142,
+ SPELL_FAILED_TRANSFORM_UNUSABLE = 143,
+ SPELL_FAILED_WRONG_WEATHER = 144,
+ SPELL_FAILED_DAMAGE_IMMUNE = 145,
+ SPELL_FAILED_PREVENTED_BY_MECHANIC = 146,
+ SPELL_FAILED_PLAY_TIME = 147,
+ SPELL_FAILED_REPUTATION = 148,
+ SPELL_FAILED_MIN_SKILL = 149,
+ SPELL_FAILED_NOT_IN_ARENA = 150,
+ SPELL_FAILED_NOT_ON_SHAPESHIFT = 151,
+ SPELL_FAILED_NOT_ON_STEALTHED = 152,
+ SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 153,
+ SPELL_FAILED_NOT_ON_MOUNTED = 154,
+ SPELL_FAILED_TOO_SHALLOW = 155,
+ SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 156,
+ SPELL_FAILED_TARGET_IS_TRIVIAL = 157,
+ SPELL_FAILED_BM_OR_INVISGOD = 158,
+ SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 159,
+ SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 160,
+ SPELL_FAILED_NOT_IDLE = 161,
+ SPELL_FAILED_NOT_INACTIVE = 162,
+ SPELL_FAILED_PARTIAL_PLAYTIME = 163,
+ SPELL_FAILED_NO_PLAYTIME = 164,
+ SPELL_FAILED_NOT_IN_BATTLEGROUND = 165,
+ SPELL_FAILED_NOT_IN_RAID_INSTANCE = 166,
+ SPELL_FAILED_ONLY_IN_ARENA = 167,
+ SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 168,
+ SPELL_FAILED_ON_USE_ENCHANT = 169,
+ SPELL_FAILED_NOT_ON_GROUND = 170,
+ SPELL_FAILED_CUSTOM_ERROR = 171,
+ SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 172,
+ SPELL_FAILED_TOO_MANY_SOCKETS = 173,
+ SPELL_FAILED_INVALID_GLYPH = 174,
+ SPELL_FAILED_UNIQUE_GLYPH = 175,
+ SPELL_FAILED_GLYPH_SOCKET_LOCKED = 176,
+ SPELL_FAILED_NO_VALID_TARGETS = 177,
+ SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178,
+ SPELL_FAILED_NOT_IN_BARBERSHOP = 179,
+ SPELL_FAILED_FISHING_TOO_LOW = 180,
+ SPELL_FAILED_UNKNOWN = 181,
+
+ SPELL_CAST_OK = 255 //custom value, don't must be send to client
};
// Spell aura states
@@ -685,25 +883,28 @@ enum AuraState
AURA_STATE_DEFENSE = 1, // C |
AURA_STATE_HEALTHLESS_20_PERCENT = 2, // CcT |
AURA_STATE_BERSERKING = 3, // C T |
- //AURA_STATE_UNKNOWN4 = 4, // c t| some limitation to charge spells (?) and target test spells
+ AURA_STATE_FROZEN = 4, // c t| frozen target
AURA_STATE_JUDGEMENT = 5, // C |
//AURA_STATE_UNKNOWN6 = 6, // | not used
AURA_STATE_HUNTER_PARRY = 7, // C |
AURA_STATE_ROGUE_ATTACK_FROM_STEALTH = 7, // C | FIX ME: not implemented yet!
- //AURA_STATE_UNKNOWN7c = 7, // c | random/focused bursts spells (?)
+ //AURA_STATE_UNKNOWN7 = 7, // c | random/focused bursts spells (?)
//AURA_STATE_UNKNOWN8 = 8, // | not used
//AURA_STATE_UNKNOWN9 = 9, // | not used
AURA_STATE_WARRIOR_VICTORY_RUSH = 10, // C | warrior victory rush
- AURA_STATE_HUNTER_CRIT_STRIKE = 10, // C | hunter crit strike
- AURA_STATE_CRIT = 11, // C |
+ //AURA_STATE_UNKNOWN11 = 11, // t|
AURA_STATE_FAERIE_FIRE = 12, // c t|
AURA_STATE_HEALTHLESS_35_PERCENT = 13, // C T |
AURA_STATE_IMMOLATE = 14, // T |
AURA_STATE_SWIFTMEND = 15, // T |
AURA_STATE_DEADLY_POISON = 16, // T |
- AURA_STATE_FORBEARANCE = 17, // c t|
- AURA_STATE_WEAKENED_SOUL = 18, // t|
- AURA_STATE_HYPOTHERMIA = 19 // c |
+ AURA_STATE_ENRAGE = 17, // C |
+ //AURA_STATE_UNKNOWN18 = 18, // C t|
+ //AURA_STATE_UNKNOWN19 = 19, // | not used
+ //AURA_STATE_UNKNOWN20 = 20, // c | only (45317 Suicide)
+ //AURA_STATE_UNKNOWN21 = 21, // | not used
+ //AURA_STATE_UNKNOWN22 = 22, // C | not implemented yet (Requires Evasive Charges to use)
+ AURA_STATE_HEALTH_ABOVE_75_PERCENT = 23, // C |
};
// Spell mechanics
@@ -711,11 +912,11 @@ enum Mechanics
{
MECHANIC_NONE = 0,
MECHANIC_CHARM = 1,
- MECHANIC_CONFUSED = 2,
+ MECHANIC_DISORIENTED = 2,
MECHANIC_DISARM = 3,
MECHANIC_DISTRACT = 4,
MECHANIC_FEAR = 5,
- MECHANIC_FUMBLE = 6,
+ MECHANIC_GRIP = 6,
MECHANIC_ROOT = 7,
MECHANIC_PACIFY = 8, //0 spells use this mechanic
MECHANIC_SILENCE = 9,
@@ -731,7 +932,7 @@ enum Mechanics
MECHANIC_SHIELD = 19,
MECHANIC_SHACKLE = 20,
MECHANIC_MOUNT = 21,
- MECHANIC_PERSUADE = 22, //0 spells use this mechanic
+ MECHANIC_INFECTED = 22,
MECHANIC_TURN = 23,
MECHANIC_HORROR = 24,
MECHANIC_INVULNERABILITY = 25,
@@ -739,12 +940,13 @@ enum Mechanics
MECHANIC_DAZE = 27,
MECHANIC_DISCOVERY = 28,
MECHANIC_IMMUNE_SHIELD = 29, // Divine (Blessing) Shield/Protection and Ice Block
- MECHANIC_SAPPED = 30
+ MECHANIC_SAPPED = 30,
+ MECHANIC_ENRAGED = 31
};
// Used for spell 42292 Immune Movement Impairment and Loss of Control (0x49967da6)
#define IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK ( \
- (1<<MECHANIC_CHARM )|(1<<MECHANIC_CONFUSED )|(1<<MECHANIC_FEAR )| \
+ (1<<MECHANIC_CHARM )|(1<<MECHANIC_DISORIENTED )|(1<<MECHANIC_FEAR )| \
(1<<MECHANIC_ROOT )|(1<<MECHANIC_PACIFY )|(1<<MECHANIC_SLEEP )| \
(1<<MECHANIC_SNARE )|(1<<MECHANIC_STUN )|(1<<MECHANIC_FREEZE)| \
(1<<MECHANIC_KNOCKOUT)|(1<<MECHANIC_POLYMORPH)|(1<<MECHANIC_BANISH)| \
@@ -764,7 +966,8 @@ enum DispelType
DISPEL_ALL = 7,
DISPEL_SPE_NPC_ONLY = 8,
DISPEL_ENRAGE = 9,
- DISPEL_ZG_TICKET = 10
+ DISPEL_ZG_TICKET = 10,
+ DESPEL_OLD_UNUSED = 11
};
#define DISPEL_ALL_MASK ( (1<<DISPEL_MAGIC) | (1<<DISPEL_CURSE) | (1<<DISPEL_DISEASE) | (1<<DISPEL_POISON) )
@@ -802,6 +1005,7 @@ enum Targets
TARGET_UNIT_AREA_ENEMY_DST = 16,
TARGET_DST_DB = 17, // uses in teleport spells and some other
TARGET_DST_CASTER = 18,
+ TARGET_PREV_EFFECT_SUMMON = 18,
TARGET_UNIT_PARTY_CASTER = 20,
TARGET_UNIT_TARGET_ALLY = 21,
TARGET_SRC_CASTER = 22,
@@ -901,9 +1105,10 @@ enum SpellHitType
{
SPELL_HIT_TYPE_UNK1 = 0x00001,
SPELL_HIT_TYPE_CRIT = 0x00002,
- SPELL_HIT_TYPE_UNK2 = 0x00004,
- SPELL_HIT_TYPE_UNK3 = 0x00008,
- SPELL_HIT_TYPE_UNK4 = 0x00020
+ SPELL_HIT_TYPE_UNK3 = 0x00004,
+ SPELL_HIT_TYPE_UNK4 = 0x00008,
+ SPELL_HIT_TYPE_UNK5 = 0x00010, // replace caster?
+ SPELL_HIT_TYPE_UNK6 = 0x00020
};
enum SpellDmgClass
@@ -958,9 +1163,10 @@ enum GameobjectTypes
GAMEOBJECT_TYPE_BARBER_CHAIR = 32,
GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING = 33,
GAMEOBJECT_TYPE_GUILD_BANK = 34,
+ GAMEOBJECT_TYPE_TRAPDOOR = 35
};
-#define MAX_GAMEOBJECT_TYPE 35 // sending to client this or greater value can crash client.
+#define MAX_GAMEOBJECT_TYPE 36 // sending to client this or greater value can crash client.
#define GAMEOBJECT_FISHINGNODE_ENTRY 35591 // Better to define it somewhere instead of hardcoding everywhere
@@ -972,7 +1178,9 @@ enum GameObjectFlags
GO_FLAG_TRANSPORT = 0x00000008, //any kind of transport? Object can transport (elevator, boat, car)
GO_FLAG_UNK1 = 0x00000010, //
GO_FLAG_NODESPAWN = 0x00000020, //never despawn, typically for doors, they just change state
- GO_FLAG_TRIGGERED = 0x00000040 //typically, summoned objects. Triggered by spell or other events
+ GO_FLAG_TRIGGERED = 0x00000040, //typically, summoned objects. Triggered by spell or other events
+ GO_FLAG_DAMAGED = 0x00000200,
+ GO_FLAG_DESTROYED = 0x00000400,
};
enum TextEmotes
@@ -1179,7 +1387,7 @@ enum Emote
EMOTE_ONESHOT_POINT = 25,
EMOTE_STATE_STAND = 26,
EMOTE_STATE_READYUNARMED = 27,
- EMOTE_STATE_WORK = 28,
+ EMOTE_STATE_WORK_SHEATHED = 28,
EMOTE_STATE_POINT = 29,
EMOTE_STATE_NONE = 30,
EMOTE_ONESHOT_WOUND = 33,
@@ -1212,13 +1420,13 @@ enum Emote
EMOTE_ONESHOT_SALUTE_NOSHEATH = 113,
EMOTE_STATE_USESTANDING_NOSHEATHE = 133,
EMOTE_ONESHOT_LAUGH_NOSHEATHE = 153,
- EMOTE_STATE_WORK_NOSHEATHE = 173,
+ EMOTE_STATE_WORK = 173,
EMOTE_STATE_SPELLPRECAST = 193,
EMOTE_ONESHOT_READYRIFLE = 213,
EMOTE_STATE_READYRIFLE = 214,
- EMOTE_STATE_WORK_NOSHEATHE_MINING = 233,
- EMOTE_STATE_WORK_NOSHEATHE_CHOPWOOD= 234,
- EMOTE_zzOLDONESHOT_LIFTOFF = 253,
+ EMOTE_STATE_WORK_MINING = 233,
+ EMOTE_STATE_WORK_CHOPWOOD = 234,
+ EMOTE_STATE_APPLAUD = 253,
EMOTE_ONESHOT_LIFTOFF = 254,
EMOTE_ONESHOT_YES = 273,
EMOTE_ONESHOT_NO = 274,
@@ -1267,8 +1475,57 @@ enum Emote
EMOTE_ONESHOT_CUSTOMSPELL09 = 410,
EMOTE_ONESHOT_CUSTOMSPELL10 = 411,
EMOTE_STATE_EXCLAIM = 412,
+ EMOTE_STATE_DANCE_CUSTOM = 413,
EMOTE_STATE_SIT_CHAIR_MED = 415,
- EMOTE_STATE_SPELLEFFECT_HOLD = 422
+ EMOTE_STATE_CUSTOM_SPELL_01 = 416,
+ EMOTE_STATE_CUSTOM_SPELL_02 = 417,
+ EMOTE_STATE_EAT = 418,
+ EMOTE_STATE_CUSTOM_SPELL_04 = 419,
+ EMOTE_STATE_CUSTOM_SPELL_03 = 420,
+ EMOTE_STATE_CUSTOM_SPELL_05 = 421,
+ EMOTE_STATE_SPELLEFFECT_HOLD = 422,
+ EMOTE_STATE_EAT_NO_SHEATHE = 423,
+ EMOTE_STATE_MOUNT = 424,
+ EMOTE_STATE_READY2HL = 425,
+ EMOTE_STATE_SIT_CHAIR_HIGH = 426,
+ EMOTE_STATE_FALL = 427,
+ EMOTE_STATE_LOOT = 428,
+ EMOTE_STATE_SUBMERGED_NEW = 429,
+ EMOTE_ONESHOT_COWER = 430,
+ EMOTE_STATE_COWER = 431,
+ EMOTE_ONESHOT_USESTANDING = 432,
+ EMOTE_STATE_STEALTH_STAND = 433,
+ EMOTE_ONESHOT_OMNICAST_GHOUL = 434,
+ EMOTE_ONESHOT_ATTACKBOW = 435,
+ EMOTE_ONESHOT_ATTACKRIFLE = 436,
+ EMOTE_STATE_SWIM_IDLE = 437,
+ EMOTE_STATE_ATTACK_UNARMED = 438,
+ EMOTE_ONESHOT_SPELLCAST_W_SOUND = 439,
+ EMOTE_ONESHOT_DODGE = 440,
+ EMOTE_ONESHOT_PARRY1H = 441,
+ EMOTE_ONESHOT_PARRY2H = 442,
+ EMOTE_ONESHOT_PARRY2HL = 443,
+ EMOTE_STATE_FLYFALL = 444,
+ EMOTE_ONESHOT_FLYDEATH = 445,
+ EMOTE_STATE_FLY_FALL = 446,
+ EMOTE_ONESHOT_FLY_SIT_GROUND_DOWN = 447,
+ EMOTE_ONESHOT_FLY_SIT_GROUND_UP = 448,
+ EMOTE_ONESHOT_EMERGE = 449,
+ EMOTE_ONESHOT_DRAGONSPIT = 450,
+ EMOTE_STATE_SPECIALUNARMED = 451,
+ EMOTE_ONESHOT_FLYGRAB = 452,
+ EMOTE_STATE_FLYGRABCLOSED = 453,
+ EMOTE_ONESHOT_FLYGRABTHROWN = 454,
+ EMOTE_STATE_FLY_SIT_GROUND = 455,
+ EMOTE_STATE_WALKBACKWARDS = 456,
+ EMOTE_ONESHOT_FLYTALK = 457,
+ EMOTE_ONESHOT_FLYATTACK1H = 458,
+ EMOTE_STATE_CUSTOMSPELL08 = 459,
+ EMOTE_ONESHOT_FLY_DRAGONSPIT = 460,
+ EMOTE_STATE_SIT_CHAIR_LOW = 461,
+ EMOTE_ONE_SHOT_STUN = 462,
+ EMOTE_ONESHOT_SPELLCAST_OMNI = 463,
+ EMOTE_STATE_READYTHROWN = 464
};
enum Anim
@@ -1527,7 +1784,9 @@ enum LockType
LOCKTYPE_BLASTING = 16,
LOCKTYPE_SLOW_OPEN = 17,
LOCKTYPE_SLOW_CLOSE = 18,
- LOCKTYPE_FISHING = 19
+ LOCKTYPE_FISHING = 19,
+ LOCKTYPE_INSCRIPTION = 20,
+ LOCKTYPE_OPEN_FROM_VEHICLE = 21
};
enum TrainerType // this is important type for npcs!
@@ -1540,6 +1799,7 @@ enum TrainerType // this is important
#define MAX_TRAINER_TYPE 4
+// CreatureType.dbc
enum CreatureType
{
CREATURE_TYPE_BEAST = 1,
@@ -1558,7 +1818,9 @@ enum CreatureType
};
uint32 const CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD = (1 << (CREATURE_TYPE_HUMANOID-1)) | (1 << (CREATURE_TYPE_UNDEAD-1));
+uint32 const CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL = (1 << (CREATURE_TYPE_MECHANICAL-1)) | (1 << (CREATURE_TYPE_ELEMENTAL-1));
+// CreatureFamily.dbc
enum CreatureFamily
{
CREATURE_FAMILY_WOLF = 1,
@@ -1570,6 +1832,7 @@ enum CreatureFamily
CREATURE_FAMILY_CARRION_BIRD = 7,
CREATURE_FAMILY_CRAB = 8,
CREATURE_FAMILY_GORILLA = 9,
+ CREATURE_FAMILY_HORSE_CUSTOM = 10, // not exist in DBC but used for horse like beasts in DB
CREATURE_FAMILY_RAPTOR = 11,
CREATURE_FAMILY_TALLSTRIDER = 12,
CREATURE_FAMILY_FELHUNTER = 15,
@@ -1581,7 +1844,7 @@ enum CreatureFamily
CREATURE_FAMILY_IMP = 23,
CREATURE_FAMILY_BAT = 24,
CREATURE_FAMILY_HYENA = 25,
- CREATURE_FAMILY_OWL = 26,
+ CREATURE_FAMILY_BIRD_OF_PREY = 26,
CREATURE_FAMILY_WIND_SERPENT = 27,
CREATURE_FAMILY_REMOTE_CONTROL = 28,
CREATURE_FAMILY_FELGUARD = 29,
@@ -1591,14 +1854,26 @@ enum CreatureFamily
CREATURE_FAMILY_SPOREBAT = 33,
CREATURE_FAMILY_NETHER_RAY = 34,
CREATURE_FAMILY_SERPENT = 35,
- CREATURE_FAMILY_SEA_LION = 36
+ CREATURE_FAMILY_MOTH = 37,
+ CREATURE_FAMILY_CHIMAERA = 38,
+ CREATURE_FAMILY_DEVILSAUR = 39,
+ CREATURE_FAMILY_GHOUL = 40,
+ CREATURE_FAMILY_SILITHID = 41,
+ CREATURE_FAMILY_WORM = 42,
+ CREATURE_FAMILY_RHINO = 43,
+ CREATURE_FAMILY_WASP = 44,
+ CREATURE_FAMILY_CORE_HOUND = 45,
+ CREATURE_FAMILY_SPIRIT_BEAST = 46
};
+#define MAX_CREATURE_FAMILY 47
+
enum CreatureTypeFlags
{
- CREATURE_TYPEFLAGS_TAMEABLE = 0x0001,
- CREATURE_TYPEFLAGS_HERBLOOT = 0x0100,
- CREATURE_TYPEFLAGS_MININGLOOT = 0x0200
+ CREATURE_TYPEFLAGS_TAMEABLE = 0x0001,
+ CREATURE_TYPEFLAGS_HERBLOOT = 0x0100,
+ CREATURE_TYPEFLAGS_MININGLOOT = 0x0200,
+ CREATURE_TYPEFLAGS_ENGINEERLOOT = 0x8000
};
enum CreatureEliteType
@@ -1611,6 +1886,31 @@ enum CreatureEliteType
CREATURE_UNKNOWN = 5 // found in 2.2.3 for 2 mobs
};
+// values based at Holidays.dbc
+enum HolidayIds
+{
+ HOLIDAY_FIREWORKS_SPECTACULAR = 62,
+ HOLIDAY_FEAST_OF_WINTER_VEIL = 141,
+ HOLIDAY_NOBLEGARDEN = 181,
+ HOLIDAY_CHILDRENS_WEEK = 201,
+ HOLIDAY_CALL_TO_ARMS_AV = 283,
+ HOLIDAY_CALL_TO_ARMS_WG = 284,
+ HOLIDAY_CALL_TO_ARMS_AB = 285,
+ HOLIDAY_FISHING_EXTRAVAGANZA = 301,
+ HOLIDAY_HARVEST_FESTIVAL = 321,
+ HOLIDAY_HALLOWS_END = 324,
+ HOLIDAY_LUNAR_FESTIVAL = 327,
+ HOLIDAY_LOVE_IS_IN_THE_AIR = 335,
+ HOLIDAY_FIRE_FESTIVAL = 341,
+ HOLIDAY_CALL_TO_ARMS_ES = 353,
+ HOLIDAY_BREWFEST = 372,
+ HOLIDAY_DARKMOON_FAIRE_ELWYNN = 374,
+ HOLIDAY_DARKMOON_FAIRE_THUNDER = 375,
+ HOLIDAY_DARKMOON_FAIRE_SHATTRATH = 376,
+ HOLIDAY_CALL_TO_ARMS_SA = 400,
+ HOLIDAY_WOTLK_LAUNCH = 406
+};
+
// values based at QuestInfo.dbc
enum QuestTypes
{
@@ -1623,6 +1923,8 @@ enum QuestTypes
QUEST_TYPE_LEGENDARY = 83,
QUEST_TYPE_ESCORT = 84,
QUEST_TYPE_HEROIC = 85,
+ QUEST_TYPE_RAID_10 = 88,
+ QUEST_TYPE_RAID_25 = 89
};
// values based at QuestSort.dbc
@@ -1633,7 +1935,7 @@ enum QuestSort
QUEST_SORT_SEASONAL = 22,
QUEST_SORT_UNDERCITY_OLD = 23,
QUEST_SORT_HERBALISM = 24,
- QUEST_SORT_SCARLET_MONASTERY_OLD= 25,
+ QUEST_SORT_BATTLEGROUNDS = 25,
QUEST_SORT_ULDAMN_OLD = 41,
QUEST_SORT_WARLOCK = 61,
QUEST_SORT_WARRIOR = 81,
@@ -1662,34 +1964,39 @@ enum QuestSort
QUEST_SORT_REPUTATION = 367,
QUEST_SORT_INVASION = 368,
QUEST_SORT_MIDSUMMER = 369,
- QUEST_SORT_BREWFEST = 370
+ QUEST_SORT_BREWFEST = 370,
+ QUEST_SORT_INSCRIPTION = 371,
+ QUEST_SORT_DEATH_KNIGHT = 372,
+ QUEST_SORT_JEWELCRAFTING = 373
};
inline uint8 ClassByQuestSort(int32 QuestSort)
{
switch(QuestSort)
{
- case QUEST_SORT_WARLOCK: return CLASS_WARLOCK;
- case QUEST_SORT_WARRIOR: return CLASS_WARRIOR;
- case QUEST_SORT_SHAMAN: return CLASS_SHAMAN;
- case QUEST_SORT_PALADIN: return CLASS_PALADIN;
- case QUEST_SORT_MAGE: return CLASS_MAGE;
- case QUEST_SORT_ROGUE: return CLASS_ROGUE;
- case QUEST_SORT_HUNTER: return CLASS_HUNTER;
- case QUEST_SORT_PRIEST: return CLASS_PRIEST;
- case QUEST_SORT_DRUID: return CLASS_DRUID;
+ case QUEST_SORT_WARLOCK: return CLASS_WARLOCK;
+ case QUEST_SORT_WARRIOR: return CLASS_WARRIOR;
+ case QUEST_SORT_SHAMAN: return CLASS_SHAMAN;
+ case QUEST_SORT_PALADIN: return CLASS_PALADIN;
+ case QUEST_SORT_MAGE: return CLASS_MAGE;
+ case QUEST_SORT_ROGUE: return CLASS_ROGUE;
+ case QUEST_SORT_HUNTER: return CLASS_HUNTER;
+ case QUEST_SORT_PRIEST: return CLASS_PRIEST;
+ case QUEST_SORT_DRUID: return CLASS_DRUID;
+ case QUEST_SORT_DEATH_KNIGHT: return CLASS_DEATH_KNIGHT;
}
return 0;
}
enum SkillType
{
+ SKILL_NONE = 0,
+
SKILL_FROST = 6,
SKILL_FIRE = 8,
SKILL_ARMS = 26,
SKILL_COMBAT = 38,
SKILL_SUBTLETY = 39,
- SKILL_POISONS = 40,
SKILL_SWORDS = 43,
SKILL_AXES = 44,
SKILL_BOWS = 45,
@@ -1697,8 +2004,8 @@ enum SkillType
SKILL_BEAST_MASTERY = 50,
SKILL_SURVIVAL = 51,
SKILL_MACES = 54,
- SKILL_HOLY = 56,
SKILL_2H_SWORDS = 55,
+ SKILL_HOLY = 56,
SKILL_SHADOW = 78,
SKILL_DEFENSE = 95,
SKILL_LANG_COMMON = 98,
@@ -1754,24 +2061,20 @@ enum SkillType
SKILL_PET_BOAR = 211,
SKILL_PET_CROCILISK = 212,
SKILL_PET_CARRION_BIRD = 213,
- SKILL_PET_GORILLA = 215,
SKILL_PET_CRAB = 214,
+ SKILL_PET_GORILLA = 215,
SKILL_PET_RAPTOR = 217,
SKILL_PET_TALLSTRIDER = 218,
SKILL_RACIAL_UNDED = 220,
- SKILL_WEAPON_TALENTS = 222,
SKILL_CROSSBOWS = 226,
- SKILL_SPEARS = 227,
SKILL_WANDS = 228,
SKILL_POLEARMS = 229,
SKILL_PET_SCORPID = 236,
SKILL_ARCANE = 237,
- SKILL_OPEN_LOCK = 242,
SKILL_PET_TURTLE = 251,
SKILL_ASSASSINATION = 253,
SKILL_FURY = 256,
SKILL_PROTECTION = 257,
- SKILL_BEAST_TRAINING = 261,
SKILL_PROTECTION2 = 267,
SKILL_PET_TALENTS = 270,
SKILL_PLATE_MAIL = 293,
@@ -1801,7 +2104,7 @@ enum SkillType
SKILL_LOCKPICKING = 633,
SKILL_PET_BAT = 653,
SKILL_PET_HYENA = 654,
- SKILL_PET_OWL = 655,
+ SKILL_PET_BIRD_OF_PREY = 655,
SKILL_PET_WIND_SERPENT = 656,
SKILL_LANG_GUTTERSPEAK = 673,
SKILL_RIDING_KODO = 713,
@@ -1821,10 +2124,41 @@ enum SkillType
SKILL_PET_WARP_STALKER = 766,
SKILL_PET_RAVAGER = 767,
SKILL_PET_SERPENT = 768,
- SKILL_INTERNAL = 769
+ SKILL_INTERNAL = 769,
+ SKILL_DK_BLOOD = 770,
+ SKILL_DK_FROST = 771,
+ SKILL_DK_UNHOLY = 772,
+ SKILL_INSCRIPTION = 773,
+ SKILL_PET_MOTH = 775,
+ SKILL_RUNEFORGING = 776,
+ SKILL_MOUNTS = 777,
+ SKILL_COMPANIONS = 778,
+ SKILL_PET_EXOTIC_CHIMAERA = 780,
+ SKILL_PET_EXOTIC_DEVILSAUR = 781,
+ SKILL_PET_GHOUL = 782,
+ SKILL_PET_EXOTIC_SILITHID = 783,
+ SKILL_PET_EXOTIC_WORM = 784,
+ SKILL_PET_WASP = 785,
+ SKILL_PET_EXOTIC_RHINO = 786,
+ SKILL_PET_EXOTIC_CORE_HOUND = 787,
+ SKILL_PET_EXOTIC_SPIRIT_BEAST = 788
};
-#define MAX_SKILL_TYPE 770
+#define MAX_SKILL_TYPE 789
+
+inline SkillType SkillByLockType(LockType locktype)
+{
+ switch(locktype)
+ {
+ case LOCKTYPE_PICKLOCK: return SKILL_LOCKPICKING;
+ case LOCKTYPE_HERBALISM: return SKILL_HERBALISM;
+ case LOCKTYPE_MINING: return SKILL_MINING;
+ case LOCKTYPE_FISHING: return SKILL_FISHING;
+ case LOCKTYPE_INSCRIPTION: return SKILL_INSCRIPTION;
+ default: break;
+ }
+ return SKILL_NONE;
+}
inline uint32 SkillByQuestSort(int32 QuestSort)
{
@@ -1839,25 +2173,27 @@ inline uint32 SkillByQuestSort(int32 QuestSort)
case QUEST_SORT_TAILORING: return SKILL_TAILORING;
case QUEST_SORT_COOKING: return SKILL_COOKING;
case QUEST_SORT_FIRST_AID: return SKILL_FIRST_AID;
+ case QUEST_SORT_JEWELCRAFTING: return SKILL_JEWELCRAFTING;
+ case QUEST_SORT_INSCRIPTION: return SKILL_INSCRIPTION;
}
return 0;
}
enum SkillCategory
{
- SKILL_CATEGORY_ATTRIBUTES = 5,
- SKILL_CATEGORY_WEAPON = 6,
- SKILL_CATEGORY_CLASS = 7,
- SKILL_CATEGORY_ARMOR = 8,
- SKILL_CATEGORY_SECONDARY = 9, // secondary professions
+ SKILL_CATEGORY_ATTRIBUTES = 5,
+ SKILL_CATEGORY_WEAPON = 6,
+ SKILL_CATEGORY_CLASS = 7,
+ SKILL_CATEGORY_ARMOR = 8,
+ SKILL_CATEGORY_SECONDARY = 9, // secondary professions
SKILL_CATEGORY_LANGUAGES = 10,
SKILL_CATEGORY_PROFESSION = 11, // primary professions
- SKILL_CATEGORY_NOT_DISPLAYED = 12
+ SKILL_CATEGORY_GENERIC = 12
};
enum TotemCategory
{
- TC_SKINNING_SKIFE = 1,
+ TC_SKINNING_SKIFE_OLD = 1,
TC_EARTH_TOTEM = 2,
TC_AIR_TOTEM = 3,
TC_FIRE_TOTEM = 4,
@@ -1867,15 +2203,28 @@ enum TotemCategory
TC_GOLDEN_ROD = 8,
TC_TRUESILVER_ROD = 9,
TC_ARCANITE_ROD = 10,
- TC_MINING_PICK = 11,
+ TC_MINING_PICK_OLD = 11,
TC_PHILOSOPHERS_STONE = 12,
- TC_BLACKSMITH_HAMMER = 13,
+ TC_BLACKSMITH_HAMMER_OLD = 13,
TC_ARCLIGHT_SPANNER = 14,
TC_GYROMATIC_MA = 15,
TC_MASTER_TOTEM = 21,
TC_FEL_IRON_ROD = 41,
TC_ADAMANTITE_ROD = 62,
- TC_ETERNIUM_ROD = 63
+ TC_ETERNIUM_ROD = 63,
+ TC_HOLLOW_QUILL = 81,
+ TC_RUNED_AZURITE_ROD = 101,
+ TC_VIRTUOSO_INKING_SET = 121,
+ TC_DRUMS = 141,
+ TC_GNOMISH_ARMY_KNIFE = 161,
+ TC_BLACKSMITH_HAMMER = 162,
+ TC_MINING_PICK = 165,
+ TC_SKINNING_KNIFE = 166,
+ TC_HAMMER_PICK = 167,
+ TC_BLADED_PICKAXE = 168,
+ TC_FLINT_AND_TINDER = 169,
+ TC_RUNED_COBALT_ROD = 189,
+ TC_RUNED_TITANIUM_ROD = 190
};
enum UnitDynFlags
@@ -1885,7 +2234,8 @@ enum UnitDynFlags
UNIT_DYNFLAG_OTHER_TAGGER = 0x0004,
UNIT_DYNFLAG_ROOTED = 0x0008,
UNIT_DYNFLAG_SPECIALINFO = 0x0010,
- UNIT_DYNFLAG_DEAD = 0x0020
+ UNIT_DYNFLAG_DEAD = 0x0020,
+ UNIT_DYNFLAG_REFER_A_FRIEND = 0x0040
};
enum CorpseDynFlags
@@ -1894,11 +2244,14 @@ enum CorpseDynFlags
};
// Passive Spell codes explicit used in code
-#define SPELL_ID_GENERIC_LEARN 483
-#define SPELL_ID_PASSIVE_BATTLE_STANCE 2457
-#define SPELL_ID_PASSIVE_RESURRECTION_SICKNESS 15007
-#define SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_5s 6119
-#define SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_0s 6123
+#define SPELL_ID_GENERIC_LEARN 483
+#define SPELL_ID_GENERIC_LEARN_PET 55884 // used for learning mounts and companions
+#define SPELL_ID_PASSIVE_BATTLE_STANCE 2457
+#define SPELL_ID_PASSIVE_RESURRECTION_SICKNESS 15007
+#define SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_5s 6119
+#define SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_0s 6123
+#define SPELL_ID_AUTOSHOT 75 // used for checks in other spells interruption
+#define SPELL_ID_SHADOWMELD 58984 // used for check ignore stealth stance state
enum WeatherType
{
@@ -1962,9 +2315,12 @@ enum ChatMsg
CHAT_MSG_BATTLEGROUND = 0x2C,
CHAT_MSG_BATTLEGROUND_LEADER = 0x2D,
CHAT_MSG_RESTRICTED = 0x2E,
+ CHAT_MSG_BN = 0x2F,
+ CHAT_MSG_ACHIEVEMENT = 0x30,
+ CHAT_MSG_GUILD_ACHIEVEMENT = 0x31
};
-#define MAX_CHAT_MSG_TYPE 0x2F
+#define MAX_CHAT_MSG_TYPE 0x32
// Values from ItemPetFood (power of (value-1) used for compare with CreatureFamilyEntry.petDietMask
enum PetDiet
@@ -2044,27 +2400,29 @@ enum DungeonDifficulties
TOTAL_DIFFICULTIES
};
+enum SummonCategory
+{
+ SUMMON_CATEGORY_WILD = 0,
+ SUMMON_CATEGORY_ALLY = 1,
+ SUMMON_CATEGORY_PET = 2,
+ SUMMON_CATEGORY_POSSESSED = 3,
+ SUMMON_CATEGORY_VEHICLE = 4,
+};
+
enum SummonType
{
- SUMMON_TYPE_CRITTER = 41,
- SUMMON_TYPE_GUARDIAN = 61,
- SUMMON_TYPE_TOTEM_SLOT1 = 63,
- SUMMON_TYPE_WILD = 64,
- SUMMON_TYPE_POSESSED = 65,
- SUMMON_TYPE_DEMON = 66,
- SUMMON_TYPE_SUMMON = 67,
- SUMMON_TYPE_TOTEM_SLOT2 = 81,
- SUMMON_TYPE_TOTEM_SLOT3 = 82,
- SUMMON_TYPE_TOTEM_SLOT4 = 83,
- SUMMON_TYPE_TOTEM = 121,
- SUMMON_TYPE_UNKNOWN3 = 181,
- SUMMON_TYPE_UNKNOWN4 = 187,
- SUMMON_TYPE_UNKNOWN1 = 247,
- SUMMON_TYPE_CRITTER2 = 407,
- SUMMON_TYPE_CRITTER3 = 307,
- SUMMON_TYPE_UNKNOWN5 = 409,
- SUMMON_TYPE_POSESSED3 = 427,
- SUMMON_TYPE_POSESSED2 = 428
+ SUMMON_TYPE_NONE = 0,
+ SUMMON_TYPE_PET = 1,
+ SUMMON_TYPE_GUARDIAN = 2,
+ SUMMON_TYPE_MINION = 3,
+ SUMMON_TYPE_TOTEM = 4,
+ SUMMON_TYPE_MINIPET = 5,
+ SUMMON_TYPE_GUARDIAN2 = 6,
+ SUMMON_TYPE_WILD2 = 7,
+ SUMMON_TYPE_WILD3 = 8,
+ SUMMON_TYPE_VEHICLE = 9,
+ SUMMON_TYPE_VEHICLE2 = 10,
+ SUMMON_TYPE_OBJECT = 11,
};
enum ResponseCodes
@@ -2133,42 +2491,45 @@ enum ResponseCodes
CHAR_CREATE_SERVER_QUEUE = 0x37,
CHAR_CREATE_ONLY_EXISTING = 0x38,
CHAR_CREATE_EXPANSION = 0x39,
-
- CHAR_DELETE_IN_PROGRESS = 0x3A,
- CHAR_DELETE_SUCCESS = 0x3B,
- CHAR_DELETE_FAILED = 0x3C,
- CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x3D,
- CHAR_DELETE_FAILED_GUILD_LEADER = 0x3E,
- CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x3F,
-
- CHAR_LOGIN_IN_PROGRESS = 0x40,
- CHAR_LOGIN_SUCCESS = 0x41,
- CHAR_LOGIN_NO_WORLD = 0x42,
- CHAR_LOGIN_DUPLICATE_CHARACTER = 0x43,
- CHAR_LOGIN_NO_INSTANCES = 0x44,
- CHAR_LOGIN_FAILED = 0x45,
- CHAR_LOGIN_DISABLED = 0x46,
- CHAR_LOGIN_NO_CHARACTER = 0x47,
- CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x48,
- CHAR_LOGIN_LOCKED_BY_BILLING = 0x49,
-
- CHAR_NAME_SUCCESS = 0x4A,
- CHAR_NAME_FAILURE = 0x4B,
- CHAR_NAME_NO_NAME = 0x4C,
- CHAR_NAME_TOO_SHORT = 0x4D,
- CHAR_NAME_TOO_LONG = 0x4E,
- CHAR_NAME_INVALID_CHARACTER = 0x4F,
- CHAR_NAME_MIXED_LANGUAGES = 0x50,
- CHAR_NAME_PROFANE = 0x51,
- CHAR_NAME_RESERVED = 0x52,
- CHAR_NAME_INVALID_APOSTROPHE = 0x53,
- CHAR_NAME_MULTIPLE_APOSTROPHES = 0x54,
- CHAR_NAME_THREE_CONSECUTIVE = 0x55,
- CHAR_NAME_INVALID_SPACE = 0x56,
- CHAR_NAME_CONSECUTIVE_SPACES = 0x57,
- CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x58,
- CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x59,
- CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x5A,
+ CHAR_CREATE_EXPANSION_CLASS = 0x3A,
+ CHAR_CREATE_LEVEL_REQUIREMENT = 0x3B,
+ CHAR_CREATE_UNIQUE_CLASS_LIMIT = 0x3C,
+
+ CHAR_DELETE_IN_PROGRESS = 0x3D,
+ CHAR_DELETE_SUCCESS = 0x3E,
+ CHAR_DELETE_FAILED = 0x3F,
+ CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x40,
+ CHAR_DELETE_FAILED_GUILD_LEADER = 0x41,
+ CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x42,
+
+ CHAR_LOGIN_IN_PROGRESS = 0x43,
+ CHAR_LOGIN_SUCCESS = 0x44,
+ CHAR_LOGIN_NO_WORLD = 0x45,
+ CHAR_LOGIN_DUPLICATE_CHARACTER = 0x46,
+ CHAR_LOGIN_NO_INSTANCES = 0x47,
+ CHAR_LOGIN_FAILED = 0x48,
+ CHAR_LOGIN_DISABLED = 0x49,
+ CHAR_LOGIN_NO_CHARACTER = 0x4A,
+ CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x4B,
+ CHAR_LOGIN_LOCKED_BY_BILLING = 0x4C,
+
+ CHAR_NAME_SUCCESS = 0x4D,
+ CHAR_NAME_FAILURE = 0x4E,
+ CHAR_NAME_NO_NAME = 0x4F,
+ CHAR_NAME_TOO_SHORT = 0x50,
+ CHAR_NAME_TOO_LONG = 0x51,
+ CHAR_NAME_INVALID_CHARACTER = 0x52,
+ CHAR_NAME_MIXED_LANGUAGES = 0x53,
+ CHAR_NAME_PROFANE = 0x54,
+ CHAR_NAME_RESERVED = 0x55,
+ CHAR_NAME_INVALID_APOSTROPHE = 0x56,
+ CHAR_NAME_MULTIPLE_APOSTROPHES = 0x57,
+ CHAR_NAME_THREE_CONSECUTIVE = 0x58,
+ CHAR_NAME_INVALID_SPACE = 0x59,
+ CHAR_NAME_CONSECUTIVE_SPACES = 0x5A,
+ CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x5B,
+ CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x5C,
+ CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x5D
};
/// Ban function modes
@@ -2186,5 +2547,24 @@ enum BanReturn
BAN_SYNTAX_ERROR,
BAN_NOTFOUND
};
+
+// indexes of BattlemasterList.dbc
+enum BattleGroundTypeId
+{
+ BATTLEGROUND_TYPE_NONE = 0,
+ BATTLEGROUND_AV = 1,
+ BATTLEGROUND_WS = 2,
+ BATTLEGROUND_AB = 3,
+ BATTLEGROUND_NA = 4,
+ BATTLEGROUND_BE = 5,
+ BATTLEGROUND_AA = 6,
+ BATTLEGROUND_EY = 7,
+ BATTLEGROUND_RL = 8,
+ BATTLEGROUND_SA = 9,
+ BATTLEGROUND_DS = 10,
+ BATTLEGROUND_RV = 11
+};
+#define MAX_BATTLEGROUND_TYPE_ID 12
+
#endif
diff --git a/src/game/SkillDiscovery.cpp b/src/game/SkillDiscovery.cpp
index 5a5869047a5..0c0517eb320 100644
--- a/src/game/SkillDiscovery.cpp
+++ b/src/game/SkillDiscovery.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
#include "Log.h"
#include "ProgressBar.h"
#include "Policies/SingletonImp.h"
-#include "ObjectAccessor.h"
#include "World.h"
#include "Util.h"
#include "SkillDiscovery.h"
@@ -31,14 +30,15 @@
struct SkillDiscoveryEntry
{
- uint32 spellId;
- float chance;
+ uint32 spellId; // discavered spell
+ uint32 reqSkillValue; // skill level limitation
+ float chance; // chance
SkillDiscoveryEntry()
- : spellId(0), chance(0) {}
+ : spellId(0), reqSkillValue(0), chance(0) {}
- SkillDiscoveryEntry(uint16 _spellId, float _chance)
- : spellId(_spellId), chance(_chance) {}
+ SkillDiscoveryEntry(uint16 _spellId, uint32 req_skill_val, float _chance)
+ : spellId(_spellId), reqSkillValue(req_skill_val), chance(_chance) {}
};
typedef std::list<SkillDiscoveryEntry> SkillDiscoveryList;
@@ -53,8 +53,8 @@ void LoadSkillDiscoveryTable()
uint32 count = 0;
- // 0 1 2
- QueryResult *result = WorldDatabase.Query("SELECT spellId, reqSpell, chance FROM skill_discovery_template");
+ // 0 1 2 3
+ QueryResult *result = WorldDatabase.Query("SELECT spellId, reqSpell, reqSkillValue, chance FROM skill_discovery_template");
if (result)
{
@@ -69,11 +69,13 @@ void LoadSkillDiscoveryTable()
uint32 spellId = fields[0].GetUInt32();
int32 reqSkillOrSpell = fields[1].GetInt32();
- float chance = fields[2].GetFloat();
+ uint32 reqSkillValue = fields[2].GetInt32();
+ float chance = fields[3].GetFloat();
if( chance <= 0 ) // chance
{
- ssNonDiscoverableEntries << "spellId = " << spellId << " reqSkillOrSpell = " << reqSkillOrSpell << " chance = " << chance << "\n";
+ ssNonDiscoverableEntries << "spellId = " << spellId << " reqSkillOrSpell = " << reqSkillOrSpell
+ << " reqSkillValue = " << reqSkillValue << " chance = " << chance << "(chance problem)\n";
continue;
}
@@ -86,13 +88,16 @@ void LoadSkillDiscoveryTable()
continue;
}
- if( spellEntry->Mechanic != MECHANIC_DISCOVERY )
+ // mechanic discovery
+ if (spellEntry->Mechanic != MECHANIC_DISCOVERY &&
+ // explicit discovery ability
+ !IsExplicitDiscoverySpell(spellEntry))
{
- sLog.outErrorDb("Spell (ID: %u) not have have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc but listed in `skill_discovery_template` table",spellId);
+ sLog.outErrorDb("Spell (ID: %u) not have have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc and not 100%% chance random discovery ability but listed in `skill_discovery_template` table",spellId);
continue;
}
- SkillDiscoveryStore[reqSkillOrSpell].push_back( SkillDiscoveryEntry(spellId, chance) );
+ SkillDiscoveryStore[reqSkillOrSpell].push_back( SkillDiscoveryEntry(spellId, reqSkillValue, chance) );
}
else if( reqSkillOrSpell == 0 ) // skill case
{
@@ -107,7 +112,7 @@ void LoadSkillDiscoveryTable()
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
{
- SkillDiscoveryStore[-int32(_spell_idx->second->skillId)].push_back( SkillDiscoveryEntry(spellId, chance) );
+ SkillDiscoveryStore[-int32(_spell_idx->second->skillId)].push_back( SkillDiscoveryEntry(spellId, reqSkillValue, chance) );
}
}
else
@@ -115,6 +120,7 @@ void LoadSkillDiscoveryTable()
sLog.outErrorDb("Spell (ID: %u) have negative value in `reqSpell` field in `skill_discovery_template` table",spellId);
continue;
}
+
++count;
} while (result->NextRow());
@@ -132,16 +138,57 @@ void LoadSkillDiscoveryTable()
}
}
+uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player)
+{
+ // explicit discovery spell chances (always success if case exist)
+ // in this case we have both skill and spell
+ SkillDiscoveryMap::const_iterator tab = SkillDiscoveryStore.find(spellId);
+ if(tab == SkillDiscoveryStore.end())
+ return 0;
+
+ SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spellId);
+ SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spellId);
+ uint32 skillvalue = lower != upper ? player->GetSkillValue(lower->second->skillId) : 0;
+
+ float full_chance = 0;
+ for(SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
+ if(item_iter->reqSkillValue <= skillvalue)
+ if(!player->HasSpell(item_iter->spellId))
+ full_chance += item_iter->chance;
+
+ float rate = full_chance / 100.0f;
+ float roll = rand_chance() * rate; // roll now in range 0..full_chance
+
+ for(SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
+ {
+ if(item_iter->reqSkillValue > skillvalue)
+ continue;
+
+ if(player->HasSpell(item_iter->spellId))
+ continue;
+
+ if(item_iter->chance > roll)
+ return item_iter->spellId;
+
+ roll -= item_iter->chance;
+ }
+
+ return 0;
+}
+
uint32 GetSkillDiscoverySpell(uint32 skillId, uint32 spellId, Player* player)
{
+ uint32 skillvalue = skillId ? player->GetSkillValue(skillId) : 0;
+
// check spell case
- SkillDiscoveryMap::iterator tab = SkillDiscoveryStore.find(spellId);
+ SkillDiscoveryMap::const_iterator tab = SkillDiscoveryStore.find(spellId);
if(tab != SkillDiscoveryStore.end())
{
- for(SkillDiscoveryList::iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
+ for(SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
{
if( roll_chance_f(item_iter->chance * sWorld.getRate(RATE_SKILL_DISCOVERY))
+ && item_iter->reqSkillValue <= skillvalue
&& !player->HasSpell(item_iter->spellId) )
return item_iter->spellId;
}
@@ -149,13 +196,17 @@ uint32 GetSkillDiscoverySpell(uint32 skillId, uint32 spellId, Player* player)
return 0;
}
+ if(!skillId)
+ return 0;
+
// check skill line case
tab = SkillDiscoveryStore.find(-(int32)skillId);
if(tab != SkillDiscoveryStore.end())
{
- for(SkillDiscoveryList::iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
+ for(SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)
{
if( roll_chance_f(item_iter->chance * sWorld.getRate(RATE_SKILL_DISCOVERY))
+ && item_iter->reqSkillValue <= skillvalue
&& !player->HasSpell(item_iter->spellId) )
return item_iter->spellId;
}
diff --git a/src/game/SkillDiscovery.h b/src/game/SkillDiscovery.h
index 350062101fe..9981eb133f6 100644
--- a/src/game/SkillDiscovery.h
+++ b/src/game/SkillDiscovery.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,5 +27,6 @@ class Player;
void LoadSkillDiscoveryTable();
uint32 GetSkillDiscoverySpell(uint32 skillId, uint32 spellId, Player* player);
+uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player);
#endif
diff --git a/src/game/SkillExtraItems.cpp b/src/game/SkillExtraItems.cpp
index d89cbbdcddf..f0061f97c00 100644
--- a/src/game/SkillExtraItems.cpp
+++ b/src/game/SkillExtraItems.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/SkillExtraItems.h b/src/game/SkillExtraItems.h
index 38684b9933a..3a44619a862 100644
--- a/src/game/SkillExtraItems.h
+++ b/src/game/SkillExtraItems.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/SkillHandler.cpp b/src/game/SkillHandler.cpp
index 973d0bf9c39..2e1f09aaf5a 100644
--- a/src/game/SkillHandler.cpp
+++ b/src/game/SkillHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,12 +23,10 @@
#include "Opcodes.h"
#include "Log.h"
#include "Player.h"
-#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "ObjectAccessor.h"
#include "UpdateMask.h"
-#include "SpellAuras.h"
void WorldSession::HandleLearnTalentOpcode( WorldPacket & recv_data )
{
@@ -37,107 +35,7 @@ void WorldSession::HandleLearnTalentOpcode( WorldPacket & recv_data )
uint32 talent_id, requested_rank;
recv_data >> talent_id >> requested_rank;
- uint32 CurTalentPoints = GetPlayer()->GetFreeTalentPoints();
-
- if(CurTalentPoints == 0)
- return;
-
- if (requested_rank > 4)
- return;
-
- TalentEntry const *talentInfo = sTalentStore.LookupEntry( talent_id );
-
- if(!talentInfo)
- return;
-
- TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
-
- if(!talentTabInfo)
- return;
-
- Player * player = GetPlayer();
-
- // prevent learn talent for different class (cheating)
- if( (player->getClassMask() & talentTabInfo->ClassMask) == 0 )
- return;
-
- // prevent skip talent ranks (cheating)
- if(requested_rank > 0 && !player->HasSpell(talentInfo->RankID[requested_rank-1]))
- return;
-
- // Check if it requires another talent
- if (talentInfo->DependsOn > 0)
- {
- if(TalentEntry const *depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
- {
- bool hasEnoughRank = false;
- for (int i = talentInfo->DependsOnRank; i <= 4; i++)
- {
- if (depTalentInfo->RankID[i] != 0)
- if (player->HasSpell(depTalentInfo->RankID[i]))
- hasEnoughRank = true;
- }
- if (!hasEnoughRank)
- return;
- }
- }
-
- // Check if it requires spell
- if( talentInfo->DependsOnSpell && !player->HasSpell(talentInfo->DependsOnSpell) )
- return;
-
- // Find out how many points we have in this field
- uint32 spentPoints = 0;
-
- uint32 tTab = talentInfo->TalentTab;
- if (talentInfo->Row > 0)
- {
- unsigned int numRows = sTalentStore.GetNumRows();
- for (unsigned int i = 0; i < numRows; i++) // Loop through all talents.
- {
- // Someday, someone needs to revamp
- const TalentEntry *tmpTalent = sTalentStore.LookupEntry(i);
- if (tmpTalent) // the way talents are tracked
- {
- if (tmpTalent->TalentTab == tTab)
- {
- for (int j = 0; j <= 4; j++)
- {
- if (tmpTalent->RankID[j] != 0)
- {
- if (player->HasSpell(tmpTalent->RankID[j]))
- {
- spentPoints += j + 1;
- }
- }
- }
- }
- }
- }
- }
-
- // not have required min points spent in talent tree
- if(spentPoints < (talentInfo->Row * 5))
- return;
-
- // spell not set in talent.dbc
- uint32 spellid = talentInfo->RankID[requested_rank];
- if( spellid == 0 )
- {
- sLog.outError("Talent.dbc have for talent: %u Rank: %u spell id = 0", talent_id, requested_rank);
- return;
- }
-
- // already known
- if(GetPlayer( )->HasSpell(spellid))
- return;
-
- // learn! (other talent ranks will unlearned at learning)
- GetPlayer( )->learnSpell(spellid);
- sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talent_id, requested_rank, spellid);
-
- // update free talent points
- GetPlayer()->SetFreeTalentPoints(CurTalentPoints - 1);
+ _player->LearnTalent(talent_id, requested_rank);
}
void WorldSession::HandleTalentWipeOpcode( WorldPacket & recv_data )
@@ -148,7 +46,7 @@ void WorldSession::HandleTalentWipeOpcode( WorldPacket & recv_data )
uint64 guid;
recv_data >> guid;
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid,UNIT_NPC_FLAG_TRAINER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleTalentWipeOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -157,7 +55,7 @@ void WorldSession::HandleTalentWipeOpcode( WorldPacket & recv_data )
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if(!(_player->resetTalents()))
{
diff --git a/src/game/SocialMgr.cpp b/src/game/SocialMgr.cpp
index 8f9db3e469d..fb0e1574d08 100644
--- a/src/game/SocialMgr.cpp
+++ b/src/game/SocialMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@
#include "Database/DatabaseEnv.h"
#include "Opcodes.h"
#include "WorldPacket.h"
-#include "WorldSession.h"
#include "Player.h"
#include "ObjectMgr.h"
#include "World.h"
@@ -44,10 +43,10 @@ PlayerSocial::~PlayerSocial()
uint32 PlayerSocial::GetNumberOfSocialsWithFlag(SocialFlag flag)
{
uint32 counter = 0;
- for(PlayerSocialMap::iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
+ for(PlayerSocialMap::const_iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
{
if(itr->second.Flags & flag)
- counter++;
+ ++counter;
}
return counter;
}
@@ -70,7 +69,7 @@ bool PlayerSocial::AddToSocialList(uint32 friend_guid, bool ignore)
if(ignore)
flag = SOCIAL_FLAG_IGNORED;
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
+ PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
if(itr != m_playerSocialMap.end())
{
CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags | %u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
@@ -110,7 +109,7 @@ void PlayerSocial::RemoveFromSocialList(uint32 friend_guid, bool ignore)
void PlayerSocial::SetFriendNote(uint32 friend_guid, std::string note)
{
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
+ PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
if(itr == m_playerSocialMap.end()) // not exist
return;
@@ -158,7 +157,7 @@ void PlayerSocial::SendSocialList()
bool PlayerSocial::HasFriend(uint32 friend_guid)
{
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
+ PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(friend_guid);
if(itr != m_playerSocialMap.end())
return itr->second.Flags & SOCIAL_FLAG_FRIEND;
return false;
@@ -166,7 +165,7 @@ bool PlayerSocial::HasFriend(uint32 friend_guid)
bool PlayerSocial::HasIgnore(uint32 ignore_guid)
{
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(ignore_guid);
+ PlayerSocialMap::const_iterator itr = m_playerSocialMap.find(ignore_guid);
if(itr != m_playerSocialMap.end())
return itr->second.Flags & SOCIAL_FLAG_IGNORED;
return false;
@@ -182,13 +181,6 @@ SocialMgr::~SocialMgr()
}
-void SocialMgr::RemovePlayerSocial(uint32 guid)
-{
- SocialMap::iterator itr = m_socialMap.find(guid);
- if(itr != m_socialMap.end())
- m_socialMap.erase(itr);
-}
-
void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &friendInfo)
{
if(!player)
@@ -204,7 +196,7 @@ void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &fri
return;
uint32 team = player->GetTeam();
- uint32 security = player->GetSession()->GetSecurity();
+ AccountTypes security = player->GetSession()->GetSecurity();
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || security > SEC_PLAYER;
@@ -250,6 +242,8 @@ void SocialMgr::SendFriendStatus(Player *player, FriendsResult result, uint32 fr
case FRIEND_ADDED_ONLINE:
data << fi.Note;
break;
+ default:
+ break;
}
switch(result)
@@ -261,6 +255,8 @@ void SocialMgr::SendFriendStatus(Player *player, FriendsResult result, uint32 fr
data << uint32(fi.Level);
data << uint32(fi.Class);
break;
+ default:
+ break;
}
if(broadcast)
@@ -275,14 +271,14 @@ void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet)
return;
uint32 team = player->GetTeam();
- uint32 security = player->GetSession()->GetSecurity();
+ AccountTypes security = player->GetSession()->GetSecurity();
uint32 guid = player->GetGUIDLow();
bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
- for(SocialMap::iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr)
+ for(SocialMap::const_iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr)
{
- PlayerSocialMap::iterator itr2 = itr->second.m_playerSocialMap.find(guid);
+ PlayerSocialMap::const_iterator itr2 = itr->second.m_playerSocialMap.find(guid);
if(itr2 != itr->second.m_playerSocialMap.end() && (itr2->second.Flags & SOCIAL_FLAG_FRIEND))
{
Player *pFriend = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
diff --git a/src/game/SocialMgr.h b/src/game/SocialMgr.h
index f5bf3c8600c..1ca04d69707 100644
--- a/src/game/SocialMgr.h
+++ b/src/game/SocialMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -143,7 +143,8 @@ class SocialMgr
SocialMgr();
~SocialMgr();
// Misc
- void RemovePlayerSocial(uint32 guid);
+ void RemovePlayerSocial(uint32 guid) { m_socialMap.erase(guid); }
+
void GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &friendInfo);
// Packet management
void MakeFriendStatusPacket(FriendsResult result, uint32 friend_guid, WorldPacket *data);
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index 4fdd26c806f..bcca1f2c873 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,9 +33,9 @@
#include "Player.h"
#include "Pet.h"
#include "Unit.h"
+#include "Totem.h"
#include "Spell.h"
#include "DynamicObject.h"
-#include "SpellAuras.h"
#include "Group.h"
#include "UpdateData.h"
#include "MapManager.h"
@@ -43,14 +43,13 @@
#include "CellImpl.h"
#include "Policies/SingletonImp.h"
#include "SharedDefines.h"
-#include "Tools.h"
#include "LootMgr.h"
#include "VMapFactory.h"
#include "BattleGround.h"
#include "Util.h"
#include "TemporarySummon.h"
-#define SPELL_CHANNEL_UPDATE_INTERVAL 1000
+#define SPELL_CHANNEL_UPDATE_INTERVAL (1*IN_MILISECONDS)
extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
@@ -63,6 +62,54 @@ bool IsQuestTameSpell(uint32 spellId)
&& spellproto->Effect[1] == SPELL_EFFECT_APPLY_AURA && spellproto->EffectApplyAuraName[1] == SPELL_AURA_DUMMY;
}
+class PrioritizeManaWraper
+{
+ friend struct PrioritizeMana;
+
+ public:
+ explicit PrioritizeManaWraper(Unit * unit) : unit(unit)
+ {
+ uint32 maxmana = unit->GetMaxPower(POWER_MANA);
+ percentMana = maxmana ? unit->GetPower(POWER_MANA) * 100 / maxmana : 101;
+ }
+ Unit* getUnit() const { return unit; }
+ private:
+ Unit* unit;
+ uint32 percentMana;
+};
+
+struct PrioritizeMana
+{
+ int operator()( PrioritizeManaWraper const& x, PrioritizeManaWraper const& y ) const
+ {
+ return x.percentMana > y.percentMana;
+ }
+};
+
+class PrioritizeHealthWraper
+{
+ friend struct PrioritizeHealth;
+
+ public:
+ explicit PrioritizeHealthWraper(Unit * unit) : unit(unit)
+ {
+ uint32 maxhp = unit->GetMaxHealth();
+ percentHealth = maxhp ? unit->GetHealth() * 100 / maxhp : 101;
+ }
+ Unit* getUnit() const { return unit; }
+ private:
+ Unit* unit;
+ uint32 percentHealth;
+};
+
+struct PrioritizeHealth
+{
+ int operator()( PrioritizeHealthWraper const& x, PrioritizeHealthWraper const& y ) const
+ {
+ return x.percentHealth > y.percentHealth;
+ }
+};
+
SpellCastTargets::SpellCastTargets()
{
m_unitTarget = NULL;
@@ -130,6 +177,14 @@ void SpellCastTargets::setDestination(WorldObject *target)
m_targetMask |= TARGET_FLAG_DEST_LOCATION;
}
+/*void SpellCastTargets::setSource(float x, float y, float z)
+{
+ m_srcX = x;
+ m_srcY = y;
+ m_srcZ = z;
+ m_targetMask |= TARGET_FLAG_SOURCE_LOCATION;
+}*/
+
void SpellCastTargets::setGOTarget(GameObject *target)
{
m_GOTarget = target;
@@ -155,7 +210,7 @@ void SpellCastTargets::setCorpseTarget(Corpse* corpse)
void SpellCastTargets::Update(Unit* caster)
{
- m_GOTarget = m_GOTargetGUID ? ObjectAccessor::GetGameObject(*caster,m_GOTargetGUID) : NULL;
+ m_GOTarget = m_GOTargetGUID ? caster->GetMap()->GetGameObject(m_GOTargetGUID) : NULL;
m_unitTarget = m_unitTargetGUID ?
( m_unitTargetGUID==caster->GetGUID() ? caster : ObjectAccessor::GetUnit(*caster, m_unitTargetGUID) ) :
NULL;
@@ -182,6 +237,8 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
if(data->rpos()+4 > data->size())
return false;
+ //data->hexlike();
+
*data >> m_targetMask;
sLog.outDebug("Spell read, target mask = %u", m_targetMask);
@@ -189,16 +246,20 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
return true;
// TARGET_FLAG_UNK2 is used for non-combat pets, maybe other?
- if( m_targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2) )
- if(!readGUID(*data, m_unitTargetGUID))
+ if( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_UNK2 ))
+ if(!data->readPackGUID(m_unitTargetGUID))
return false;
- if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK ))
- if(!readGUID(*data, m_GOTargetGUID))
+ if( m_targetMask & ( TARGET_FLAG_OBJECT ))
+ if(!data->readPackGUID(m_GOTargetGUID))
return false;
if(( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM )) && caster->GetTypeId() == TYPEID_PLAYER)
- if(!readGUID(*data, m_itemTargetGUID))
+ if(!data->readPackGUID(m_itemTargetGUID))
+ return false;
+
+ if( m_targetMask & (TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) )
+ if(!data->readPackGUID(m_CorpseTargetGUID))
return false;
if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
@@ -213,7 +274,10 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
if( m_targetMask & TARGET_FLAG_DEST_LOCATION )
{
- if(data->rpos()+4+4+4 > data->size())
+ if(data->rpos()+1+4+4+4 > data->size())
+ return false;
+
+ if(!data->readPackGUID(m_unitTargetGUID))
return false;
*data >> m_destX >> m_destY >> m_destZ;
@@ -229,10 +293,6 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
*data >> m_strTarget;
}
- if( m_targetMask & (TARGET_FLAG_CORPSE | TARGET_FLAG_PVP_CORPSE ) )
- if(!readGUID(*data, m_CorpseTargetGUID))
- return false;
-
// find real units/GOs
Update(caster);
return true;
@@ -252,7 +312,7 @@ void SpellCastTargets::write ( WorldPacket * data )
else
*data << uint8(0);
}
- else if( m_targetMask & ( TARGET_FLAG_OBJECT | TARGET_FLAG_OBJECT_UNK ) )
+ else if( m_targetMask & TARGET_FLAG_OBJECT )
{
if(m_GOTarget)
data->append(m_GOTarget->GetPackGUID());
@@ -277,7 +337,14 @@ void SpellCastTargets::write ( WorldPacket * data )
*data << m_srcX << m_srcY << m_srcZ;
if( m_targetMask & TARGET_FLAG_DEST_LOCATION )
+ {
+ if(m_unitTarget)
+ data->append(m_unitTarget->GetPackGUID());
+ else
+ *data << uint8(0);
+
*data << m_destX << m_destY << m_destZ;
+ }
if( m_targetMask & TARGET_FLAG_STRING )
*data << m_strTarget;
@@ -293,10 +360,14 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_triggeringContainer = triggeringContainer;
m_referencedFromCurrentSpell = false;
m_executedCurrently = false;
+ m_needComboPoints = NeedsComboPoints(m_spellInfo);
m_delayStart = 0;
m_delayAtDamageCount = 0;
+ m_canTrigger=true;
+
m_applyMultiplierMask = 0;
+ m_effectMask = 0;
// Get data for type of attack
switch (m_spellInfo->DmgClass)
@@ -308,11 +379,11 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_attackType = BASE_ATTACK;
break;
case SPELL_DAMAGE_CLASS_RANGED:
- m_attackType = RANGED_ATTACK;
+ m_attackType = IsRangedWeaponSpell(m_spellInfo) ? RANGED_ATTACK : BASE_ATTACK;
break;
default:
// Wands
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_WAND)
+ if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG)
m_attackType = RANGED_ATTACK;
else
m_attackType = BASE_ATTACK;
@@ -327,7 +398,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER)
{
if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK))
- m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType);
+ m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage[0].DamageType);
}
}
// Set health leech amount to zero
@@ -362,14 +433,15 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
gameObjTarget = NULL;
focusObject = NULL;
m_cast_count = 0;
+ m_glyphIndex = 0;
+ m_preCastSpell = 0;
m_triggeredByAuraSpell = NULL;
+ m_spellAura = NULL;
- //Auto Shot & Shoot
- if( m_spellInfo->AttributesEx2 == 0x000020 && !triggered )
- m_autoRepeat = true;
- else
- m_autoRepeat = false;
+ //Auto Shot & Shoot (wand)
+ m_autoRepeat = IsAutoRepeatRangedSpell(m_spellInfo);
+ m_runesState = 0;
m_powerCost = 0; // setup to correct value in Spell::prepare, don't must be used before.
m_casttime = 0; // setup to correct value in Spell::prepare, don't must be used before.
m_timer = 0; // will set to castime in prepare
@@ -379,7 +451,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
// determine reflection
m_canReflect = false;
- if(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && (m_spellInfo->AttributesEx2 & 0x4)==0)
+ if(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED))
{
for(int j=0;j<3;j++)
{
@@ -406,6 +478,35 @@ Spell::~Spell()
delete m_spellValue;
}
+template<typename T>
+WorldObject* Spell::FindCorpseUsing()
+{
+ // non-standard target selection
+ float max_range = GetSpellMaxRange(m_spellInfo, false);
+
+ CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ WorldObject* result = NULL;
+
+ T u_check(m_caster, max_range);
+ MaNGOS::WorldObjectSearcher<T> searcher(m_caster, result, u_check);
+
+ TypeContainerVisitor<MaNGOS::WorldObjectSearcher<T>, GridTypeMapContainer > grid_searcher(searcher);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_searcher, *m_caster->GetMap());
+
+ if (!result)
+ {
+ TypeContainerVisitor<MaNGOS::WorldObjectSearcher<T>, WorldTypeMapContainer > world_searcher(searcher);
+ cell_lock->Visit(cell_lock, world_searcher, *m_caster->GetMap());
+ }
+
+ return result;
+}
+
void Spell::FillTargetMap()
{
for(uint32 i = 0; i < 3; ++i)
@@ -441,8 +542,20 @@ void Spell::FillTargetMap()
continue;
}
+ if(/*tmpUnitMap.empty() && */m_spellInfo->Targets & TARGET_FLAG_CASTER)
+ {
+ AddUnitTarget(m_caster, i);
+ continue;
+ }
+
if(!targetA && !targetB)
{
+ if(!GetSpellMaxRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)))
+ {
+ AddUnitTarget(m_caster, i);
+ continue;
+ }
+
// add here custom effects that need default target.
// FOR EVERY TARGET TYPE THERE IS A DIFFERENT FILL!!
switch(m_spellInfo->Effect[i])
@@ -453,17 +566,7 @@ void Spell::FillTargetMap()
{
case 20577: // Cannibalize
{
- // non-standard target selection
- SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
- float max_range = GetSpellMaxRange(srange);
- WorldObject* result = NULL;
-
- Trinity::CannibalizeObjectCheck u_check(m_caster, max_range);
- Trinity::WorldObjectSearcher<Trinity::CannibalizeObjectCheck > searcher(result, u_check);
- m_caster->VisitNearbyGridObject(max_range, searcher);
- if(!result)
- m_caster->VisitNearbyWorldObject(max_range, searcher);
-
+ WorldObject* result = FindCorpseUsing<MaNGOS::CannibalizeObjectCheck> ();
if(result)
{
@@ -484,15 +587,7 @@ void Spell::FillTargetMap()
{
// clear cooldown at fail
if(m_caster->GetTypeId()==TYPEID_PLAYER)
- {
- ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
-
- WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
- data << uint32(m_spellInfo->Id);
- data << uint64(m_caster->GetGUID());
- ((Player*)m_caster)->GetSession()->SendPacket(&data);
- }
-
+ ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true);
SendCastResult(SPELL_FAILED_NO_EDIBLE_CORPSES);
finish(false);
}
@@ -501,6 +596,8 @@ void Spell::FillTargetMap()
default:
if(m_targets.getUnitTarget())
AddUnitTarget(m_targets.getUnitTarget(), i);
+ else
+ AddUnitTarget(m_caster, i);
break;
}
break;
@@ -509,12 +606,16 @@ void Spell::FillTargetMap()
case SPELL_EFFECT_CREATE_ITEM:
case SPELL_EFFECT_TRIGGER_SPELL:
case SPELL_EFFECT_SKILL_STEP:
+ case SPELL_EFFECT_PROFICIENCY:
+ case SPELL_EFFECT_SUMMON_OBJECT_WILD:
case SPELL_EFFECT_SELF_RESURRECT:
case SPELL_EFFECT_REPUTATION:
case SPELL_EFFECT_LEARN_SPELL:
+ case SPELL_EFFECT_SEND_TAXI:
if(m_targets.getUnitTarget())
AddUnitTarget(m_targets.getUnitTarget(), i);
- else
+ // Triggered spells have additional spell targets - cast them even if no explicit unit target is given (required for spell 50516 for example)
+ else if(m_spellInfo->Effect[i] == SPELL_EFFECT_TRIGGER_SPELL)
AddUnitTarget(m_caster, i);
break;
case SPELL_EFFECT_SUMMON_PLAYER:
@@ -541,19 +642,23 @@ void Spell::FillTargetMap()
break;
case SPELL_EFFECT_SUMMON_CHANGE_ITEM:
case SPELL_EFFECT_ADD_FARSIGHT:
+ case SPELL_EFFECT_APPLY_GLYPH:
case SPELL_EFFECT_STUCK:
+ case SPELL_EFFECT_FEED_PET:
case SPELL_EFFECT_DESTROY_ALL_TOTEMS:
+ case SPELL_EFFECT_KILL_CREDIT2: // only one spell: 42793
AddUnitTarget(m_caster, i);
break;
case SPELL_EFFECT_LEARN_PET_SPELL:
- if(Pet* pet = m_caster->GetPet())
+ if(Guardian* pet = m_caster->GetGuardianPet())
AddUnitTarget(pet, i);
break;
/*case SPELL_EFFECT_ENCHANT_ITEM:
case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
+ case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC:
case SPELL_EFFECT_DISENCHANT:
- case SPELL_EFFECT_FEED_PET:
case SPELL_EFFECT_PROSPECTING:
+ case SPELL_EFFECT_MILLING:
if(m_targets.getItemTarget())
AddItemTarget(m_targets.getItemTarget(), i);
break;*/
@@ -590,6 +695,7 @@ void Spell::FillTargetMap()
}
break;
default:
+ AddUnitTarget(m_caster, i);
break;
}
}
@@ -619,44 +725,39 @@ void Spell::FillTargetMap()
}
}
-void Spell::prepareDataForTriggerSystem()
+void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura)
{
//==========================================================================================
// Now fill data for trigger system, need know:
- // Ñan spell trigger another or not ( m_canTrigger )
- // Create base triggers flags for Attacker and Victim ( m_procAttacker and m_procVictim)
+ // can spell trigger another or not ( m_canTrigger )
+ // Create base triggers flags for Attacker and Victim ( m_procAttacker, m_procVictim and m_procEx)
//==========================================================================================
- // Fill flag can spell trigger or not
- if (!m_IsTriggeredSpell)
- m_canTrigger = true; // Normal cast - can trigger
- else if (!m_triggeredByAuraSpell)
- m_canTrigger = true; // Triggered from SPELL_EFFECT_TRIGGER_SPELL - can trigger
- else // Exceptions (some periodic triggers)
+ /*
+ Effects which are result of aura proc from triggered spell cannot proc
+ to prevent chain proc of these spells
+ */
+
+ if (triggeredByAura && !triggeredByAura->GetParentAura()->GetTarget()->CanProc())
{
- m_canTrigger = false; // Triggered spells can`t trigger another
- switch (m_spellInfo->SpellFamilyName)
- {
- case SPELLFAMILY_MAGE: // Arcane Missles / Blizzard triggers need do it
- if (m_spellInfo->SpellFamilyFlags & 0x0000000000200080LL) m_canTrigger = true;
- break;
- case SPELLFAMILY_WARLOCK: // For Hellfire Effect / Rain of Fire / Seed of Corruption triggers need do it
- if (m_spellInfo->SpellFamilyFlags & 0x0000800000000060LL) m_canTrigger = true;
- break;
- case SPELLFAMILY_HUNTER: // Hunter Explosive Trap Effect/Immolation Trap Effect/Frost Trap Aura/Snake Trap Effect
- if (m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL) m_canTrigger = true;
- break;
- case SPELLFAMILY_PALADIN: // For Holy Shock triggers need do it
- if (m_spellInfo->SpellFamilyFlags & 0x0001000000200000LL) m_canTrigger = true;
- break;
- case SPELLFAMILY_ROGUE: // mutilate mainhand + offhand
- if (m_spellInfo->SpellFamilyFlags & 0x600000000LL) m_canTrigger = true;
- break;
- }
+ m_canTrigger=false;
+ }
+
+ m_procEx = (m_IsTriggeredSpell)
+ && !(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER)
+ && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2)
+ ? PROC_EX_INTERNAL_TRIGGERED : PROC_EX_NONE;
+
+ if (m_IsTriggeredSpell &&
+ (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER ||
+ m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2))
+ m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
+
+ // Totem casts require spellfamilymask defined in spell_proc_event to proc
+ if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isTotem() && m_caster->IsControlledByPlayer())
+ {
+ m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
}
- // Do not trigger from item cast spell
- if (m_CastItem)
- m_canTrigger = false;
// Get data for type of attack and fill base info for trigger
switch (m_spellInfo->DmgClass)
@@ -666,21 +767,30 @@ void Spell::prepareDataForTriggerSystem()
m_procVictim = PROC_FLAG_TAKEN_MELEE_SPELL_HIT;
break;
case SPELL_DAMAGE_CLASS_RANGED:
- m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
- m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
+ // Auto attack
+ if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG)
+ {
+ m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT;
+ m_procVictim = PROC_FLAG_TAKEN_RANGED_HIT;
+ }
+ else // Ranged spell attack
+ {
+ m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
+ m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
+ }
break;
default:
- if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell
+ if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;
m_procVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL;
}
- else if (m_spellInfo->Id == 5019) // Wands
+ else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack
{
- m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
- m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
+ m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT;
+ m_procVictim = PROC_FLAG_TAKEN_RANGED_HIT;
}
- else
+ else // Negative spell
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
m_procVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
@@ -689,7 +799,7 @@ void Spell::prepareDataForTriggerSystem()
}
// Hunter traps spells (for Entrapment trigger)
// Gives your Immolation Trap, Frost Trap, Explosive Trap, and Snake Trap ....
- if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL)
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (m_spellInfo->SpellFamilyFlags[1] & 0x00002000 || m_spellInfo->SpellFamilyFlags[0] & 0x1C))
m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION;
}
@@ -698,8 +808,6 @@ void Spell::CleanupTargetList()
m_UniqueTargetInfo.clear();
m_UniqueGOTargetInfo.clear();
m_UniqueItemInfo.clear();
- m_countOfHit = 0;
- m_countOfMiss = 0;
m_delayMoment = 0;
}
@@ -711,6 +819,9 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
if(!CheckTarget(pVictim, effIndex))
return;
+ // Check for effect immune skip if immuned
+ bool immuned = pVictim->IsImmunedToSpellEffect(m_spellInfo, effIndex);
+
uint64 targetGUID = pVictim->GetGUID();
// Lookup target in already in list
@@ -718,7 +829,8 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
{
if (targetGUID == ihit->targetGUID) // Found in list
{
- ihit->effectMask |= 1<<effIndex; // Add only effect mask
+ if (!immuned)
+ ihit->effectMask |= 1<<effIndex; // Add only effect mask if not immuned
return;
}
}
@@ -728,8 +840,9 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
// Get spell hit result on target
TargetInfo target;
target.targetGUID = targetGUID; // Store target GUID
- target.effectMask = 1<<effIndex; // Store index of effect
+ target.effectMask = immuned ? 0 : 1<<effIndex; // Store index of effect if not immuned
target.processed = false; // Effects not apply on target
+ target.alive = pVictim->isAlive();
target.damage = 0;
// Calculate hit result
@@ -742,11 +855,6 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
else
target.missCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE;
- if (target.missCondition == SPELL_MISS_NONE)
- ++m_countOfHit;
- else
- ++m_countOfMiss;
-
// Spell have speed - need calculate incoming time
if (m_spellInfo->speed > 0.0f)
{
@@ -827,15 +935,13 @@ void Spell::AddGOTarget(GameObject* pVictim, uint32 effIndex)
else
target.timeDelay = 0LL;
- ++m_countOfHit;
-
// Add target to list
m_UniqueGOTargetInfo.push_back(target);
}
void Spell::AddGOTarget(uint64 goGUID, uint32 effIndex)
{
- GameObject* go = ObjectAccessor::GetGameObject(*m_caster, goGUID);
+ GameObject* go = m_caster->GetMap()->GetGameObject(goGUID);
if (go)
AddGOTarget(go, effIndex);
}
@@ -862,83 +968,6 @@ void Spell::AddItemTarget(Item* pitem, uint32 effIndex)
target.effectMask = 1<<effIndex;
m_UniqueItemInfo.push_back(target);
}
-/*
-void Spell::doTriggers(SpellMissInfo missInfo, uint32 damage, SpellSchoolMask damageSchoolMask, uint32 block, uint32 absorb, bool crit)
-{
- // Do triggers depends from hit result (triggers on hit do in effects)
- // Set aura states depends from hit result
- if (missInfo!=SPELL_MISS_NONE)
- {
- // Miss/dodge/parry/block only for melee based spells
- // Resist only for magic based spells
- switch (missInfo)
- {
- case SPELL_MISS_MISS:
- if(m_caster->GetTypeId()== TYPEID_PLAYER)
- ((Player*)m_caster)->UpdateWeaponSkill(BASE_ATTACK);
-
- m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_MISS, m_spellInfo, m_IsTriggeredSpell);
- break;
- case SPELL_MISS_RESIST:
- m_caster->ProcDamageAndSpell(unitTarget, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, damageSchoolMask, m_spellInfo, m_IsTriggeredSpell);
- break;
- case SPELL_MISS_DODGE:
- if(unitTarget->GetTypeId() == TYPEID_PLAYER)
- ((Player*)unitTarget)->UpdateDefense();
-
- // Overpower
- if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARRIOR)
- {
- ((Player*) m_caster)->AddComboPoints(unitTarget, 1);
- m_caster->StartReactiveTimer( REACTIVE_OVERPOWER );
- }
-
- // Riposte
- if (unitTarget->getClass() != CLASS_ROGUE)
- {
- unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true);
- unitTarget->StartReactiveTimer( REACTIVE_DEFENSE );
- }
-
- m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_DODGE, m_spellInfo, m_IsTriggeredSpell);
- break;
- case SPELL_MISS_PARRY:
- // Update victim defense ?
- if(unitTarget->GetTypeId() == TYPEID_PLAYER)
- ((Player*)unitTarget)->UpdateDefense();
- // Mongoose bite - set only Counterattack here
- if (unitTarget->getClass() == CLASS_HUNTER)
- {
- unitTarget->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true);
- unitTarget->StartReactiveTimer( REACTIVE_HUNTER_PARRY );
- }
- else
- {
- unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true);
- unitTarget->StartReactiveTimer( REACTIVE_DEFENSE );
- }
- m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_PARRY, m_spellInfo, m_IsTriggeredSpell);
- break;
- case SPELL_MISS_BLOCK:
- unitTarget->ModifyAuraState(AURA_STATE_DEFENSE, true);
- unitTarget->StartReactiveTimer( REACTIVE_DEFENSE );
-
- m_caster->CastMeleeProcDamageAndSpell(unitTarget, 0, damageSchoolMask, m_attackType, MELEE_HIT_BLOCK, m_spellInfo, m_IsTriggeredSpell);
- break;
- // Trigger from this events not supported
- case SPELL_MISS_EVADE:
- case SPELL_MISS_IMMUNE:
- case SPELL_MISS_IMMUNE2:
- case SPELL_MISS_DEFLECT:
- case SPELL_MISS_ABSORB:
- // Trigger from reflects need do after get reflect result
- case SPELL_MISS_REFLECT:
- break;
- default:
- break;
- }
- }
-}*/
void Spell::DoAllEffectOnTarget(TargetInfo *target)
{
@@ -948,15 +977,16 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
// Get mask of effects for target
uint32 mask = target->effectMask;
- if (mask == 0) // No effects
- return;
Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID);
if (!unit)
return;
+ if(unit->isAlive() != target->alive)
+ return;
+
// Get original caster (if exist) and calculate damage/healing from him data
- Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
+ Unit *caster = m_originalCaster ? m_originalCaster : m_caster;
// Skip if m_originalCaster not avaiable
if (!caster)
@@ -975,30 +1005,38 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
uint32 procVictim = m_procVictim;
- uint32 procEx = PROC_EX_NONE;
+ uint32 procEx = m_procEx;
+
+ m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
//Spells with this flag cannot trigger if effect is casted on self
// Slice and Dice, relentless strikes, eviscerate
- bool canEffectTrigger = (m_spellInfo->AttributesEx4 & (SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST | SPELL_ATTR_EX4_UNK4) ? m_caster!=unitTarget : true)
- && m_canTrigger;
+ bool canEffectTrigger = m_canTrigger && (m_spellInfo->AttributesEx4 & (SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST | SPELL_ATTR_EX4_UNK4) ? m_caster!=unitTarget : true);
+ Unit * spellHitTarget = NULL;
if (missInfo==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
- DoSpellHitOnUnit(unit, mask);
+ spellHitTarget = unit;
else if (missInfo == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit)
{
if (target->reflectResult == SPELL_MISS_NONE) // If reflected spell hit caster -> do all effect on him
- DoSpellHitOnUnit(m_caster, mask);
+ spellHitTarget = m_caster;
}
- /*else //TODO: This is a hack. need fix
+
+ if(spellHitTarget)
{
- uint32 tempMask = 0;
- for(uint32 i = 0; i < 3; ++i)
- if(m_spellInfo->Effect[i] == SPELL_EFFECT_DUMMY
- || m_spellInfo->Effect[i] == SPELL_EFFECT_TRIGGER_SPELL)
- tempMask |= 1<<i;
- if(tempMask &= mask)
- DoSpellHitOnUnit(unit, tempMask);
- }*/
+ SpellMissInfo missInfo = DoSpellHitOnUnit(spellHitTarget, mask);
+ if(missInfo != SPELL_MISS_NONE)
+ {
+ m_caster->SendSpellMiss(unit, m_spellInfo->Id, missInfo);
+ m_damage = 0;
+ spellHitTarget = NULL;
+ }
+ }
+
+ // Do not take combo points on dodge
+ if (m_needComboPoints && m_targets.getUnitTargetGUID() == target->targetGUID)
+ if( missInfo != SPELL_MISS_NONE && missInfo != SPELL_MISS_MISS)
+ m_needComboPoints = false;
// All calculated do it!
// Do healing and triggers
@@ -1009,23 +1047,20 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
if (crit)
{
procEx |= PROC_EX_CRITICAL_HIT;
- addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, NULL);
+ addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, NULL);
}
else
procEx |= PROC_EX_NORMAL_HIT;
- caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
-
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo);
+ caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
- int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
+ if (m_spellAura)
+ m_spellAura->SetProcDamage(addhealth);
+ int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo, crit);
unitTarget->getHostilRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
- if(caster->GetTypeId()==TYPEID_PLAYER)
- if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
- bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
}
// Do damage and triggers
else if (m_damage > 0)
@@ -1035,127 +1070,115 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
// Add bonuses and fill damageInfo struct
caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo);
+ caster->DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
- procEx = createProcExtendMask(&damageInfo, missInfo);
+ procEx |= createProcExtendMask(&damageInfo, missInfo);
procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo);
+ caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
+
+ if (m_spellAura)
+ m_spellAura->SetProcDamage(damageInfo.damage);
caster->DealSpellDamage(&damageInfo, true);
- // Shadow Word: Death - deals damage equal to damage done to caster if victim is not killed
- if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags&0x0000000200000000LL &&
- caster != unitTarget && unitTarget->isAlive())
- {
- // Redirect damage to caster if victim Alive
- damageInfo.target = caster;
- damageInfo.absorb = 0;
- damageInfo.resist = 0;
- damageInfo.blocked = 0;
- // Send log damage message to client
- caster->SendSpellNonMeleeDamageLog(&damageInfo);
- caster->DealSpellDamage(&damageInfo, true);
- }
// Judgement of Blood
- else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL && m_spellInfo->SpellIconID==153)
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags[1] & 0x00000008 && m_spellInfo->SpellIconID==153)
{
int32 damagePoint = damageInfo.damage * 33 / 100;
m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
}
- // Bloodthirst
- else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
- {
- uint32 BTAura = 0;
- switch(m_spellInfo->Id)
- {
- case 23881: BTAura = 23885; break;
- case 23892: BTAura = 23886; break;
- case 23893: BTAura = 23887; break;
- case 23894: BTAura = 23888; break;
- case 25251: BTAura = 25252; break;
- case 30335: BTAura = 30339; break;
- default:
- sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
- break;
- }
- if (BTAura)
- m_caster->CastSpell(m_caster,BTAura,true);
- }
}
// Passive spell hits/misses or active spells only misses (only triggers)
else
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
- procEx = createProcExtendMask(&damageInfo, missInfo);
+ procEx |= createProcExtendMask(&damageInfo, missInfo);
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
- caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo);
- }
-
- // Call scripted function for AI if this spell is casted upon a creature (except pets)
- if(IS_CREATURE_GUID(target->targetGUID))
- {
- // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
- // ignore autorepeat/melee casts for speed (not exist quest for spells (hm... )
- if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() )
- ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id);
+ caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
}
if( !m_caster->IsFriendlyTo(unit) && !IsPositiveSpell(m_spellInfo->Id))
{
- if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) )
+ if( !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) )
{
m_caster->CombatStart(unit);
}
else if(m_customAttr & SPELL_ATTR_CU_AURA_CC)
{
if(!unit->IsStandState())
- unit->SetStandState(PLAYER_STATE_NONE);
+ unit->SetStandState(UNIT_STAND_STATE_STAND);
+ }
+ }
+
+ if(spellHitTarget)
+ {
+ //AI functions
+ if(spellHitTarget->GetTypeId() == TYPEID_UNIT)
+ {
+ if(((Creature*)spellHitTarget)->IsAIEnabled)
+ ((Creature*)spellHitTarget)->AI()->SpellHit(m_caster, m_spellInfo);
+
+ // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
+ // ignore pets or autorepeat/melee casts for speed (not exist quest for spells (hm... )
+ if(!((Creature*)spellHitTarget)->isPet() && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() )
+ {
+ if ( Player* p = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself() )
+ p->CastedCreatureOrGO(spellHitTarget->GetEntry(),spellHitTarget->GetGUID(),m_spellInfo->Id);
+ }
}
+
+ if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->IsAIEnabled)
+ ((Creature*)m_caster)->AI()->SpellHitTarget(spellHitTarget, m_spellInfo);
+
+ // Needs to be called after dealing damage/healing to not remove breaking on damage auras
+ DoTriggersOnSpellHit(spellHitTarget);
}
}
-void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
+SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
{
if(!unit || !effectMask)
- return;
+ return SPELL_MISS_EVADE;
// Recheck immune (only for delayed spells)
- if( m_spellInfo->speed &&
- !(m_spellInfo->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)
- && (unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo),true) ||
- unit->IsImmunedToSpell(m_spellInfo,true) ))
+ if(m_spellInfo->speed && (unit->IsImmunedToDamage(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo)))
+ return SPELL_MISS_IMMUNE;
+
+ if (unit->GetTypeId() == TYPEID_PLAYER)
{
- m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE);
- m_damage = 0;
- return;
+ ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id);
+ ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, m_spellInfo->Id);
+ }
+
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, unit);
}
if( m_caster != unit )
{
- if (unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
+ // Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
+ if (m_spellInfo->speed > 0.0f &&
+ unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) &&
+ unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
{
- if (unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
- {
- m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
- m_damage = 0;
- return;
- }
+ return SPELL_MISS_EVADE;
}
+
if( !m_caster->IsFriendlyTo(unit) )
{
// for delayed spells ignore not visible explicit target
if(m_spellInfo->speed > 0.0f && unit==m_targets.getUnitTarget() && !unit->isVisibleForOrDetect(m_caster,false))
{
- m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
- m_damage = 0;
- return;
+ return SPELL_MISS_EVADE;
}
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL);
@@ -1168,9 +1191,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
// TODO: this cause soul transfer bugged
if(m_spellInfo->speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !IsPositiveSpell(m_spellInfo->Id))
{
- m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
- m_damage = 0;
- return;
+ return SPELL_MISS_EVADE;
}
// assisting case, healing and resurrection
@@ -1179,7 +1200,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
m_caster->SetContestedPvP();
//m_caster->UpdatePvP(true);
}
- if( unit->isInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) )
+ if( unit->isInCombat() && !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) )
{
m_caster->SetInCombatState(unit->GetCombatTimer() > 0);
unit->getHostilRefManager().threatAssist(m_caster, 0.0f);
@@ -1197,51 +1218,131 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
unit->IncrDiminishing(m_diminishGroup);
}
- for(uint32 effectNumber=0;effectNumber<3;effectNumber++)
+ uint8 aura_effmask = 0;
+ for (uint8 i = 0; i < 3; ++i)
+ if (effectMask & (1<<i) && (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA || IsAreaAuraEffect(m_spellInfo->Effect[i])))
+ aura_effmask |= 1<<i;
+
+ if (aura_effmask)
{
- if (effectMask & (1<<effectNumber))
+ Unit * caster = m_originalCaster ? m_originalCaster : m_caster;
+ Aura * Aur = new Aura(m_spellInfo, aura_effmask, m_currentBasePoints, unit, m_caster, caster, m_CastItem);
+
+ if (!Aur->IsAreaAura())
{
- HandleEffects(unit,NULL,NULL,effectNumber/*,m_damageMultipliers[effectNumber]*/);
- //Only damage and heal spells need this
- /*if ( m_applyMultiplierMask & (1 << effectNumber) )
+ // Now Reduce spell duration using data received at spell hit
+ int32 duration = Aur->GetAuraMaxDuration();
+ unit->ApplyDiminishingToDuration(m_diminishGroup,duration,caster,m_diminishLevel);
+ Aur->setDiminishGroup(m_diminishGroup);
+
+ duration = caster->ModSpellDuration(m_spellInfo, unit, duration, Aur->IsPositive());
+
+ //mod duration of channeled aura by spell haste
+ if (IsChanneledSpell(m_spellInfo))
+ caster->ModSpellCastTime(m_spellInfo, duration, this);
+
+ if(duration != Aur->GetAuraMaxDuration())
{
- // Get multiplier
- float multiplier = m_spellInfo->DmgMultiplier[effectNumber];
- // Apply multiplier mods
- if(m_originalCaster)
- if(Player* modOwner = m_originalCaster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier,this);
- m_damageMultipliers[effectNumber] *= multiplier;
- }*/
+ Aur->SetAuraMaxDuration(duration);
+ Aur->SetAuraDuration(duration);
+ }
+
+ // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
+ if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST)
+ {
+ if(m_spellInfo->SpellFamilyFlags[1] & 0x000020)
+ m_caster->CastSpell(unit, 41637, true, NULL, NULL, m_originalCasterGUID);
+ }
+ else
+ {
+ // spell is triggered with only stackamount change but no amount change
+ switch(m_spellInfo->Id)
+ {
+ case 28832: // Mark of Korth'azz
+ case 28833: // Mark of Blaumeux
+ case 28834: // Mark of Rivendare
+ case 28835: // Mark of Zeliek
+ {
+ Aura *aur = unit->GetAura(m_spellInfo->Id);
+ if(!aur) break;
+ //int8 stack = GetParentAura()->GetStackAmount();
+ int8 stack = aur->GetStackAmount();
+ ++stack;
+ int32 damage;
+ switch(stack)
+ {
+ case 1: damage = 0; break;
+ case 2: damage = 500; break;
+ case 3: damage = 1000; break;
+ case 4: damage = 1500; break;
+ case 5: damage = 4000; break;
+ case 6: damage = 12000; break;
+ default:damage = 20000 + 1000 * (stack - 7); break;
+ }
+ if(damage)
+ m_caster->CastCustomSpell(28836, SPELLVALUE_BASE_POINT0, damage, unit);
+ break;
+ }
+ }
+ }
}
+ // Set aura only when successfully applied
+ if (unit->AddAura(Aur, false))
+ m_spellAura = Aur;
}
- if(unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->IsAIEnabled)
- ((Creature*)unit)->AI()->SpellHit(m_caster, m_spellInfo);
+ for(uint32 effectNumber = 0; effectNumber < 3; ++effectNumber)
+ {
+ if (effectMask & (1<<effectNumber))
+ HandleEffects(unit,NULL,NULL,effectNumber);
+ }
- if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->IsAIEnabled)
- ((Creature*)m_caster)->AI()->SpellHitTarget(unit, m_spellInfo);
+ return SPELL_MISS_NONE;
+}
+
+void Spell::DoTriggersOnSpellHit(Unit *unit)
+{
+ // Apply additional spell effects to target
+ if (m_preCastSpell)
+ {
+ // Special spell id
+ // TODO: Handle all of special spells in one place?
+ if(m_preCastSpell==61988)
+ {
+ //Cast Forbearance
+ m_caster->CastSpell(unit,25771, true, m_CastItem);
+ // Cast Avenging Wrath Marker
+ m_caster->CastSpell(unit,61987, true, m_CastItem);
+ }
+ else
+ m_caster->CastSpell(unit,m_preCastSpell, true, m_CastItem);
+ }
// spells with this flag can trigger only if not selfcast (eviscerate for example)
- if (m_ChanceTriggerSpells.size() && (!(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST | SPELL_ATTR_EX4_UNK4) || unit!=m_caster))
+ if (m_ChanceTriggerSpells.size() && (!((m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST | SPELL_ATTR_EX4_UNK4) && unit==m_caster)))
{
int _duration=0;
for(ChanceTriggerSpells::const_iterator i = m_ChanceTriggerSpells.begin(); i != m_ChanceTriggerSpells.end(); ++i)
{
+ // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
+ // set duration equal to triggering spell
if(roll_chance_i(i->second))
{
m_caster->CastSpell(unit, i->first, true);
- // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
- // set duration equal to triggering spell
- if (GetSpellDuration(i->first)==-1)
+ sLog.outDebug("Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first);
+ }
+ if (GetSpellDuration(i->first)==-1)
+ {
+ if (Aura * triggeredAur = unit->GetAura(i->first->Id, m_caster->GetGUID()))
{
// get duration from aura-only once
if (!_duration)
{
- Aura * aur = unit->GetAuraByCasterSpell(m_spellInfo->Id, m_caster->GetGUID());
+ Aura * aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());
_duration = aur ? aur->GetAuraDuration() : -1;
}
- unit->SetAurasDurationByCasterSpell(i->first->Id, m_caster->GetGUID(), _duration);
+ triggeredAur->SetAuraDuration(_duration);
+ triggeredAur->SetPermanent(false);
}
}
}
@@ -1256,15 +1357,6 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
else
unit->CastSpell(unit, *i, true, 0, 0, m_caster->GetGUID());
}
-
- //This is not needed with procflag patch
- /*if(m_originalCaster)
- {
- if(m_customAttr & SPELL_ATTR_CU_EFFECT_HEAL)
- m_originalCaster->ProcDamageAndSpell(unit, PROC_FLAG_HEAL, PROC_FLAG_NONE, 0, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
- if(m_originalCaster != unit && (m_customAttr & SPELL_ATTR_CU_EFFECT_DAMAGE))
- m_originalCaster->ProcDamageAndSpell(unit, PROC_FLAG_HIT_SPELL, PROC_FLAG_STRUCK_SPELL, 0, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
- }*/
}
void Spell::DoAllEffectOnTarget(GOTargetInfo *target)
@@ -1277,7 +1369,7 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo *target)
if(!effectMask)
return;
- GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID);
+ GameObject* go = m_caster->GetMap()->GetGameObject(target->targetGUID);
if(!go)
return;
@@ -1287,8 +1379,11 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo *target)
// cast at creature (or GO) quest objectives update at successful cast finished (+channel finished)
// ignore autorepeat/melee casts for speed (not exist quest for spells (hm... )
- if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() )
- ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id);
+ if( !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive() )
+ {
+ if ( Player* p = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself() )
+ p->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id);
+ }
}
void Spell::DoAllEffectOnTarget(ItemTargetInfo *target)
@@ -1302,13 +1397,19 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo *target)
HandleEffects(NULL, target->item, NULL, effectNumber);
}
-bool Spell::IsAliveUnitPresentInTargetList()
+bool Spell::UpdateChanneledTargetList()
{
// Not need check return true
if (m_needAliveTargetMask == 0)
return true;
uint8 needAliveTargetMask = m_needAliveTargetMask;
+ uint8 needAuraMask = 0;
+ for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i)
+ if (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA)
+ needAuraMask |= 1<<i;
+
+ needAuraMask &= needAliveTargetMask;
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
{
@@ -1317,7 +1418,27 @@ bool Spell::IsAliveUnitPresentInTargetList()
Unit *unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
if (unit && unit->isAlive())
+ {
+ if (needAuraMask & ihit->effectMask)
+ {
+ if(Aura * aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID()))
+ {
+ float range = m_caster->GetSpellMaxRangeForTarget(unit,GetSpellRangeStore()->LookupEntry(m_spellInfo->rangeIndex));
+ if(Player * modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
+ if (m_caster != unit && !m_caster->IsWithinDistInMap(unit,range))
+ {
+ ihit->effectMask &= ~aur->GetEffectMask();
+ unit->RemoveAura(aur);
+ continue;
+ }
+ }
+ else
+ continue;
+ }
+
needAliveTargetMask &= ~ihit->effectMask; // remove from need alive mask effect that have alive target
+ }
}
}
@@ -1365,7 +1486,7 @@ struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit,
// functor for operator ">"
bool operator()(const Unit* _Left, const Unit* _Right) const
{
- return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right));
+ return MainTarget->GetDistanceOrder(_Left,_Right);
}
};
@@ -1375,6 +1496,16 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin
if(!cur)
return;
+ // Get spell max affected targets
+ /*uint32 unMaxTargets = m_spellInfo->MaxAffectedTargets;
+ Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
+ for(Unit::AuraList::const_iterator m = mod.begin(); m != mod.end(); ++m)
+ {
+ if (!(*m)->isAffectedOnSpell(m_spellInfo))
+ continue;
+ unMaxTargets+=(*m)->GetAmount();
+ }*/
+
//FIXME: This very like horrible hack and wrong for most spells
if(m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE)
max_range += num * CHAIN_SPELL_JUMP_RADIUS;
@@ -1420,7 +1551,7 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin
if(cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS)
break;
while(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE
- && !m_caster->isInFront(*next, max_range)
+ && !m_caster->isInFrontInMap(*next, max_range)
|| !m_caster->canSeeOrDetect(*next, false)
|| !cur->IsWithinLOSInMap(*next))
{
@@ -1435,7 +1566,7 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin
}
}
-void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const uint32 type, SpellTargets TargetType, uint32 entry)
+void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry)
{
float x, y, z;
switch(type)
@@ -1478,6 +1609,9 @@ void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const u
m_caster->GetMap()->VisitWorld(x, y, radius, notifier);
else
m_caster->GetMap()->VisitAll(x, y, radius, notifier);
+
+ if(m_customAttr & SPELL_ATTR_CU_EXCLUDE_SELF)
+ TagUnitMap.remove(m_caster);
}
WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
@@ -1511,7 +1645,7 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
if(i_spellST->second.targetEntry)
{
Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range);
- Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check);
+ Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(m_caster,p_GameObject,go_check);
m_caster->VisitNearbyGridObject(range, checker);
if(p_GameObject)
@@ -1535,13 +1669,15 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
break;
}
case SPELL_TARGET_TYPE_CREATURE:
+ if(m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetEntry() == i_spellST->second.targetEntry)
+ return m_targets.getUnitTarget();
case SPELL_TARGET_TYPE_DEAD:
default:
{
Creature *p_Creature = NULL;
Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range);
- Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check);
+ Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(m_caster,p_Creature, u_check);
m_caster->VisitNearbyObject(range, searcher);
if(p_Creature )
@@ -1565,7 +1701,7 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
{
Unit *target = NULL;
Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, range);
- Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, u_check);
+ Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check);
m_caster->VisitNearbyObject(range, searcher);
return target;
}
@@ -1573,7 +1709,7 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
{
Unit *target = NULL;
Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, range);
- Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(target, u_check);
+ Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check);
m_caster->VisitNearbyObject(range, searcher);
return target;
}
@@ -1599,8 +1735,8 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
case TARGET_UNIT_CASTER_FISHING:
{
AddUnitTarget(m_caster, i);
- float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
- float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
+ float min_dis = GetSpellMinRange(m_spellInfo, true);
+ float max_dis = GetSpellMaxRange(m_spellInfo, true);
float dis = rand_norm() * (max_dis - min_dis) + min_dis;
float x, y, z;
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis);
@@ -1612,7 +1748,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
AddUnitTarget(owner, i);
break;
case TARGET_UNIT_PET:
- if(Pet* pet = m_caster->GetPet())
+ if(Guardian* pet = m_caster->GetGuardianPet())
AddUnitTarget(pet, i);
break;
case TARGET_UNIT_PARTY_CASTER:
@@ -1635,13 +1771,23 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
switch(cur)
{
case TARGET_UNIT_TARGET_ENEMY:
- SelectMagnetTarget();
+ if(Unit *magnet = m_caster->SelectMagnetTarget(target, m_spellInfo))
+ if(magnet != target)
+ m_targets.setUnitTarget(magnet);
+ pushType = PUSH_CHAIN;
+ break;
+ case TARGET_UNIT_TARGET_ANY:
+ if(!IsPositiveSpell(m_spellInfo->Id))
+ if(Unit *magnet = m_caster->SelectMagnetTarget(target, m_spellInfo))
+ if(magnet != target)
+ m_targets.setUnitTarget(magnet);
+ pushType = PUSH_CHAIN;
+ break;
case TARGET_UNIT_CHAINHEAL:
pushType = PUSH_CHAIN;
break;
case TARGET_UNIT_TARGET_ALLY:
case TARGET_UNIT_TARGET_RAID:
- case TARGET_UNIT_TARGET_ANY: // SelectMagnetTarget()?
case TARGET_UNIT_TARGET_PARTY:
case TARGET_UNIT_MINIPET:
AddUnitTarget(target, i);
@@ -1656,38 +1802,41 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
case TARGET_TYPE_UNIT_NEARBY:
{
- float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
- if(modOwner)
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
-
WorldObject *target = NULL;
+ float range;
switch(cur)
{
case TARGET_UNIT_NEARBY_ENEMY:
+ range = GetSpellMaxRange(m_spellInfo, false);
+ if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
target = SearchNearbyTarget(range, SPELL_TARGETS_ENEMY);
break;
case TARGET_UNIT_NEARBY_ALLY:
case TARGET_UNIT_NEARBY_ALLY_UNK:
case TARGET_UNIT_NEARBY_RAID:
+ range = GetSpellMaxRange(m_spellInfo, true);
+ if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
target = SearchNearbyTarget(range, SPELL_TARGETS_ALLY);
break;
case TARGET_UNIT_NEARBY_ENTRY:
+ range = GetSpellMaxRange(m_spellInfo, IsPositiveSpell(m_spellInfo->Id));
+ if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
target = SearchNearbyTarget(range, SPELL_TARGETS_ENTRY);
break;
}
if(!target)
return;
- else if(target->GetTypeId() == TYPEID_UNIT)
+ else if(target->GetTypeId() == TYPEID_GAMEOBJECT)
+ AddGOTarget((GameObject*)target, i);
+ else
{
pushType = PUSH_CHAIN;
- if(!m_targets.getUnitTarget())
+ if(m_targets.getUnitTarget() != target)
m_targets.setUnitTarget((Unit*)target);
}
- else if(target->GetTypeId() == TYPEID_GAMEOBJECT)
- AddGOTarget((GameObject*)target, i);
break;
}
@@ -1725,7 +1874,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
float x, y, z, angle, dist;
float objSize = m_caster->GetObjectSize();
- dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ dist = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
if(dist < objSize)
dist = objSize;
else if(cur == TARGET_DEST_CASTER_RANDOM)
@@ -1769,7 +1918,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
float x, y, z, angle, dist;
float objSize = target->GetObjectSize();
- dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ dist = target->GetSpellRadiusForTarget(target, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
if(dist < objSize)
dist = objSize;
else if(cur == TARGET_DEST_CASTER_RANDOM)
@@ -1822,7 +1971,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
}
float dist, x, y, z;
- dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ dist = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
if (cur == TARGET_DEST_DEST_RANDOM)
dist *= rand_norm();
@@ -1850,7 +1999,13 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
m_targets.setDestination(st->target_X, st->target_Y, st->target_Z);
}
else
- sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id );
+ {
+ sLog.outError( "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id );
+ Unit *target = NULL;
+ if(uint64 guid = m_caster->GetUInt64Value(UNIT_FIELD_TARGET))
+ target = ObjectAccessor::GetUnit(*m_caster, guid);
+ m_targets.setDestination(target ? target : m_caster);
+ }
break;
case TARGET_DST_HOME:
if(m_caster->GetTypeId() == TYPEID_PLAYER)
@@ -1858,9 +2013,8 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
break;
case TARGET_DST_NEARBY_ENTRY:
{
- float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
- if(modOwner)
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
+ float range = GetSpellMaxRange(m_spellInfo, IsPositiveSpell(m_spellInfo->Id));
+ if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
WorldObject *target = SearchNearbyTarget(range, SPELL_TARGETS_ENTRY);
if(target)
@@ -1890,6 +2044,8 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
case TARGET_DEST_CHANNEL:
if(m_originalCaster->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_targets.HasDst())
m_targets = m_originalCaster->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_targets;
+ else if(Unit* target = m_originalCaster->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_targets.getUnitTarget())
+ m_targets.setDestination(target);
else
sLog.outError( "SPELL: cannot find channel spell destination for spell ID %u", m_spellInfo->Id );
break;
@@ -1940,10 +2096,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
m_damageMultipliers[i] = 1.0f;
m_applyMultiplierMask |= 1 << i;
- float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
- if(modOwner)
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
-
+ float range;
std::list<Unit*> unitList;
switch(cur)
@@ -1951,12 +2104,16 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
case TARGET_UNIT_NEARBY_ENEMY:
case TARGET_UNIT_TARGET_ENEMY:
case TARGET_UNIT_NEARBY_ENTRY: // fix me
+ range = GetSpellMaxRange(m_spellInfo, false);
+ if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
SearchChainTarget(unitList, range, maxTargets, SPELL_TARGETS_ENEMY);
break;
case TARGET_UNIT_CHAINHEAL:
case TARGET_UNIT_NEARBY_ALLY: // fix me
case TARGET_UNIT_NEARBY_ALLY_UNK:
case TARGET_UNIT_NEARBY_RAID:
+ range = GetSpellMaxRange(m_spellInfo, true);
+ if(modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
SearchChainTarget(unitList, range, maxTargets, SPELL_TARGETS_CHAINHEAL);
break;
}
@@ -1970,114 +2127,226 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
else if(pushType)
{
// Dummy, just for client
- if(spellmgr.EffectTargetType[m_spellInfo->Effect[i]] == SPELL_REQUIRE_DEST)
+ if(spellmgr.EffectTargetType[m_spellInfo->Effect[i]] != SPELL_REQUIRE_UNIT)
return;
- float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
- if(modOwner)
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius, this);
-
- std::list<Unit*> unitList;
-
+ float radius;
+ SpellTargets targetType;
switch(cur)
{
case TARGET_UNIT_AREA_ENEMY_SRC:
case TARGET_UNIT_AREA_ENEMY_DST:
case TARGET_UNIT_CONE_ENEMY:
case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY);
+ radius = GetSpellRadius(m_spellInfo, i, false);
+ targetType = SPELL_TARGETS_ENEMY;
break;
case TARGET_UNIT_AREA_ALLY_SRC:
case TARGET_UNIT_AREA_ALLY_DST:
case TARGET_UNIT_CONE_ALLY:
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY);
- break;
- case TARGET_UNIT_AREA_PARTY_SRC:
- case TARGET_UNIT_AREA_PARTY_DST:
- m_caster->GetPartyMember(unitList, radius); //fix me
- break;
- case TARGET_OBJECT_AREA_SRC: // fix me
- case TARGET_OBJECT_AREA_DST:
+ radius = GetSpellRadius(m_spellInfo, i, true);
+ targetType = SPELL_TARGETS_ALLY;
break;
case TARGET_UNIT_AREA_ENTRY_SRC:
case TARGET_UNIT_AREA_ENTRY_DST:
case TARGET_UNIT_CONE_ENTRY: // fix me
+ radius = GetSpellRadius(m_spellInfo, i, IsPositiveSpell(m_spellInfo->Id));
+ targetType = SPELL_TARGETS_ENTRY;
+ break;
+ default:
+ radius = GetSpellRadius(m_spellInfo, i, true);
+ targetType = SPELL_TARGETS_NONE;
+ break;
+ }
+
+ if(modOwner)
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius, this);
+ radius *= m_spellValue->RadiusMod;
+
+ std::list<Unit*> unitList;
+ if(targetType == SPELL_TARGETS_ENTRY)
+ {
+ SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id);
+ SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);
+ if(lower == upper)
{
- SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id);
- SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);
- if(lower == upper)
- {
- sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
+ sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
- if(IsPositiveEffect(m_spellInfo->Id, i))
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY);
- else
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY);
- }
- // let it be done in one check?
+ if(IsPositiveEffect(m_spellInfo->Id, i))
+ SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY);
else
+ SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY);
+ }
+ // let it be done in one check?
+ else
+ {
+ for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST)
{
- for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST)
- {
- if(i_spellST->second.type == SPELL_TARGET_TYPE_CREATURE)
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry);
- }
+ if(i_spellST->second.type == SPELL_TARGET_TYPE_CREATURE)
+ SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry);
}
- break;
}
- case TARGET_UNIT_PARTY_TARGET:
- m_targets.getUnitTarget()->GetPartyMember(unitList, radius);
- break;
- case TARGET_UNIT_PARTY_CASTER:
- m_caster->GetPartyMember(unitList, radius);
- break;
- case TARGET_UNIT_RAID_CASTER:
- m_caster->GetRaidMember(unitList, radius);
- break;
- case TARGET_UNIT_CLASS_TARGET:
+ }
+ else if(targetType)
+ SearchAreaTarget(unitList, radius, pushType, targetType);
+ else
+ {
+ switch(cur)
{
- Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
- ? (Player*)m_targets.getUnitTarget() : NULL;
-
- Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL;
- if(pGroup)
+ case TARGET_UNIT_AREA_PARTY_SRC:
+ case TARGET_UNIT_AREA_PARTY_DST:
+ m_caster->GetPartyMember(unitList, radius); //fix me
+ break;
+ case TARGET_OBJECT_AREA_SRC: // fix me
+ case TARGET_OBJECT_AREA_DST:
{
- for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ float x, y, z;
+ if(cur == TARGET_OBJECT_AREA_SRC)
{
- Player* Target = itr->getSource();
+ if(m_targets.HasSrc())
+ {
+ x = m_targets.m_srcX;
+ y = m_targets.m_srcY;
+ z = m_targets.m_srcZ;
+ }
+ else
+ break;
+ }
+ else if(m_targets.HasDst())
+ {
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+ }
+ else
+ break;
- // IsHostileTo check duel and controlled by enemy
- if( Target && targetPlayer->IsWithinDistInMap(Target, radius) &&
- targetPlayer->getClass() == Target->getClass() &&
- !m_caster->IsHostileTo(Target) )
+ Trinity::GameObjectInRangeCheck check(x, y, z, radius + 50);
+ std::list<GameObject*> goList;
+ Trinity::GameObjectListSearcher<Trinity::GameObjectInRangeCheck> searcher(m_caster, goList, check);
+ m_caster->GetMap()->VisitGrid(x, y, radius, searcher);
+ for(std::list<GameObject*>::iterator itr = goList.begin(); itr != goList.end(); ++itr)
+ AddGOTarget(*itr, i);
+ break;
+ }
+ case TARGET_UNIT_PARTY_TARGET:
+ m_targets.getUnitTarget()->GetPartyMember(unitList, radius);
+ break;
+ case TARGET_UNIT_PARTY_CASTER:
+ m_caster->GetPartyMember(unitList, radius);
+ break;
+ case TARGET_UNIT_RAID_CASTER:
+ m_caster->GetRaidMember(unitList, radius);
+ break;
+ case TARGET_UNIT_CLASS_TARGET:
+ {
+ Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
+ ? (Player*)m_targets.getUnitTarget() : NULL;
+
+ Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL;
+ if(pGroup)
+ {
+ for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
{
- AddUnitTarget(Target, i);
+ Player* Target = itr->getSource();
+
+ // IsHostileTo check duel and controlled by enemy
+ if( Target && targetPlayer->IsWithinDistInMap(Target, radius) &&
+ targetPlayer->getClass() == Target->getClass() &&
+ !m_caster->IsHostileTo(Target) )
+ {
+ AddUnitTarget(Target, i);
+ }
}
}
+ else if(m_targets.getUnitTarget())
+ AddUnitTarget(m_targets.getUnitTarget(), i);
+ break;
}
- else if(m_targets.getUnitTarget())
- AddUnitTarget(m_targets.getUnitTarget(), i);
- break;
}
}
if(!unitList.empty())
{
- if(m_spellValue->MaxAffectedTargets)
+ if(uint32 maxTargets = m_spellValue->MaxAffectedTargets)
{
+ Unit::AuraEffectList const& Auras = m_caster->GetAurasByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
+ for(Unit::AuraEffectList::const_iterator j = Auras.begin();j != Auras.end(); ++j)
+ if((*j)->isAffectedOnSpell(m_spellInfo))
+ maxTargets += (*j)->GetAmount();
+
if(m_spellInfo->Id == 5246) //Intimidating Shout
unitList.remove(m_targets.getUnitTarget());
-
Trinity::RandomResizeList(unitList, m_spellValue->MaxAffectedTargets);
}
+ else
+ {
+ if (m_spellInfo->Id==57699) //Replenishment (special target selection) 10 targets with lowest mana
+ {
+ typedef std::priority_queue<PrioritizeManaWraper, std::vector<PrioritizeManaWraper>, PrioritizeMana> TopMana;
+ TopMana manaUsers;
+ for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();++itr)
+ {
+ if ((*itr)->getPowerType() == POWER_MANA)
+ {
+ PrioritizeManaWraper WTarget(*itr);
+ manaUsers.push(WTarget);
+ }
+ }
+
+ unitList.clear();
+ while(!manaUsers.empty() && unitList.size()<10)
+ {
+ unitList.push_back(manaUsers.top().getUnit());
+ manaUsers.pop();
+ }
+ }
+ else if (m_spellInfo->Id==52759)// Ancestral Awakening
+ {
+ typedef std::priority_queue<PrioritizeHealthWraper, std::vector<PrioritizeHealthWraper>, PrioritizeHealth> TopHealth;
+ TopHealth healedMembers;
+ for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();++itr)
+ {
+ PrioritizeHealthWraper WTarget(*itr);
+ healedMembers.push(WTarget);
+ }
+ unitList.clear();
+ while(!healedMembers.empty() && unitList.size()<1)
+ {
+ unitList.push_back(healedMembers.top().getUnit());
+ healedMembers.pop();
+ }
+ }
+ else if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_TARGET_ANY
+ && m_spellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ALLY_DST)// Wild Growth, Circle of Healing, Glyph of holy light target special selection
+ {
+ typedef std::priority_queue<PrioritizeHealthWraper, std::vector<PrioritizeHealthWraper>, PrioritizeHealth> TopHealth;
+ TopHealth healedMembers;
+ for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();++itr)
+ {
+ if ((*itr)->IsInRaidWith(m_targets.getUnitTarget()))
+ {
+ PrioritizeHealthWraper WTarget(*itr);
+ healedMembers.push(WTarget);
+ }
+ }
+
+ unitList.clear();
+ while(!healedMembers.empty() && unitList.size()<5)
+ {
+ unitList.push_back(healedMembers.top().getUnit());
+ healedMembers.pop();
+ }
+ }
+ }
for(std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
AddUnitTarget(*itr, i);
}
- } // Chain or Area
+ }
}
-void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
+void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura)
{
if(m_CastItem)
m_castItemGUID = m_CastItem->GetGUID();
@@ -2086,6 +2355,24 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
m_targets = *targets;
+ if(!m_targets.getUnitTargetGUID() && m_spellInfo->Targets & TARGET_FLAG_UNIT)
+ {
+ Unit *target = NULL;
+ if(m_caster->GetTypeId() == TYPEID_UNIT)
+ target = m_caster->getVictim();
+ else
+ target = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
+
+ if(target && IsValidSingleTargetSpell(target))
+ m_targets.setUnitTarget(target);
+ else
+ {
+ SendCastResult(SPELL_FAILED_BAD_TARGETS);
+ finish(false);
+ return;
+ }
+ }
+
m_spellState = SPELL_STATE_PREPARING;
m_caster->GetPosition(m_castPositionX, m_castPositionY, m_castPositionZ);
@@ -2099,7 +2386,7 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));
//Prevent casting at cast another spell (ServerSide check)
- if(m_caster->IsNonMeleeSpellCasted(false, true) && m_cast_count)
+ if(m_caster->IsNonMeleeSpellCasted(false, true, true) && m_cast_count)
{
SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS);
finish(false);
@@ -2136,13 +2423,13 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
// Fill cost data
m_powerCost = CalculatePowerCost();
- uint8 result = CanCast(true);
- if(result != 0 && !IsAutoRepeat()) //always cast autorepeat dummy for triggering
+ SpellCastResult result = CheckCast(true);
+ if(result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering
{
if(triggeredByAura)
{
SendChannelUpdate(0);
- triggeredByAura->SetAuraDuration(0);
+ triggeredByAura->GetParentAura()->SetAuraDuration(0);
}
SendCastResult(result);
finish(false);
@@ -2150,15 +2437,22 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
}
// Prepare data for triggers
- prepareDataForTriggerSystem();
+ prepareDataForTriggerSystem(triggeredByAura);
+
+ // Set combo point requirement
+ if (m_IsTriggeredSpell || m_CastItem || m_caster->GetTypeId()!=TYPEID_PLAYER)
+ m_needComboPoints = false;
- // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail)
+ // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)
m_casttime = GetSpellCastTime(m_spellInfo, this);
+ //m_caster->ModSpellCastTime(m_spellInfo, m_casttime, this);
// set timer base at cast time
ReSetTimer();
-
- if(m_IsTriggeredSpell)
+ //Containers for channeled spells have to be set
+ //TODO:Apply this to all casted spells if needed
+ // Why check duration? 29350: channelled triggers channelled
+ if(m_IsTriggeredSpell && (!IsChanneledSpell(m_spellInfo) || !GetSpellMaxDuration(m_spellInfo)))
cast(true);
else
{
@@ -2208,11 +2502,10 @@ void Spell::cancel()
{
Unit* unit = m_caster->GetGUID()==(*ihit).targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
if( unit && unit->isAlive() )
- unit->RemoveAurasByCasterSpell(m_spellInfo->Id, m_caster->GetGUID());
+ unit->RemoveAurasDueToSpell(m_spellInfo->Id, m_caster->GetGUID(), AURA_REMOVE_BY_CANCEL);
}
}
-
- m_caster->RemoveAurasByCasterSpell(m_spellInfo->Id, m_caster->GetGUID());
+ m_caster->RemoveAurasDueToSpell(m_spellInfo->Id, m_caster->GetGUID(), AURA_REMOVE_BY_CANCEL);
SendChannelUpdate(0);
SendInterrupted(0);
SendCastResult(SPELL_FAILED_INTERRUPTED);
@@ -2236,8 +2529,6 @@ void Spell::cast(bool skipCheck)
{
SetExecutedCurrently(true);
- uint8 castResult = 0;
-
// update pointers base at GUIDs to prevent access to non-existed already object
UpdatePointers();
@@ -2252,23 +2543,12 @@ void Spell::cast(bool skipCheck)
if(m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster)
m_caster->SetInFront(m_targets.getUnitTarget());
- if(!m_IsTriggeredSpell)
- {
- castResult = CheckPower();
- if(castResult != 0)
- {
- SendCastResult(castResult);
- finish(false);
- SetExecutedCurrently(false);
- return;
- }
- }
// triggered cast called from Spell::prepare where it was already checked
- if(!skipCheck)
+ if(!m_IsTriggeredSpell || !skipCheck)
{
- castResult = CanCast(false);
- if(castResult != 0)
+ SpellCastResult castResult = CheckCast(false);
+ if(castResult != SPELL_CAST_OK)
{
SendCastResult(castResult);
finish(false);
@@ -2279,19 +2559,62 @@ void Spell::cast(bool skipCheck)
FillTargetMap();
- if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in Take*/FillTargetMap
+ if(m_spellInfo->SpellFamilyName)
{
- SetExecutedCurrently(false);
- return;
+ if (m_spellInfo->excludeCasterAuraSpell && !IsPositiveSpell(m_spellInfo->excludeCasterAuraSpell))
+ m_preCastSpell = m_spellInfo->excludeCasterAuraSpell;
+ else if (m_spellInfo->excludeTargetAuraSpell && !IsPositiveSpell(m_spellInfo->excludeTargetAuraSpell))
+ m_preCastSpell = m_spellInfo->excludeTargetAuraSpell;
+ }
+ switch (m_spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ {
+ if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
+ m_preCastSpell = 11196; // Recently Bandaged
+ else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20)
+ m_preCastSpell = 23230; // Blood Fury - Healing Reduction
+ break;
+ }
}
-
// traded items have trade slot instead of guid in m_itemTargetGUID
// set to real guid to be sent later to the client
m_targets.updateTradeSlotItem();
+ if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (!m_IsTriggeredSpell && m_CastItem)
+ ((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, m_CastItem->GetEntry());
+
+ ((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id);
+ }
+
+ // this is related to combo points so must be done before takepower
+ // are there any spells need to be triggered after hit?
+ // handle SPELL_AURA_ADD_TARGET_TRIGGER auras
+ Unit::AuraEffectList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER);
+ for(Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i)
+ {
+ if (!(*i)->isAffectedOnSpell(m_spellInfo))
+ continue;
+ SpellEntry const *auraSpellInfo = (*i)->GetSpellProto();
+ uint32 auraSpellIdx = (*i)->GetEffIndex();
+ if(SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx]))
+ {
+ // Calculate chance at that moment (can be depend for example from combo points)
+ int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(), NULL);
+ m_ChanceTriggerSpells.push_back(std::make_pair(spellInfo, chance * (*i)->GetParentAura()->GetStackAmount()));
+ }
+ }
+
+ // this is related to combo points so must be done before takepower
+ if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE)
+ CalculateDamageDoneForAllTargets();
+
if(!m_IsTriggeredSpell)
{
- //TakePower();
+ // Powers have to be taken before SendSpellGo
+ TakePower();
TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
}
@@ -2300,30 +2623,23 @@ void Spell::cast(bool skipCheck)
//SendCastResult(castResult);
SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
- if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE)
- CalculateDamageDoneForAllTargets();
-
- //handle SPELL_AURA_ADD_TARGET_TRIGGER auras
- //are there any spells need to be triggered after hit?
- Unit::AuraList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER);
- for(Unit::AuraList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i)
+ if(m_customAttr & SPELL_ATTR_CU_CHARGE)
{
- SpellEntry const *auraSpellInfo = (*i)->GetSpellProto();
- uint32 auraSpellIdx = (*i)->GetEffIndex();
- if (IsAffectedBy(auraSpellInfo, auraSpellIdx))
+ for(uint32 i = 0; i < 3; ++i)
{
- if(SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx]))
+ switch(m_spellInfo->Effect[i])
{
- // Calculate chance at that moment (can be depend for example from combo points)
- int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(), NULL);
- m_ChanceTriggerSpells.push_back(std::make_pair(spellInfo, chance * (*i)->GetStackAmount()));
+ case SPELL_EFFECT_CHARGE:
+ case SPELL_EFFECT_JUMP:
+ case SPELL_EFFECT_JUMP2:
+ case SPELL_EFFECT_138:
+ HandleEffects(NULL,NULL,NULL,i);
+ m_effectMask |= (1<<i);
+ break;
}
}
}
- if(m_customAttr & SPELL_ATTR_CU_CHARGE)
- EffectCharge(0);
-
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
if (m_spellInfo->speed > 0.0f && !IsChanneledSpell(m_spellInfo))
{
@@ -2342,12 +2658,6 @@ void Spell::cast(bool skipCheck)
handle_immediate();
}
- // combo points should not be taken before SPELL_AURA_ADD_TARGET_TRIGGER auras are handled
- if(!m_IsTriggeredSpell)
- {
- TakePower();
- }
-
if(m_customAttr & SPELL_ATTR_CU_LINK_CAST)
{
if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(m_spellInfo->Id))
@@ -2366,9 +2676,18 @@ void Spell::handle_immediate()
// start channeling if applicable
if(IsChanneledSpell(m_spellInfo))
{
- m_spellState = SPELL_STATE_CASTING;
- m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags);
- SendChannelStart(GetSpellDuration(m_spellInfo));
+ int32 duration = GetSpellDuration(m_spellInfo);
+ if (duration)
+ {
+ //apply haste mods
+ m_caster->ModSpellCastTime(m_spellInfo, duration, this);
+ // Apply duration mod
+ if(Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
+ m_spellState = SPELL_STATE_CASTING;
+ m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags);
+ SendChannelStart(duration);
+ }
}
// process immediate effects (items, ground, etc.) also initialize some variables
@@ -2485,14 +2804,22 @@ void Spell::_handle_immediate_phase()
if(!m_targets.HasDst()) // FIXME: this will ignore dest set in effect
m_targets.setDestination(m_caster);
HandleEffects(m_originalCaster, NULL, NULL, j);
+ m_effectMask |= (1<<j);
}
else if(spellmgr.EffectTargetType[m_spellInfo->Effect[j]] == SPELL_REQUIRE_NONE)
+ {
HandleEffects(m_originalCaster, NULL, NULL, j);
+ m_effectMask |= (1<<j);
+ }
}
}
void Spell::_handle_finish_phase()
{
+ // Take for real after all targets are processed
+ if (m_needComboPoints)
+ ((Player*)m_caster)->ClearComboPoints();
+
// spell log
if(m_needSpellLog)
SendLogExecute();
@@ -2504,93 +2831,20 @@ void Spell::SendSpellCooldown()
return;
Player* _player = (Player*)m_caster;
- // Add cooldown for max (disable spell)
- // Cooldown started on SendCooldownEvent call
- if (m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
- {
- _player->AddSpellCooldown(m_spellInfo->Id, 0, time(NULL) - 1);
- return;
- }
-
- // init cooldown values
- uint32 cat = 0;
- int32 rec = -1;
- int32 catrec = -1;
-
- // some special item spells without correct cooldown in SpellInfo
- // cooldown information stored in item prototype
- // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
-
- if(m_CastItem)
- {
- ItemPrototype const* proto = m_CastItem->GetProto();
- if(proto)
- {
- for(int idx = 0; idx < 5; ++idx)
- {
- if(proto->Spells[idx].SpellId == m_spellInfo->Id)
- {
- cat = proto->Spells[idx].SpellCategory;
- rec = proto->Spells[idx].SpellCooldown;
- catrec = proto->Spells[idx].SpellCategoryCooldown;
- break;
- }
- }
- }
- }
- // if no cooldown found above then base at DBC data
- if(rec < 0 && catrec < 0)
+ // mana/health/etc potions, disabled by client (until combat out as declarate)
+ if (m_CastItem && m_CastItem->IsPotion())
{
- cat = m_spellInfo->Category;
- rec = m_spellInfo->RecoveryTime;
- catrec = m_spellInfo->CategoryRecoveryTime;
+ // need in some way provided data for Spell::finish SendCooldownEvent
+ _player->SetLastPotionId(m_CastItem->GetEntry());
+ return;
}
- // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
- // prevent 0 cooldowns set by another way
- if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351))
- rec = _player->GetAttackTime(RANGED_ATTACK);
-
- // Now we have cooldown data (if found any), time to apply mods
- if(rec > 0)
- _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, rec, this);
-
- if(catrec > 0)
- _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, catrec, this);
-
- // replace negative cooldowns by 0
- if (rec < 0) rec = 0;
- if (catrec < 0) catrec = 0;
-
- // no cooldown after applying spell mods
- if( rec == 0 && catrec == 0)
+ // have infinity cooldown but set at aura apply // do not set cooldown for triggered spells (needed by reincarnation)
+ if(m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE || m_IsTriggeredSpell)
return;
- time_t curTime = time(NULL);
-
- time_t catrecTime = catrec ? curTime+catrec/1000 : 0; // in secs
- time_t recTime = rec ? curTime+rec/1000 : catrecTime;// in secs
-
- // self spell cooldown
- if(recTime > 0)
- _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, recTime);
-
- // category spells
- if (catrec > 0)
- {
- SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
- if(i_scstore != sSpellCategoryStore.end())
- {
- for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
- {
- if(*i_scset == m_spellInfo->Id) // skip main spell, already handled above
- continue;
-
- _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime);
- }
- }
- }
+ _player->AddSpellAndCategoryCooldowns(m_spellInfo,m_CastItem ? m_CastItem->GetEntry() : 0, this);
}
void Spell::update(uint32 difftime)
@@ -2649,8 +2903,9 @@ void Spell::update(uint32 difftime)
}
// check if there are alive targets left
- if (!IsAliveUnitPresentInTargetList())
+ if (!UpdateChanneledTargetList())
{
+ sLog.outDebug("Channeled spell %d is removed due to lack of targets", m_spellInfo->Id);
SendChannelUpdate(0);
finish();
}
@@ -2668,30 +2923,33 @@ void Spell::update(uint32 difftime)
// channeled spell processed independently for quest targeting
// cast at creature (or GO) quest objectives update at successful cast channel finished
// ignore autorepeat/melee casts for speed (not exist quest for spells (hm... )
- if( m_caster->GetTypeId() == TYPEID_PLAYER && !IsAutoRepeat() && !IsNextMeleeSwingSpell() )
+ if( !IsAutoRepeat() && !IsNextMeleeSwingSpell() )
{
- for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
+ if ( Player* p = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself() )
{
- TargetInfo* target = &*ihit;
- if(!IS_CREATURE_GUID(target->targetGUID))
- continue;
+ for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
+ {
+ TargetInfo* target = &*ihit;
+ if(!IS_CREATURE_GUID(target->targetGUID))
+ continue;
- Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID);
- if (unit==NULL)
- continue;
+ Unit* unit = m_caster->GetGUID()==target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster,target->targetGUID);
+ if (unit==NULL)
+ continue;
- ((Player*)m_caster)->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id);
- }
+ p->CastedCreatureOrGO(unit->GetEntry(),unit->GetGUID(),m_spellInfo->Id);
+ }
- for(std::list<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit)
- {
- GOTargetInfo* target = &*ihit;
+ for(std::list<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin();ihit != m_UniqueGOTargetInfo.end();++ihit)
+ {
+ GOTargetInfo* target = &*ihit;
- GameObject* go = ObjectAccessor::GetGameObject(*m_caster, target->targetGUID);
- if(!go)
- continue;
+ GameObject* go = m_caster->GetMap()->GetGameObject(target->targetGUID);
+ if(!go)
+ continue;
- ((Player*)m_caster)->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id);
+ p->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id);
+ }
}
}
@@ -2711,7 +2969,6 @@ void Spell::finish(bool ok)
if(m_spellState == SPELL_STATE_FINISHED)
return;
-
m_spellState = SPELL_STATE_FINISHED;
if(IsChanneledSpell(m_spellInfo))
@@ -2720,20 +2977,50 @@ void Spell::finish(bool ok)
if(!m_caster->IsNonMeleeSpellCasted(false, false, true))
m_caster->clearUnitState(UNIT_STAT_CASTING);
+ // Unsummon summon as possessed creatures on spell cancel
+ if(IsChanneledSpell(m_spellInfo) && m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (Unit * charm = m_caster->GetCharm())
+ for(int i = 0; i < 3; ++i)
+ {
+ if(m_spellInfo->Effect[i] == SPELL_EFFECT_SUMMON)
+ if(SummonPropertiesEntry const *SummonProperties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]))
+ if(SummonProperties->Category == SUMMON_CATEGORY_POSSESSED)
+ {
+ if(charm->GetTypeId() == TYPEID_UNIT)
+ {
+ if(((Creature*)charm)->isPet() && ((Pet*)charm)->getPetType() == POSSESSED_PET)
+ ((Pet*)charm)->Remove(PET_SAVE_AS_DELETED);
+ break;
+ }
+ }
+ }
+ }
+
// other code related only to successfully finished spells
if(!ok)
return;
+ if (m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isSummon())
+ {
+ // Unsummon statue
+ uint32 spell = m_caster->GetUInt32Value(UNIT_CREATED_BY_SPELL);
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell );
+ if (spellInfo && spellInfo->SpellIconID==2056)
+ {
+ sLog.outDebug("Statue %d is unsummoned in spell %d finish", m_caster->GetGUIDLow(), m_spellInfo->Id);
+ m_caster->setDeathState(JUST_DIED);
+ return;
+ }
+ }
+
//remove spell mods
if (m_caster->GetTypeId() == TYPEID_PLAYER)
((Player*)m_caster)->RemoveSpellMods(this);
// Heal caster for all health leech from all targets
if (m_healthLeech)
- {
- m_caster->ModifyHealth(m_healthLeech);
- m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(m_healthLeech));
- }
+ m_caster->DealHeal(m_caster, uint32(m_healthLeech), m_spellInfo);
if (IsMeleeAttackResetSpell())
{
@@ -2744,6 +3031,10 @@ void Spell::finish(bool ok)
m_caster->resetAttackTimer(RANGED_ATTACK);
}
+ // potions disabled by client, send event "not in combat" if need
+ if (!m_triggeredByAuraSpell && m_caster->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)m_caster)->UpdatePotionCooldown(this);
+
// call triggered spell only at successful cast (after clear combo points -> for add some if need)
// I assume what he means is that some triggered spells may add combo points
if(!m_TriggerSpells.empty())
@@ -2754,72 +3045,67 @@ void Spell::finish(bool ok)
m_caster->AttackStop();
}
-void Spell::SendCastResult(uint8 result)
+void Spell::SendCastResult(SpellCastResult result)
{
+ if(result == SPELL_CAST_OK)
+ return;
+
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if(((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time
return;
- if(result != 0)
- {
- WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
- data << uint32(m_spellInfo->Id);
- data << uint8(result); // problem
- data << uint8(m_cast_count); // single cast or multi 2.3 (0/1)
- switch (result)
- {
- case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
- data << uint32(m_spellInfo->RequiresSpellFocus);
- break;
- case SPELL_FAILED_REQUIRES_AREA:
- // hardcode areas limitation case
- switch(m_spellInfo->Id)
- {
- case 41617: // Cenarion Mana Salve
- case 41619: // Cenarion Healing Salve
- data << uint32(3905);
- break;
- case 41618: // Bottled Nethergon Energy
- case 41620: // Bottled Nethergon Vapor
- data << uint32(3842);
- break;
- case 45373: // Bloodberry Elixir
- data << uint32(4075);
- break;
- default: // default case
- data << uint32(m_spellInfo->AreaId);
- break;
- }
- break;
- case SPELL_FAILED_TOTEMS:
- if(m_spellInfo->Totem[0])
- data << uint32(m_spellInfo->Totem[0]);
- if(m_spellInfo->Totem[1])
- data << uint32(m_spellInfo->Totem[1]);
- break;
- case SPELL_FAILED_TOTEM_CATEGORY:
- if(m_spellInfo->TotemCategory[0])
- data << uint32(m_spellInfo->TotemCategory[0]);
- if(m_spellInfo->TotemCategory[1])
- data << uint32(m_spellInfo->TotemCategory[1]);
- break;
- case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
- data << uint32(m_spellInfo->EquippedItemClass);
- data << uint32(m_spellInfo->EquippedItemSubClassMask);
- data << uint32(m_spellInfo->EquippedItemInventoryTypeMask);
- break;
- }
- ((Player*)m_caster)->GetSession()->SendPacket(&data);
- }
- else
+ WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
+ data << uint8(m_cast_count); // single cast or multi 2.3 (0/1)
+ data << uint32(m_spellInfo->Id);
+ data << uint8(result); // problem
+ switch (result)
{
- WorldPacket data(SMSG_CLEAR_EXTRA_AURA_INFO, (8+4));
- data.append(m_caster->GetPackGUID());
- data << uint32(m_spellInfo->Id);
- ((Player*)m_caster)->GetSession()->SendPacket(&data);
+ case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
+ data << uint32(m_spellInfo->RequiresSpellFocus);
+ break;
+ case SPELL_FAILED_REQUIRES_AREA:
+ // hardcode areas limitation case
+ switch(m_spellInfo->Id)
+ {
+ case 41617: // Cenarion Mana Salve
+ case 41619: // Cenarion Healing Salve
+ data << uint32(3905);
+ break;
+ case 41618: // Bottled Nethergon Energy
+ case 41620: // Bottled Nethergon Vapor
+ data << uint32(3842);
+ break;
+ case 45373: // Bloodberry Elixir
+ data << uint32(4075);
+ break;
+ default: // default case (don't must be)
+ data << uint32(0);
+ break;
+ }
+ break;
+ case SPELL_FAILED_TOTEMS:
+ if(m_spellInfo->Totem[0])
+ data << uint32(m_spellInfo->Totem[0]);
+ if(m_spellInfo->Totem[1])
+ data << uint32(m_spellInfo->Totem[1]);
+ break;
+ case SPELL_FAILED_TOTEM_CATEGORY:
+ if(m_spellInfo->TotemCategory[0])
+ data << uint32(m_spellInfo->TotemCategory[0]);
+ if(m_spellInfo->TotemCategory[1])
+ data << uint32(m_spellInfo->TotemCategory[1]);
+ break;
+ case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
+ data << uint32(m_spellInfo->EquippedItemClass);
+ data << uint32(m_spellInfo->EquippedItemSubClassMask);
+ //data << uint32(m_spellInfo->EquippedItemInventoryTypeMask);
+ break;
+ default:
+ break;
}
+ ((Player*)m_caster)->GetSession()->SendPacket(&data);
}
void Spell::SendSpellStart()
@@ -2830,10 +3116,15 @@ void Spell::SendSpellStart()
sLog.outDebug("Sending SMSG_SPELL_START id=%u", m_spellInfo->Id);
uint32 castFlags = CAST_FLAG_UNKNOWN1;
- if(IsRangedSpell())
+ if(m_spellInfo->Attributes & SPELL_ATTR_REQ_AMMO)
castFlags |= CAST_FLAG_AMMO;
+ if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
+ (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isPet()))
+ && m_spellInfo->powerType != POWER_HEALTH )
+ castFlags |= CAST_FLAG_POWER_LEFT_SELF;
- Unit *target = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster;
+ if(m_spellInfo->runeCostID)
+ castFlags |= CAST_FLAG_UNKNOWN10;
WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2));
if(m_CastItem)
@@ -2842,14 +3133,17 @@ void Spell::SendSpellStart()
data.append(m_caster->GetPackGUID());
data.append(m_caster->GetPackGUID());
- data << uint32(m_spellInfo->Id);
- data << uint8(m_cast_count); // single cast or multi 2.3 (0/1)
- data << uint16(castFlags);
- data << uint32(m_timer);
+ data << uint8(m_cast_count); // pending spell cast?
+ data << uint32(m_spellInfo->Id); // spellId
+ data << uint32(castFlags); // cast flags
+ data << uint32(m_timer); // delay?
m_targets.write(&data);
- if( castFlags & CAST_FLAG_AMMO )
+ if(castFlags & CAST_FLAG_POWER_LEFT_SELF)
+ data << uint32(m_caster->GetPower((Powers)m_spellInfo->powerType));
+
+ if ( castFlags & CAST_FLAG_AMMO )
WriteAmmoToPacket(&data);
m_caster->SendMessageToSet(&data, true);
@@ -2863,30 +3157,75 @@ void Spell::SendSpellGo()
sLog.outDebug("Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id);
- Unit *target = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster;
-
uint32 castFlags = CAST_FLAG_UNKNOWN3;
- if(IsRangedSpell())
+ if(m_spellInfo->Attributes & SPELL_ATTR_REQ_AMMO)
castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual
+ if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
+ (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isPet()))
+ && m_spellInfo->powerType != POWER_HEALTH )
+ castFlags |= CAST_FLAG_POWER_LEFT_SELF; // should only be sent to self, but the current messaging doesn't make that possible
+
+ if((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->getClass() == CLASS_DEATH_KNIGHT) && m_spellInfo->runeCostID)
+ {
+ castFlags |= CAST_FLAG_UNKNOWN10; // same as in SMSG_SPELL_START
+ castFlags |= CAST_FLAG_UNKNOWN7; // rune cooldowns list
+ }
WorldPacket data(SMSG_SPELL_GO, 50); // guess size
+
if(m_CastItem)
data.append(m_CastItem->GetPackGUID());
else
data.append(m_caster->GetPackGUID());
data.append(m_caster->GetPackGUID());
- data << uint32(m_spellInfo->Id);
- data << uint16(castFlags);
+ data << uint8(m_cast_count); // pending spell cast?
+ data << uint32(m_spellInfo->Id); // spellId
+ data << uint32(castFlags); // cast flags
data << uint32(getMSTime()); // timestamp
WriteSpellGoTargets(&data);
m_targets.write(&data);
- if( castFlags & CAST_FLAG_AMMO )
+ if(castFlags & CAST_FLAG_POWER_LEFT_SELF)
+ data << uint32(m_caster->GetPower((Powers)m_spellInfo->powerType));
+
+ if ( castFlags & CAST_FLAG_UNKNOWN7 ) // rune cooldowns list
+ {
+ uint8 v1 = m_runesState;
+ uint8 v2 = ((Player*)m_caster)->GetRunesState();
+ data << uint8(v1); // runes state before
+ data << uint8(v2); // runes state after
+ for(uint8 i = 0; i < MAX_RUNES; ++i)
+ {
+ uint8 m = (1 << i);
+ if(m & v1) // usable before...
+ if(!(m & v2)) // ...but on cooldown now...
+ data << uint8(0); // some unknown byte (time?)
+ }
+ }
+
+ if ( castFlags & CAST_FLAG_UNKNOWN4 ) // unknown wotlk
+ {
+ data << float(0);
+ data << uint32(0);
+ }
+
+ if ( castFlags & CAST_FLAG_AMMO )
WriteAmmoToPacket(&data);
+ if ( castFlags & CAST_FLAG_UNKNOWN5 ) // unknown wotlk
+ {
+ data << uint32(0);
+ data << uint32(0);
+ }
+
+ if ( m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION )
+ {
+ data << uint8(0);
+ }
+
m_caster->SendMessageToSet(&data, true);
}
@@ -2923,7 +3262,40 @@ void Spell::WriteAmmoToPacket( WorldPacket * data )
}
}
}
- // TODO: implement selection ammo data based at ranged weapon stored in equipmodel/equipinfo/equipslot fields
+ else
+ {
+ for (uint8 i = 0; i < 3; ++i)
+ {
+ if(uint32 item_id = m_caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i))
+ {
+ if(ItemEntry const * itemEntry = sItemStore.LookupEntry(item_id))
+ {
+ if(itemEntry->Class==ITEM_CLASS_WEAPON)
+ {
+ switch(itemEntry->SubClass)
+ {
+ case ITEM_SUBCLASS_WEAPON_THROWN:
+ ammoDisplayID = itemEntry->DisplayId;
+ ammoInventoryType = itemEntry->InventoryType;
+ break;
+ case ITEM_SUBCLASS_WEAPON_BOW:
+ case ITEM_SUBCLASS_WEAPON_CROSSBOW:
+ ammoDisplayID = 5996; // is this need fixing?
+ ammoInventoryType = INVTYPE_AMMO;
+ break;
+ case ITEM_SUBCLASS_WEAPON_GUN:
+ ammoDisplayID = 5998; // is this need fixing?
+ ammoInventoryType = INVTYPE_AMMO;
+ break;
+ }
+
+ if(ammoDisplayID)
+ break;
+ }
+ }
+ }
+ }
+ }
*data << uint32(ammoDisplayID);
*data << uint32(ammoInventoryType);
@@ -2931,15 +3303,36 @@ void Spell::WriteAmmoToPacket( WorldPacket * data )
void Spell::WriteSpellGoTargets( WorldPacket * data )
{
- *data << (uint8)m_countOfHit;
+ // This function also fill data for channeled spells:
+ // m_needAliveTargetMask req for stop channelig if one target die
+ uint32 hit = m_UniqueGOTargetInfo.size(); // Always hits on GO
+ uint32 miss = 0;
+ for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
+ {
+ if ((*ihit).effectMask == 0) // No effect apply - all immuned add state
+ {
+ // possibly SPELL_MISS_IMMUNE2 for this??
+ ihit->missCondition = SPELL_MISS_IMMUNE2;
+ miss++;
+ }
+ else if ((*ihit).missCondition == SPELL_MISS_NONE)
+ hit++;
+ else
+ miss++;
+ }
+
+ *data << (uint8)hit;
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
if ((*ihit).missCondition == SPELL_MISS_NONE) // Add only hits
+ {
*data << uint64(ihit->targetGUID);
+ m_needAliveTargetMask |=ihit->effectMask;
+ }
for(std::list<GOTargetInfo>::iterator ighit= m_UniqueGOTargetInfo.begin();ighit != m_UniqueGOTargetInfo.end();++ighit)
*data << uint64(ighit->targetGUID); // Always hits
- *data << (uint8)m_countOfMiss;
+ *data << (uint8)miss;
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
{
if( ihit->missCondition != SPELL_MISS_NONE ) // Add only miss
@@ -2950,6 +3343,9 @@ void Spell::WriteSpellGoTargets( WorldPacket * data )
*data << uint8(ihit->reflectResult);
}
}
+ // Reset m_needAliveTargetMask for non channeled spell
+ if(!IsChanneledSpell(m_spellInfo))
+ m_needAliveTargetMask = 0;
}
void Spell::SendLogExecute()
@@ -3014,30 +3410,19 @@ void Spell::SendLogExecute()
data << uint8(0);
break;
case SPELL_EFFECT_CREATE_ITEM:
+ case SPELL_EFFECT_CREATE_ITEM_2:
data << uint32(m_spellInfo->EffectItemType[0]);
break;
case SPELL_EFFECT_SUMMON:
- case SPELL_EFFECT_SUMMON_WILD:
- case SPELL_EFFECT_SUMMON_GUARDIAN:
case SPELL_EFFECT_TRANS_DOOR:
case SPELL_EFFECT_SUMMON_PET:
- case SPELL_EFFECT_SUMMON_POSSESSED:
- case SPELL_EFFECT_SUMMON_TOTEM:
case SPELL_EFFECT_SUMMON_OBJECT_WILD:
case SPELL_EFFECT_CREATE_HOUSE:
case SPELL_EFFECT_DUEL:
- case SPELL_EFFECT_SUMMON_TOTEM_SLOT1:
- case SPELL_EFFECT_SUMMON_TOTEM_SLOT2:
- case SPELL_EFFECT_SUMMON_TOTEM_SLOT3:
- case SPELL_EFFECT_SUMMON_TOTEM_SLOT4:
- case SPELL_EFFECT_SUMMON_PHANTASM:
- case SPELL_EFFECT_SUMMON_CRITTER:
case SPELL_EFFECT_SUMMON_OBJECT_SLOT1:
case SPELL_EFFECT_SUMMON_OBJECT_SLOT2:
case SPELL_EFFECT_SUMMON_OBJECT_SLOT3:
case SPELL_EFFECT_SUMMON_OBJECT_SLOT4:
- case SPELL_EFFECT_SUMMON_DEMON:
- case SPELL_EFFECT_150:
if(Unit *unit = m_targets.getUnitTarget())
data.append(unit->GetPackGUID());
else if(m_targets.getItemTargetGUID())
@@ -3056,6 +3441,13 @@ void Spell::SendLogExecute()
else
data << uint8(0);
break;
+ case SPELL_EFFECT_RESURRECT:
+ case SPELL_EFFECT_RESURRECT_NEW:
+ if(Unit *unit = m_targets.getUnitTarget())
+ data.append(unit->GetPackGUID());
+ else
+ data << uint8(0);
+ break;
default:
return;
}
@@ -3069,13 +3461,16 @@ void Spell::SendInterrupted(uint8 result)
{
WorldPacket data(SMSG_SPELL_FAILURE, (8+4+1));
data.append(m_caster->GetPackGUID());
- data << m_spellInfo->Id;
- data << result;
+ data << uint8(m_cast_count);
+ data << uint32(m_spellInfo->Id);
+ data << uint8(result);
m_caster->SendMessageToSet(&data, true);
data.Initialize(SMSG_SPELL_FAILED_OTHER, (8+4));
data.append(m_caster->GetPackGUID());
- data << m_spellInfo->Id;
+ data << uint8(m_cast_count);
+ data << uint32(m_spellInfo->Id);
+ data << uint8(result);
m_caster->SendMessageToSet(&data, true);
}
@@ -3119,7 +3514,7 @@ void Spell::SendChannelStart(uint32 duration)
{
if(itr->effectMask & (1<<0) )
{
- target = ObjectAccessor::GetGameObject(*m_caster, itr->targetGUID);
+ target = m_caster->GetMap()->GetGameObject(itr->targetGUID);
break;
}
}
@@ -3143,10 +3538,19 @@ void Spell::SendChannelStart(uint32 duration)
void Spell::SendResurrectRequest(Player* target)
{
- WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+2+4));
- data << m_caster->GetGUID();
- data << uint32(1) << uint16(0) << uint32(1);
+ // Both players and NPCs can resurrect using spells - have a look at creature 28487 for example
+ // However, the packet structure differs slightly
+
+ const char* sentName = m_caster->GetTypeId()==TYPEID_PLAYER ?"":m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex());
+ WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+strlen(sentName)+1+1+1));
+ data << uint64(m_caster->GetGUID());
+ data << uint32(strlen(sentName)+1);
+
+ data << sentName;
+ data << uint8(0);
+
+ data << uint8(m_caster->GetTypeId()==TYPEID_PLAYER ?0:1);
target->GetSession()->SendPacket(&data);
}
@@ -3183,7 +3587,7 @@ void Spell::TakeCastItem()
bool expendable = false;
bool withoutCharges = false;
- for (int i = 0; i<5; i++)
+ for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (proto->Spells[i].SpellId)
{
@@ -3199,7 +3603,7 @@ void Spell::TakeCastItem()
if (charges)
{
(charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
- if (proto->Stackable < 2)
+ if (proto->Stackable == 1)
m_CastItem->SetSpellCharges(i, charges);
m_CastItem->SetState(ITEM_CHANGED, (Player*)m_caster);
}
@@ -3225,7 +3629,7 @@ void Spell::TakeCastItem()
void Spell::TakePower()
{
- if(m_CastItem || m_triggeredByAuraSpell || !m_powerCost)
+ if(m_CastItem || m_triggeredByAuraSpell)
return;
bool hit = true;
@@ -3238,12 +3642,27 @@ void Spell::TakePower()
{
if(ihit->missCondition != SPELL_MISS_NONE && ihit->missCondition != SPELL_MISS_MISS/* && ihit->targetGUID!=m_caster->GetGUID()*/)
hit = false;
+ if (ihit->missCondition != SPELL_MISS_NONE)
+ {
+ //lower spell cost on fail (by talent aura)
+ if(Player *modOwner = ((Player*)m_caster)->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost);
+ }
break;
}
- if(hit && NeedsComboPoints(m_spellInfo))
- ((Player*)m_caster)->ClearComboPoints();
}
+ Powers powerType = Powers(m_spellInfo->powerType);
+
+ if(powerType == POWER_RUNE)
+ {
+ TakeRunePower();
+ return;
+ }
+
+ if (!m_powerCost)
+ return;
+
// health as power used
if(m_spellInfo->powerType == POWER_HEALTH)
{
@@ -3257,8 +3676,6 @@ void Spell::TakePower()
return;
}
- Powers powerType = Powers(m_spellInfo->powerType);
-
if(hit)
m_caster->ModifyPower(powerType, -m_powerCost);
else
@@ -3269,6 +3686,136 @@ void Spell::TakePower()
m_caster->SetLastManaUse(getMSTime());
}
+void Spell::TakeAmmo()
+{
+ if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
+
+ // wands don't have ammo
+ if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
+ return;
+
+ if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
+ {
+ if(pItem->GetMaxStackCount()==1)
+ {
+ // decrease durability for non-stackable throw weapon
+ ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
+ }
+ else
+ {
+ // decrease items amount for stackable throw weapon
+ uint32 count = 1;
+ ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
+ }
+ }
+ else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
+ ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
+ }
+}
+
+SpellCastResult Spell::CheckRuneCost(uint32 runeCostID)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_CAST_OK;
+
+ Player *plr = (Player*)m_caster;
+
+ if(plr->getClass() != CLASS_DEATH_KNIGHT)
+ return SPELL_CAST_OK;
+
+ SpellRuneCostEntry const *src = sSpellRuneCostStore.LookupEntry(runeCostID);
+
+ if(!src)
+ return SPELL_CAST_OK;
+
+ if(src->NoRuneCost())
+ return SPELL_CAST_OK;
+
+ int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death
+
+ for(uint32 i = 0; i < RUNE_DEATH; ++i)
+ runeCost[i] = src->RuneCost[i];
+
+ runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
+
+ for(uint32 i = 0; i < MAX_RUNES; ++i)
+ {
+ uint8 rune = plr->GetCurrentRune(i);
+ if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0))
+ runeCost[rune]--;
+ }
+
+ for(uint32 i = 0; i < RUNE_DEATH; ++i)
+ if(runeCost[i] > 0)
+ runeCost[RUNE_DEATH] += runeCost[i];
+
+ if(runeCost[RUNE_DEATH] > MAX_RUNES)
+ return SPELL_FAILED_NO_POWER; // not sure if result code is correct
+
+ return SPELL_CAST_OK;
+}
+
+void Spell::TakeRunePower()
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player *plr = (Player*)m_caster;
+
+ if(plr->getClass() != CLASS_DEATH_KNIGHT)
+ return;
+
+ SpellRuneCostEntry const *src = sSpellRuneCostStore.LookupEntry(m_spellInfo->runeCostID);
+
+ if(!src || (src->NoRuneCost() && src->NoRunicPowerGain()))
+ return;
+ m_runesState = plr->GetRunesState(); // store previous state
+
+ int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death
+
+ for(uint32 i = 0; i < RUNE_DEATH; ++i)
+ {
+ runeCost[i] = src->RuneCost[i];
+ }
+
+ runeCost[RUNE_DEATH] = 0; // calculated later
+
+ for(uint32 i = 0; i < MAX_RUNES; ++i)
+ {
+ uint8 rune = plr->GetCurrentRune(i);
+ if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0))
+ {
+ plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec
+ runeCost[rune]--;
+ }
+ }
+
+ runeCost[RUNE_DEATH] = runeCost[RUNE_BLOOD] + runeCost[RUNE_UNHOLY] + runeCost[RUNE_FROST];
+
+ if(runeCost[RUNE_DEATH] > 0)
+ {
+ for(uint32 i = 0; i < MAX_RUNES; ++i)
+ {
+ uint8 rune = plr->GetCurrentRune(i);
+ if((plr->GetRuneCooldown(i) == 0) && (rune == RUNE_DEATH))
+ {
+ plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec
+ runeCost[rune]--;
+ plr->ConvertRune(i, plr->GetBaseRune(i));
+ if(runeCost[RUNE_DEATH] == 0)
+ break;
+ }
+ }
+ }
+
+ // you can gain some runic power when use runes
+ float rp = src->runePowerGain;
+ rp *= sWorld.getRate(RATE_POWER_RUNICPOWER_INCOME);
+ plr->ModifyPower(POWER_RUNIC_POWER, (int32)rp);
+}
+
void Spell::TakeReagents()
{
if(m_IsTriggeredSpell) // reagents used in triggered spell removed by original spell or don't must be removed.
@@ -3277,11 +3824,13 @@ void Spell::TakeReagents()
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- if (m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP &&
- m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION))
+ // do not take reagents for these item casts
+ if (m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST)
return;
Player* p_caster = (Player*)m_caster;
+ if (p_caster->CanNoReagentCast(m_spellInfo))
+ return;
for(uint32 x=0;x<8;x++)
{
@@ -3297,7 +3846,7 @@ void Spell::TakeReagents()
ItemPrototype const *proto = m_CastItem->GetProto();
if( proto && proto->ItemId == itemid )
{
- for(int s=0;s<5;s++)
+ for(int s=0;s < MAX_ITEM_PROTO_SPELLS; ++s)
{
// CastItem will be used up and does not count as reagent
int32 charges = m_CastItem->GetSpellCharges(s);
@@ -3337,20 +3886,19 @@ void Spell::HandleThreatSpells(uint32 spellId)
DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat);
}
-void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float /*DamageMultiplier*/)
+void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i)
{
+ //effect has been handled, skip it
+ if(m_effectMask & (1<<i))
+ return;
+
unitTarget = pUnitTarget;
itemTarget = pItemTarget;
gameObjTarget = pGOTarget;
uint8 eff = m_spellInfo->Effect[i];
- uint32 mechanic = m_spellInfo->EffectMechanic[i];
- sLog.outDebug( "Spell: Effect : %u", eff);
-
- //Simply return. Do not display "immune" in red text on client
- if(unitTarget && unitTarget->IsImmunedToSpellEffect(eff, mechanic))
- return;
+ sLog.outDebug( "Spell: %u Effect : %u", m_spellInfo->Id, eff);
//we do not need DamageMultiplier here.
damage = CalculateDamage(i, NULL);
@@ -3358,21 +3906,8 @@ void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTar
if(eff<TOTAL_SPELL_EFFECTS)
{
//sLog.outDebug( "WORLD: Spell FX %d < TOTAL_SPELL_EFFECTS ", eff);
- (*this.*SpellEffects[eff])(i);
+ (this->*SpellEffects[eff])(i);
}
- /*
- else
- {
- sLog.outDebug( "WORLD: Spell FX %d > TOTAL_SPELL_EFFECTS ", eff);
- if (m_CastItem)
- EffectEnchantItemTmp(i);
- else
- {
- sLog.outError("SPELL: unknown effect %u spell id %u\n",
- eff, m_spellInfo->Id);
- }
- }
- */
}
void Spell::TriggerSpell()
@@ -3384,11 +3919,14 @@ void Spell::TriggerSpell()
}
}
-uint8 Spell::CanCast(bool strict)
+SpellCastResult Spell::CheckCast(bool strict)
{
// check cooldowns to prevent cheating
if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id))
{
+ //can cast triggered (by aura only?) spells while have this flag
+ if (!m_IsTriggeredSpell && ((Player*)m_caster)->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
+ return SPELL_FAILED_SPELL_IN_PROGRESS;
if(m_triggeredByAuraSpell)
return SPELL_FAILED_DONT_REPORT;
else
@@ -3405,19 +3943,59 @@ uint8 Spell::CanCast(bool strict)
// for now, ignore triggered spells
if( strict && !m_IsTriggeredSpell)
{
- // Cannot be used in this stance/form
- if(uint8 shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form))
- return shapeError;
+ bool checkForm = true;
+ // Ignore form req aura
+ Unit::AuraEffectList const& ignore = m_caster->GetAurasByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
+ for(Unit::AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
+ {
+ if (!(*i)->isAffectedOnSpell(m_spellInfo))
+ continue;
+ checkForm = false;
+ break;
+ }
+ if (checkForm)
+ {
+ // Cannot be used in this stance/form
+ SpellCastResult shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form);
+ if(shapeError != SPELL_CAST_OK)
+ return shapeError;
+
+ if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura()))
+ return SPELL_FAILED_ONLY_STEALTHED;
+ }
+ }
- if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura()))
- return SPELL_FAILED_ONLY_STEALTHED;
+ bool reqCombat=true;
+ Unit::AuraEffectList const& stateAuras = m_caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
+ for(Unit::AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j)
+ {
+ if((*j)->isAffectedOnSpell(m_spellInfo))
+ {
+ if ((*j)->GetMiscValue()==1)
+ {
+ reqCombat=false;
+ break;
+ }
+ }
}
- // caster state requirements
- if(m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState)))
- return SPELL_FAILED_CASTER_AURASTATE;
- if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot)))
- return SPELL_FAILED_CASTER_AURASTATE;
+ // caster state requirements
+ // not for triggered spells (needed by execute)
+ if (!m_IsTriggeredSpell)
+ {
+ if(m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState), m_spellInfo, m_caster))
+ return SPELL_FAILED_CASTER_AURASTATE;
+ if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot), m_spellInfo, m_caster))
+ return SPELL_FAILED_CASTER_AURASTATE;
+
+ if(m_spellInfo->casterAuraSpell && !m_caster->HasAura(m_spellInfo->casterAuraSpell))
+ return SPELL_FAILED_CASTER_AURASTATE;
+ if(m_spellInfo->excludeCasterAuraSpell && m_caster->HasAura(m_spellInfo->excludeCasterAuraSpell))
+ return SPELL_FAILED_CASTER_AURASTATE;
+
+ if(reqCombat && m_caster->isInCombat() && IsNonCombatSpell(m_spellInfo))
+ return SPELL_FAILED_AFFECTING_COMBAT;
+ }
// cancel autorepeat spells if cast start when moving
// (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
@@ -3429,22 +4007,26 @@ uint8 Spell::CanCast(bool strict)
return SPELL_FAILED_MOVING;
}
- Unit *target = m_targets.getUnitTarget();
-
- if(target)
+ if(Unit *target = m_targets.getUnitTarget())
{
// target state requirements (not allowed state), apply to self also
- if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot)))
+ if(!m_IsTriggeredSpell && m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot), m_spellInfo, m_caster))
+ return SPELL_FAILED_TARGET_AURASTATE;
+
+ if(m_spellInfo->targetAuraSpell && !target->HasAura(m_spellInfo->targetAuraSpell))
+ return SPELL_FAILED_TARGET_AURASTATE;
+
+ if(m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell))
return SPELL_FAILED_TARGET_AURASTATE;
if(target != m_caster)
{
// target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds
- if(m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState)))
+ if(!m_IsTriggeredSpell && m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState), m_spellInfo, m_caster))
return SPELL_FAILED_TARGET_AURASTATE;
// Not allow casting on flying player
- if (target->isInFlight())
+ if (target->hasUnitState(UNIT_STAT_UNATTACKABLE))
return SPELL_FAILED_BAD_TARGETS;
if(!m_IsTriggeredSpell && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target))
@@ -3453,13 +4035,23 @@ uint8 Spell::CanCast(bool strict)
// auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode
// this case can be triggered if rank not found (too low-level target for first rank)
if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem)
- {
for(int i=0;i<3;i++)
- {
if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA)
if(target->getLevel() + 10 < m_spellInfo->spellLevel)
return SPELL_FAILED_LOWLEVEL;
- }
+ }
+ else if (m_caster->GetTypeId()==TYPEID_PLAYER) // Target - is player caster
+ {
+ // Additional check for some spells
+ // If 0 spell effect empty - client not send target data (need use selection)
+ // TODO: check it on next client version
+ if (m_targets.m_targetMask == TARGET_FLAG_SELF &&
+ m_spellInfo->EffectImplicitTargetA[1] == TARGET_UNIT_TARGET_ENEMY)
+ {
+ if (target = m_caster->GetUnit(*m_caster, ((Player *)m_caster)->GetSelection()))
+ m_targets.setUnitTarget(target);
+ else
+ return SPELL_FAILED_BAD_TARGETS;
}
}
@@ -3468,7 +4060,7 @@ uint8 Spell::CanCast(bool strict)
{
if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_PET)
{
- target = m_caster->GetPet();
+ target = m_caster->GetGuardianPet();
if(!target)
{
if(m_triggeredByAuraSpell) // not report pet not existence for triggered spells
@@ -3512,14 +4104,15 @@ uint8 Spell::CanCast(bool strict)
}
if(IsPositiveSpell(m_spellInfo->Id))
- {
- if(target->IsImmunedToSpell(m_spellInfo,false))
+ if(target->IsImmunedToSpell(m_spellInfo))
return SPELL_FAILED_TARGET_AURASTATE;
- }
//Must be behind the target.
if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster)
- && (m_spellInfo->SpellFamilyName != SPELLFAMILY_DRUID || m_spellInfo->SpellFamilyFlags != 0x0000000000020000LL))
+ //Exclusion for Pounce: Facing Limitation was removed in 2.0.1, but it still uses the same, old Ex-Flags
+ && (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags.IsEqual(0x20000,0,0)))
+ //Mutilate no longer requires you be behind the target as of patch 3.0.3
+ && (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellInfo->SpellFamilyFlags[1] & 0x200000)))
{
SendInterrupted(2);
return SPELL_FAILED_NOT_BEHIND;
@@ -3534,10 +4127,9 @@ uint8 Spell::CanCast(bool strict)
// check if target is in combat
if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat())
- {
return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
- }
}
+
// Spell casted only on battleground
if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) && m_caster->GetTypeId()==TYPEID_PLAYER)
if(!((Player*)m_caster)->InBattleGround())
@@ -3547,14 +4139,22 @@ uint8 Spell::CanCast(bool strict)
// - with greater than 15 min CD without SPELL_ATTR_EX4_USABLE_IN_ARENA flag
// - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag
if( (m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) ||
- GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * 1000 && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) )
+ GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * IN_MILISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) )
if(MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId()))
if(mapEntry->IsBattleArena())
return SPELL_FAILED_NOT_IN_ARENA;
// zone check
- if(!IsSpellAllowedInLocation(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId()))
- return SPELL_FAILED_REQUIRES_AREA;
+ if(m_caster->GetTypeId() == TYPEID_UNIT || !((Player*)m_caster)->isGameMaster())
+ {
+ uint32 zone, area;
+ m_caster->GetZoneAndAreaId(zone,area);
+
+ SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area,
+ m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL);
+ if(locRes != SPELL_CAST_OK)
+ return locRes;
+ }
// not let players cast spells at mount (and let do it to creatures)
if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell &&
@@ -3568,11 +4168,14 @@ uint8 Spell::CanCast(bool strict)
// always (except passive spells) check items (focus object can be required for any type casts)
if(!IsPassiveSpell(m_spellInfo->Id))
- if(uint8 castResult = CheckItems())
+ {
+ SpellCastResult castResult = CheckItems();
+ if(castResult != SPELL_CAST_OK)
return castResult;
+ }
/*//ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38
- if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example)
+ if(m_UniqueTargetInfo.empty()) // skip second CheckCast apply (for delayed spells for example)
{
for(uint8 j = 0; j < 3; j++)
{
@@ -3607,7 +4210,7 @@ uint8 Spell::CanCast(bool strict)
cell.data.Part.reserved = ALL_DISTRICT;
MaNGOS::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range);
- MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check);
+ MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> checker(m_caster, p_GameObject,go_check);
TypeContainerVisitor<MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
@@ -3645,7 +4248,7 @@ uint8 Spell::CanCast(bool strict)
cell.SetNoCreate(); // Really don't know what is that???
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range);
- MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check);
+ MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(m_caster, p_Creature, u_check);
TypeContainerVisitor<MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
@@ -3708,13 +4311,16 @@ uint8 Spell::CanCast(bool strict)
if(!m_IsTriggeredSpell)
{
- if(uint8 castResult = CheckRange(strict))
+ SpellCastResult castResult = CheckRange(strict);
+ if(castResult != SPELL_CAST_OK)
return castResult;
- if(uint8 castResult = CheckPower())
+ castResult = CheckPower();
+ if(castResult != SPELL_CAST_OK)
return castResult;
- if(uint8 castResult = CheckCasterAuras())
+ castResult = CheckCasterAuras();
+ if(castResult != SPELL_CAST_OK)
return castResult;
}
@@ -3725,12 +4331,7 @@ uint8 Spell::CanCast(bool strict)
{
case SPELL_EFFECT_DUMMY:
{
- if(m_spellInfo->SpellIconID == 1648) // Execute
- {
- if(!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2)
- return SPELL_FAILED_BAD_TARGETS;
- }
- else if (m_spellInfo->Id == 51582) // Rocket Boots Engaged
+ if (m_spellInfo->Id == 51582) // Rocket Boots Engaged
{
if(m_caster->IsInWater())
return SPELL_FAILED_ONLY_ABOVEWATER;
@@ -3739,7 +4340,7 @@ uint8 Spell::CanCast(bool strict)
{
// spell different for friends and enemies
// hart version required facing
- if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, target ))
+ if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, m_targets.getUnitTarget() ))
return SPELL_FAILED_UNIT_NOT_INFRONT;
}
else if (m_spellInfo->Id == 19938) // Awaken Peon
@@ -3750,25 +4351,15 @@ uint8 Spell::CanCast(bool strict)
}
break;
}
- case SPELL_EFFECT_SCHOOL_DAMAGE:
- {
- // Hammer of Wrath
- if(m_spellInfo->SpellVisual == 7250)
- {
- if (!m_targets.getUnitTarget())
- return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
-
- if(m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2)
- return SPELL_FAILED_BAD_TARGETS;
- }
- break;
- }
case SPELL_EFFECT_LEARN_SPELL:
{
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_TARGETS;
+
if(m_spellInfo->EffectImplicitTargetA[i] != TARGET_UNIT_PET)
break;
- Pet* pet = m_caster->GetPet();
+ Pet* pet = ((Player*)m_caster)->GetPet();
if(!pet)
return SPELL_FAILED_NO_PET;
@@ -3778,21 +4369,17 @@ uint8 Spell::CanCast(bool strict)
if(!learn_spellproto)
return SPELL_FAILED_NOT_KNOWN;
- if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id))
- return SPELL_FAILED_TOO_MANY_SKILLS;
-
if(m_spellInfo->spellLevel > pet->getLevel())
return SPELL_FAILED_LOWLEVEL;
- if(!pet->HasTPForSpell(learn_spellproto->Id))
- return SPELL_FAILED_TRAINING_POINTS;
-
break;
}
case SPELL_EFFECT_LEARN_PET_SPELL:
{
- Pet* pet = m_caster->GetPet();
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_TARGETS;
+ Pet* pet = ((Player*)m_caster)->GetPet();
if(!pet)
return SPELL_FAILED_NO_PET;
@@ -3801,31 +4388,29 @@ uint8 Spell::CanCast(bool strict)
if(!learn_spellproto)
return SPELL_FAILED_NOT_KNOWN;
- if(!pet->CanTakeMoreActiveSpells(learn_spellproto->Id))
- return SPELL_FAILED_TOO_MANY_SKILLS;
-
if(m_spellInfo->spellLevel > pet->getLevel())
return SPELL_FAILED_LOWLEVEL;
- if(!pet->HasTPForSpell(learn_spellproto->Id))
- return SPELL_FAILED_TRAINING_POINTS;
-
break;
}
case SPELL_EFFECT_FEED_PET:
{
- if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getItemTarget() )
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ Item* foodItem = m_targets.getItemTarget();
+ if(!foodItem)
return SPELL_FAILED_BAD_TARGETS;
- Pet* pet = m_caster->GetPet();
+ Pet* pet = ((Player*)m_caster)->GetPet();
if(!pet)
return SPELL_FAILED_NO_PET;
- if(!pet->HaveInDiet(m_targets.getItemTarget()->GetProto()))
+ if(!pet->HaveInDiet(foodItem->GetProto()))
return SPELL_FAILED_WRONG_PET_FOOD;
- if(!pet->GetCurrentFoodBenefitLevel(m_targets.getItemTarget()->GetProto()->ItemLevel))
+ if(!pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel))
return SPELL_FAILED_FOOD_LOWLEVEL;
if(m_caster->isInCombat() || pet->isInCombat())
@@ -3897,130 +4482,40 @@ uint8 Spell::CanCast(bool strict)
// In BattleGround players can use only flags and banners
if( ((Player*)m_caster)->InBattleGround() &&
- !((Player*)m_caster)->isAllowUseBattleGroundObject() )
+ !((Player*)m_caster)->CanUseBattleGroundObject() )
return SPELL_FAILED_TRY_AGAIN;
// get the lock entry
- LockEntry const *lockInfo = NULL;
+ uint32 lockId = 0;
if (GameObject* go=m_targets.getGOTarget())
- lockInfo = sLockStore.LookupEntry(go->GetLockId());
+ lockId = go->GetLockId();
else if(Item* itm=m_targets.getItemTarget())
- lockInfo = sLockStore.LookupEntry(itm->GetProto()->LockID);
-
- // check lock compatibility
- if (lockInfo)
- {
- // check for lock - key pair (checked by client also, just prevent cheating
- bool ok_key = false;
- for(int it = 0; it < 5; ++it)
- {
- switch(lockInfo->keytype[it])
- {
- case LOCK_KEY_NONE:
- break;
- case LOCK_KEY_ITEM:
- {
- if(lockInfo->key[it])
- {
- if(m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it])
- ok_key =true;
- break;
- }
- }
- case LOCK_KEY_SKILL:
- {
- if(uint32(m_spellInfo->EffectMiscValue[i])!=lockInfo->key[it])
- break;
+ lockId = itm->GetProto()->LockID;
- switch(lockInfo->key[it])
- {
- case LOCKTYPE_HERBALISM:
- if(((Player*)m_caster)->HasSkill(SKILL_HERBALISM))
- ok_key =true;
- break;
- case LOCKTYPE_MINING:
- if(((Player*)m_caster)->HasSkill(SKILL_MINING))
- ok_key =true;
- break;
- default:
- ok_key =true;
- break;
- }
- }
- }
- if(ok_key)
- break;
- }
+ SkillType skillId =SKILL_NONE;
+ int32 reqSkillValue = 0;
+ int32 skillValue = 0;
- if(!ok_key)
- return SPELL_FAILED_BAD_TARGETS;
- }
+ // check lock compatibility
+ SpellCastResult res = CanOpenLock(i,lockId,skillId,reqSkillValue,skillValue);
+ if(res != SPELL_CAST_OK)
+ return res;
// chance for fail at orange mining/herb/LockPicking gathering attempt
- if (!m_selfContainer || ((*m_selfContainer) != this))
- break;
-
- // get the skill value of the player
- int32 SkillValue = 0;
- bool canFailAtMax = true;
- if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_HERBALISM)
+ // second check prevent fail at rechecks
+ if(skillId != SKILL_NONE && (!m_selfContainer || ((*m_selfContainer) != this)))
{
- SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_HERBALISM);
- canFailAtMax = false;
- }
- else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_MINING)
- {
- SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_MINING);
- canFailAtMax = false;
- }
- else if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK)
- SkillValue = ((Player*)m_caster)->GetSkillValue(SKILL_LOCKPICKING);
-
- // castitem check: rogue using skeleton keys. the skill values should not be added in this case.
- if(m_CastItem)
- SkillValue = 0;
-
- // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value)
- // TODO: is this a hack?
- SkillValue += m_currentBasePoints[i]+1;
-
- // get the required lock value
- int32 ReqValue=0;
- if (lockInfo)
- {
- // check for lock - key pair
- bool ok = false;
- for(int it = 0; it < 5; ++it)
- {
- if(lockInfo->keytype[it]==LOCK_KEY_ITEM && lockInfo->key[it] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[it])
- {
- // if so, we're good to go
- ok = true;
- break;
- }
- }
- if(ok)
- break;
+ bool canFailAtMax = skillId != SKILL_HERBALISM && skillId != SKILL_MINING;
- if (m_spellInfo->EffectMiscValue[i] == LOCKTYPE_PICKLOCK)
- ReqValue = lockInfo->requiredlockskill;
- else
- ReqValue = lockInfo->requiredminingskill;
+ // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill)
+ if((canFailAtMax || skillValue < sWorld.GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue-25, skillValue+37))
+ return SPELL_FAILED_TRY_AGAIN;
}
-
- // skill doesn't meet the required value
- if (ReqValue > SkillValue)
- return SPELL_FAILED_LOW_CASTLEVEL;
-
- // chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill)
- if((canFailAtMax || SkillValue < sWorld.GetConfigMaxSkillValue()) && ReqValue > irand(SkillValue-25, SkillValue+37))
- return SPELL_FAILED_TRY_AGAIN;
-
break;
}
case SPELL_EFFECT_SUMMON_DEAD_PET:
{
- Creature *pet = m_caster->GetPet();
+ Creature *pet = m_caster->GetGuardianPet();
if(!pet)
return SPELL_FAILED_NO_PET;
@@ -4029,34 +4524,26 @@ uint8 Spell::CanCast(bool strict)
break;
}
- // This is generic summon effect now and don't make this check for summon types similar
- // SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN.
- // These won't show up in m_caster->GetPetGUID()
+ // This is generic summon effect
case SPELL_EFFECT_SUMMON:
{
- switch(m_spellInfo->EffectMiscValueB[i])
+ SummonPropertiesEntry const *SummonProperties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]);
+ if(!SummonProperties)
+ break;
+ switch(SummonProperties->Category)
{
- case SUMMON_TYPE_POSESSED:
- case SUMMON_TYPE_POSESSED2:
- case SUMMON_TYPE_POSESSED3:
- case SUMMON_TYPE_DEMON:
- case SUMMON_TYPE_SUMMON:
- {
+ case SUMMON_CATEGORY_PET:
if(m_caster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
-
+ case SUMMON_CATEGORY_POSSESSED:
if(m_caster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
break;
- }
}
break;
}
- // Don't make this check for SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN.
- // These won't show up in m_caster->GetPetGUID()
- case SPELL_EFFECT_SUMMON_POSSESSED:
+ // Not used for summon?
case SPELL_EFFECT_SUMMON_PHANTASM:
- case SPELL_EFFECT_SUMMON_DEMON:
{
if(m_caster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
@@ -4070,13 +4557,11 @@ uint8 Spell::CanCast(bool strict)
{
if(m_caster->GetPetGUID()) //let warlock do a replacement summon
{
-
- Pet* pet = ((Player*)m_caster)->GetPet();
-
if (m_caster->GetTypeId()==TYPEID_PLAYER && m_caster->getClass()==CLASS_WARLOCK)
{
if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
- pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetGUID());
+ if(Pet* pet = ((Player*)m_caster)->GetPet())
+ pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetGUID());
}
else
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
@@ -4112,7 +4597,7 @@ uint8 Spell::CanCast(bool strict)
case SPELL_EFFECT_LEAP:
case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:
{
- float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ float dis = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation());
float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation());
// teleport a bit above terrain level to avoid falling below it
@@ -4148,25 +4633,38 @@ uint8 Spell::CanCast(bool strict)
{
case SPELL_AURA_DUMMY:
{
- if(m_spellInfo->Id == 1515)
+ //custom check
+ switch(m_spellInfo->Id)
{
- if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER)
- return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
+ case 61336:
+ if(m_caster->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_caster)->IsInFeralForm())
+ return SPELL_FAILED_ONLY_SHAPESHIFT;
+ break;
+ case 1515:
+ {
+ if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
- if (m_targets.getUnitTarget()->getLevel() > m_caster->getLevel())
- return SPELL_FAILED_HIGHLEVEL;
+ if (m_targets.getUnitTarget()->getLevel() > m_caster->getLevel())
+ return SPELL_FAILED_HIGHLEVEL;
- // use SMSG_PET_TAME_FAILURE?
- if (!((Creature*)m_targets.getUnitTarget())->GetCreatureInfo()->isTameable ())
- return SPELL_FAILED_BAD_TARGETS;
+ // use SMSG_PET_TAME_FAILURE?
+ if (!((Creature*)m_targets.getUnitTarget())->GetCreatureInfo()->isTameable ())
+ return SPELL_FAILED_BAD_TARGETS;
- if(m_caster->GetPetGUID())
- return SPELL_FAILED_ALREADY_HAVE_SUMMON;
+ if(m_caster->GetPetGUID())
+ return SPELL_FAILED_ALREADY_HAVE_SUMMON;
- if(m_caster->GetCharmGUID())
- return SPELL_FAILED_ALREADY_HAVE_CHARM;
+ if(m_caster->GetCharmGUID())
+ return SPELL_FAILED_ALREADY_HAVE_CHARM;
+
+ break;
+ }
+ default:
+ break;
}
- }break;
+ break;
+ }
case SPELL_AURA_MOD_POSSESS:
case SPELL_AURA_MOD_CHARM:
{
@@ -4199,17 +4697,14 @@ uint8 Spell::CanCast(bool strict)
return SPELL_FAILED_NO_MOUNTS_ALLOWED;
// Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells
- if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaId)
- return SPELL_FAILED_NO_MOUNTS_ALLOWED;
-
- if (m_caster->GetAreaId()==35)
+ if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaGroupId)
return SPELL_FAILED_NO_MOUNTS_ALLOWED;
ShapeshiftForm form = m_caster->m_form;
if( form == FORM_CAT || form == FORM_TREE || form == FORM_TRAVEL ||
form == FORM_AQUA || form == FORM_BEAR || form == FORM_DIREBEAR ||
form == FORM_CREATUREBEAR || form == FORM_GHOSTWOLF || form == FORM_FLIGHT ||
- form == FORM_FLIGHT_EPIC || form == FORM_MOONKIN )
+ form == FORM_FLIGHT_EPIC || form == FORM_MOONKIN || form == FORM_METAMORPHOSIS )
return SPELL_FAILED_NOT_SHAPESHIFT;
break;
@@ -4225,14 +4720,13 @@ uint8 Spell::CanCast(bool strict)
break;
}
- case SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED:
+ case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED:
case SPELL_AURA_FLY:
{
- // not allow cast fly spells at old maps by players (all spells is self target)
- if(m_caster->GetTypeId()==TYPEID_PLAYER)
+ // not allow cast fly spells at old maps by players (all spells is self target)
+ if(m_originalCaster && m_originalCaster->GetTypeId()==TYPEID_PLAYER)
{
- if( !((Player*)m_caster)->isGameMaster() &&
- GetVirtualMapForMapAndZone(m_caster->GetMapId(),m_caster->GetZoneId()) != 530)
+ if( !((Player*)m_originalCaster)->IsAllowUseFlyMountsHere() )
return SPELL_FAILED_NOT_HERE;
}
break;
@@ -4256,10 +4750,10 @@ uint8 Spell::CanCast(bool strict)
}
// all ok
- return 0;
+ return SPELL_CAST_OK;
}
-int16 Spell::PetCanCast(Unit* target)
+SpellCastResult Spell::CheckPetCast(Unit* target)
{
if(!m_caster->isAlive())
return SPELL_FAILED_CASTER_DEAD;
@@ -4269,28 +4763,25 @@ int16 Spell::PetCanCast(Unit* target)
if(m_caster->isInCombat() && IsNonCombatSpell(m_spellInfo))
return SPELL_FAILED_AFFECTING_COMBAT;
- if(m_caster->GetTypeId()==TYPEID_UNIT && (((Creature*)m_caster)->isPet() || m_caster->isCharmed()))
- {
//dead owner (pets still alive when owners ressed?)
- if(m_caster->GetCharmerOrOwner() && !m_caster->GetCharmerOrOwner()->isAlive())
- return SPELL_FAILED_CASTER_DEAD;
+ if(Unit *owner = m_caster->GetCharmerOrOwner())
+ if(!owner->isAlive())
+ return SPELL_FAILED_CASTER_DEAD;
if(!target && m_targets.getUnitTarget())
target = m_targets.getUnitTarget();
- bool need = false;
- for(uint32 i = 0;i<3;i++)
+ for(uint32 i = 0; i < 3; ++i)
{
- if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ENEMY || m_spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ALLY || m_spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ANY || m_spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_PARTY || m_spellInfo->EffectImplicitTargetA[i] == TARGET_DST_TARGET_ENEMY)
+ if(spellmgr.SpellTargetType[m_spellInfo->EffectImplicitTargetA[i]] == TARGET_TYPE_UNIT_TARGET
+ || spellmgr.SpellTargetType[m_spellInfo->EffectImplicitTargetA[i]] == TARGET_TYPE_DEST_TARGET)
{
- need = true;
if(!target)
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
+ m_targets.setUnitTarget(target);
break;
}
}
- if(need)
- m_targets.setUnitTarget(target);
Unit* _target = m_targets.getUnitTarget();
@@ -4305,22 +4796,17 @@ int16 Spell::PetCanCast(Unit* target)
//cooldown
if(((Creature*)m_caster)->HasSpellCooldown(m_spellInfo->Id))
return SPELL_FAILED_NOT_READY;
- }
- uint16 result = CanCast(true);
- if(result != 0)
- return result;
- else
- return -1; //this allows to check spell fail 0, in combat
+ return CheckCast(true);
}
-uint8 Spell::CheckCasterAuras() const
+SpellCastResult Spell::CheckCasterAuras() const
{
// Flag drop spells totally immuned to caster auras
// FIXME: find more nice check for all totally immuned spells
// AttributesEx3 & 0x10000000?
if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991)
- return 0;
+ return SPELL_CAST_OK;
uint8 school_immune = 0;
uint32 mechanic_immune = 0;
@@ -4340,26 +4826,27 @@ uint8 Spell::CheckCasterAuras() const
dispel_immune |= GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i]));
}
//immune movement impairment and loss of control
- if(m_spellInfo->Id==(uint32)42292)
+ if(m_spellInfo->Id==42292 || m_spellInfo->Id==59752)
mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
}
//Check whether the cast should be prevented by any state you might have.
- uint8 prevented_reason = 0;
+ SpellCastResult prevented_reason = SPELL_CAST_OK;
// Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out
- if(!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED) && m_caster->HasAuraType(SPELL_AURA_MOD_STUN))
+ uint32 unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS); // Get unit state
+ if(unitflag & UNIT_FLAG_STUNNED && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED))
prevented_reason = SPELL_FAILED_STUNNED;
- else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED))
+ else if(unitflag & UNIT_FLAG_CONFUSED && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED))
prevented_reason = SPELL_FAILED_CONFUSED;
- else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING) && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED))
+ else if(unitflag & UNIT_FLAG_FLEEING && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED))
prevented_reason = SPELL_FAILED_FLEEING;
- else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE)
+ else if(unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE)
prevented_reason = SPELL_FAILED_SILENCED;
- else if(m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY)
+ else if(unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY)
prevented_reason = SPELL_FAILED_PACIFIED;
// Attr must make flag drop spell totally immune from all effects
- if(prevented_reason)
+ if(prevented_reason != SPELL_CAST_OK)
{
if(school_immune || mechanic_immune || dispel_immune)
{
@@ -4369,7 +4856,7 @@ uint8 Spell::CheckCasterAuras() const
{
if(itr->second)
{
- if( GetSpellMechanicMask(itr->second->GetSpellProto(), itr->second->GetEffIndex()) & mechanic_immune )
+ if( GetAllSpellMechanicMask(itr->second->GetSpellProto()) & mechanic_immune )
continue;
if( GetSpellSchoolMask(itr->second->GetSpellProto()) & school_immune )
continue;
@@ -4378,28 +4865,34 @@ uint8 Spell::CheckCasterAuras() const
//Make a second check for spell failed so the right SPELL_FAILED message is returned.
//That is needed when your casting is prevented by multiple states and you are only immune to some of them.
- switch(itr->second->GetModifier()->m_auraname)
+ for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i)
{
- case SPELL_AURA_MOD_STUN:
- if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED))
- return SPELL_FAILED_STUNNED;
- break;
- case SPELL_AURA_MOD_CONFUSE:
- if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED))
- return SPELL_FAILED_CONFUSED;
- break;
- case SPELL_AURA_MOD_FEAR:
- if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED))
- return SPELL_FAILED_FLEEING;
- break;
- case SPELL_AURA_MOD_SILENCE:
- case SPELL_AURA_MOD_PACIFY:
- case SPELL_AURA_MOD_PACIFY_SILENCE:
- if( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY)
- return SPELL_FAILED_PACIFIED;
- else if ( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE)
- return SPELL_FAILED_SILENCED;
- break;
+ if (AuraEffect * part = itr->second->GetPartAura(i))
+ {
+ switch(part->GetAuraName())
+ {
+ case SPELL_AURA_MOD_STUN:
+ if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED))
+ return SPELL_FAILED_STUNNED;
+ break;
+ case SPELL_AURA_MOD_CONFUSE:
+ if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED))
+ return SPELL_FAILED_CONFUSED;
+ break;
+ case SPELL_AURA_MOD_FEAR:
+ if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_FEARED))
+ return SPELL_FAILED_FLEEING;
+ break;
+ case SPELL_AURA_MOD_SILENCE:
+ case SPELL_AURA_MOD_PACIFY:
+ case SPELL_AURA_MOD_PACIFY_SILENCE:
+ if( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_PACIFY)
+ return SPELL_FAILED_PACIFIED;
+ else if ( m_spellInfo->PreventionType==SPELL_PREVENTION_TYPE_SILENCE)
+ return SPELL_FAILED_SILENCED;
+ break;
+ }
+ }
}
}
}
@@ -4408,7 +4901,7 @@ uint8 Spell::CheckCasterAuras() const
else
return prevented_reason;
}
- return 0; // all ok
+ return SPELL_CAST_OK;
}
bool Spell::CanAutoCast(Unit* target)
@@ -4421,25 +4914,26 @@ bool Spell::CanAutoCast(Unit* target)
{
if( m_spellInfo->StackAmount <= 1)
{
- if( target->HasAura(m_spellInfo->Id, j) )
+ if( target->HasAuraEffect(m_spellInfo->Id, j) )
return false;
}
else
{
- if( target->GetAuras().count(Unit::spellEffectPair(m_spellInfo->Id, j)) >= m_spellInfo->StackAmount)
- return false;
+ if( AuraEffect * aureff = target->GetAuraEffect(m_spellInfo->Id, j))
+ if (aureff->GetParentAura()->GetStackAmount() >= m_spellInfo->StackAmount)
+ return false;
}
}
else if ( IsAreaAuraEffect( m_spellInfo->Effect[j] ))
{
- if( target->HasAura(m_spellInfo->Id, j) )
- return false;
+ if( target->HasAuraEffect(m_spellInfo->Id, j) )
+ return false;
}
}
- int16 result = PetCanCast(target);
+ SpellCastResult result = CheckPetCast(target);
- if(result == -1 || result == SPELL_FAILED_UNIT_NOT_INFRONT)
+ if(result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT)
{
FillTargetMap();
//check if among target units, our WANTED target is as well (->only self cast spells return false)
@@ -4450,12 +4944,13 @@ bool Spell::CanAutoCast(Unit* target)
return false; //target invalid
}
-uint8 Spell::CheckRange(bool strict)
+SpellCastResult Spell::CheckRange(bool strict)
{
//float range_mod;
// self cast doesn't need range checking -- also for Starshards fix
- if (m_spellInfo->rangeIndex == 1) return 0;
+ if (m_spellInfo->rangeIndex == 1)
+ return SPELL_CAST_OK;
// i do not know why we need this
/*if (strict) //add radius of caster
@@ -4464,15 +4959,15 @@ uint8 Spell::CheckRange(bool strict)
range_mod = 6.25;*/
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
- float max_range = GetSpellMaxRange(srange); // + range_mod;
- float min_range = GetSpellMinRange(srange);
+
+ Unit *target = m_targets.getUnitTarget();
+ float max_range = m_caster->GetSpellMaxRangeForTarget(target, srange); // + range_mod;
+ float min_range = m_caster->GetSpellMinRangeForTarget(target, srange);
uint32 range_type = GetSpellRangeType(srange);
if(Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this);
- Unit *target = m_targets.getUnitTarget();
-
if(target && target != m_caster)
{
if(range_type == SPELL_RANGE_MELEE)
@@ -4499,14 +4994,13 @@ uint8 Spell::CheckRange(bool strict)
if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0)
{
- float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ);
- if(dist > max_range)
+ if(!m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,max_range))
return SPELL_FAILED_OUT_OF_RANGE;
- if(dist < min_range)
+ if(m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,min_range))
return SPELL_FAILED_TOO_CLOSE;
}
- return 0; // ok
+ return SPELL_CAST_OK;
}
int32 Spell::CalculatePowerCost()
@@ -4546,9 +5040,12 @@ int32 Spell::CalculatePowerCost()
case POWER_FOCUS:
case POWER_ENERGY:
case POWER_HAPPINESS:
- // case POWER_RUNES:
powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100;
break;
+ case POWER_RUNE:
+ case POWER_RUNIC_POWER:
+ sLog.outDebug("Spell::CalculateManaCost: Not implemented yet!");
+ break;
default:
sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id);
return 0;
@@ -4574,39 +5071,43 @@ int32 Spell::CalculatePowerCost()
return powerCost;
}
-uint8 Spell::CheckPower()
+SpellCastResult Spell::CheckPower()
{
// item cast not used power
if(m_CastItem)
- return 0;
+ return SPELL_CAST_OK;
// health as power used - need check health amount
if(m_spellInfo->powerType == POWER_HEALTH)
{
if(m_caster->GetHealth() <= m_powerCost)
return SPELL_FAILED_CASTER_AURASTATE;
- return 0;
+ return SPELL_CAST_OK;
}
// Check valid power type
if( m_spellInfo->powerType >= MAX_POWERS )
{
- sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType);
+ sLog.outError("Spell::CheckPower: Unknown power type '%d'", m_spellInfo->powerType);
return SPELL_FAILED_UNKNOWN;
}
+
+ SpellCastResult failReason = CheckRuneCost(m_spellInfo->runeCostID);
+ if(failReason != SPELL_CAST_OK)
+ return failReason;
+
// Check power amount
Powers powerType = Powers(m_spellInfo->powerType);
if(m_caster->GetPower(powerType) < m_powerCost)
return SPELL_FAILED_NO_POWER;
else
- return 0;
+ return SPELL_CAST_OK;
}
-uint8 Spell::CheckItems()
+SpellCastResult Spell::CheckItems()
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
- return 0;
+ return SPELL_CAST_OK;
- uint32 itemid, itemcount;
Player* p_caster = (Player*)m_caster;
if(!m_CastItem)
@@ -4616,77 +5117,72 @@ uint8 Spell::CheckItems()
}
else
{
- itemid = m_CastItem->GetEntry();
+ uint32 itemid = m_CastItem->GetEntry();
if( !p_caster->HasItemCount(itemid,1) )
return SPELL_FAILED_ITEM_NOT_READY;
- else
- {
- ItemPrototype const *proto = m_CastItem->GetProto();
- if(!proto)
- return SPELL_FAILED_ITEM_NOT_READY;
- for (int i = 0; i<5; i++)
- {
- if (proto->Spells[i].SpellCharges)
- {
- if(m_CastItem->GetSpellCharges(i)==0)
- return SPELL_FAILED_NO_CHARGES_REMAIN;
- }
- }
+ ItemPrototype const *proto = m_CastItem->GetProto();
+ if(!proto)
+ return SPELL_FAILED_ITEM_NOT_READY;
+
+ for (int i = 0; i<5; i++)
+ if (proto->Spells[i].SpellCharges)
+ if(m_CastItem->GetSpellCharges(i)==0)
+ return SPELL_FAILED_NO_CHARGES_REMAIN;
- uint32 ItemClass = proto->Class;
- if (ItemClass == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget())
+ // consumable cast item checks
+ if (proto->Class == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget())
+ {
+ // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
+ SpellCastResult failReason = SPELL_CAST_OK;
+ for (int i = 0; i < 3; i++)
{
- // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
- uint8 failReason = 0;
- for (int i = 0; i < 3; i++)
- {
// skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.getUnitTarget() is not the real target but the caster
if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_PET)
- continue;
+ continue;
- if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL)
+ if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL)
+ {
+ if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth())
{
- if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth())
- {
- failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_HEALTH;
- continue;
- }
- else
- {
- failReason = 0;
- break;
- }
+ failReason = SPELL_FAILED_ALREADY_AT_FULL_HEALTH;
+ continue;
+ }
+ else
+ {
+ failReason = SPELL_CAST_OK;
+ break;
}
+ }
- // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
- if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE)
+ // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
+ if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE)
+ {
+ if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
{
- if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
- {
- failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER;
- continue;
- }
+ failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER;
+ continue;
+ }
- Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
- if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power))
- {
- failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER;
- continue;
- }
- else
- {
- failReason = 0;
- break;
- }
+ Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
+ if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power))
+ {
+ failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER;
+ continue;
+ }
+ else
+ {
+ failReason = SPELL_CAST_OK;
+ break;
}
}
- if (failReason)
- return failReason;
}
+ if (failReason != SPELL_CAST_OK)
+ return failReason;
}
}
+ // check target item
if(m_targets.getItemTargetGUID())
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
@@ -4705,6 +5201,7 @@ uint8 Spell::CheckItems()
return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
}
+ // check spell focus object
if(m_spellInfo->RequiresSpellFocus)
{
CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
@@ -4712,86 +5209,92 @@ uint8 Spell::CheckItems()
cell.data.Part.reserved = ALL_DISTRICT;
GameObject* ok = NULL;
- Trinity::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus);
- Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck> checker(ok,go_check);
+ MaNGOS::GameObjectFocusCheck go_check(m_caster,m_spellInfo->RequiresSpellFocus);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectFocusCheck> checker(m_caster,ok,go_check);
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
if(!ok)
- return (uint8)SPELL_FAILED_REQUIRES_SPELL_FOCUS;
+ return SPELL_FAILED_REQUIRES_SPELL_FOCUS;
focusObject = ok; // game object found in range
}
- if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP &&
- m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION)))
+ // do not take reagents for these item casts
+ if (!(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST))
{
- for(uint32 i=0;i<8;i++)
+ // check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case.
+ if (!m_IsTriggeredSpell && !p_caster->CanNoReagentCast(m_spellInfo))
{
- if(m_spellInfo->Reagent[i] <= 0)
- continue;
+ for(uint32 i=0;i<8;i++)
+ {
+ if(m_spellInfo->Reagent[i] <= 0)
+ continue;
- itemid = m_spellInfo->Reagent[i];
- itemcount = m_spellInfo->ReagentCount[i];
+ uint32 itemid = m_spellInfo->Reagent[i];
+ uint32 itemcount = m_spellInfo->ReagentCount[i];
- // if CastItem is also spell reagent
- if( m_CastItem && m_CastItem->GetEntry() == itemid )
- {
- ItemPrototype const *proto = m_CastItem->GetProto();
- if(!proto)
- return SPELL_FAILED_ITEM_NOT_READY;
- for(int s=0;s<5;s++)
+ // if CastItem is also spell reagent
+ if( m_CastItem && m_CastItem->GetEntry() == itemid )
{
- // CastItem will be used up and does not count as reagent
- int32 charges = m_CastItem->GetSpellCharges(s);
- if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)
+ ItemPrototype const *proto = m_CastItem->GetProto();
+ if(!proto)
+ return SPELL_FAILED_ITEM_NOT_READY;
+ for(int s=0; s < MAX_ITEM_PROTO_SPELLS; ++s)
{
- ++itemcount;
- break;
+ // CastItem will be used up and does not count as reagent
+ int32 charges = m_CastItem->GetSpellCharges(s);
+ if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)
+ {
+ ++itemcount;
+ break;
+ }
}
}
+ if( !p_caster->HasItemCount(itemid,itemcount) )
+ return SPELL_FAILED_ITEM_NOT_READY; //0x54
}
- if( !p_caster->HasItemCount(itemid,itemcount) )
- return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54
}
- }
- uint32 totems = 2;
- for(int i=0;i<2;++i)
- {
- if(m_spellInfo->Totem[i] != 0)
+ // check totem-item requirements (items presence in inventory)
+ uint32 totems = 2;
+ for(int i=0;i<2;++i)
{
- if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) )
+ if(m_spellInfo->Totem[i] != 0)
{
- totems -= 1;
- continue;
- }
- }else
- totems -= 1;
- }
- if(totems != 0)
- return (uint8)SPELL_FAILED_TOTEMS; //0x7C
+ if( p_caster->HasItemCount(m_spellInfo->Totem[i],1) )
+ {
+ totems -= 1;
+ continue;
+ }
+ }else
+ totems -= 1;
+ }
+ if(totems != 0)
+ return SPELL_FAILED_TOTEMS; //0x7C
- //Check items for TotemCategory
- uint32 TotemCategory = 2;
- for(int i=0;i<2;++i)
- {
- if(m_spellInfo->TotemCategory[i] != 0)
+ // Check items for TotemCategory (items presence in inventory)
+ uint32 TotemCategory = 2;
+ for(int i=0;i<2;++i)
{
- if( p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i]) )
+ if(m_spellInfo->TotemCategory[i] != 0)
{
- TotemCategory -= 1;
- continue;
+ if( p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i]) )
+ {
+ TotemCategory -= 1;
+ continue;
+ }
}
+ else
+ TotemCategory -= 1;
}
- else
- TotemCategory -= 1;
+ if(TotemCategory != 0)
+ return SPELL_FAILED_TOTEM_CATEGORY; //0x7B
}
- if(TotemCategory != 0)
- return (uint8)SPELL_FAILED_TOTEM_CATEGORY; //0x7B
+ // special checks for spell effects
for(int i = 0; i < 3; i++)
{
switch (m_spellInfo->Effect[i])
@@ -4811,6 +5314,24 @@ uint8 Spell::CheckItems()
break;
}
case SPELL_EFFECT_ENCHANT_ITEM:
+ if(m_spellInfo->EffectItemType[i] && m_targets.getItemTarget()
+ && (m_targets.getItemTarget()->IsWeaponVellum() || m_targets.getItemTarget()->IsArmorVellum()))
+ {
+ // cannot enchant vellum for other player
+ if (m_targets.getItemTarget()->GetOwner()!=m_caster)
+ return SPELL_FAILED_NOT_TRADEABLE;
+ // do not allow to enchant vellum from scroll made by vellum-prevent exploit
+ if (m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST)
+ return SPELL_FAILED_TOTEM_CATEGORY;
+ ItemPosCountVec dest;
+ uint8 msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1 );
+ if (msg != EQUIP_ERR_OK )
+ {
+ p_caster->SendEquipError( msg, NULL, NULL );
+ return SPELL_FAILED_DONT_REPORT;
+ }
+ }
+ case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC:
{
Item* targetItem = m_targets.getItemTarget();
if(!targetItem)
@@ -4894,13 +5415,36 @@ uint8 Spell::CheckItems()
return SPELL_FAILED_LOW_CASTLEVEL;
//make sure the player has the required ores in inventory
if(m_targets.getItemTarget()->GetCount() < 5)
- return SPELL_FAILED_PROSPECT_NEED_MORE;
+ return SPELL_FAILED_NEED_MORE_ITEMS;
if(!LootTemplates_Prospecting.HaveLootFor(m_targets.getItemTargetEntry()))
return SPELL_FAILED_CANT_BE_PROSPECTED;
break;
}
+ case SPELL_EFFECT_MILLING:
+ {
+ if(!m_targets.getItemTarget())
+ return SPELL_FAILED_CANT_BE_MILLED;
+ //ensure item is a millable herb
+ if(!(m_targets.getItemTarget()->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS) || m_targets.getItemTarget()->GetProto()->Class != ITEM_CLASS_TRADE_GOODS)
+ return SPELL_FAILED_CANT_BE_MILLED;
+ //prevent milling in trade slot
+ if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() )
+ return SPELL_FAILED_CANT_BE_MILLED;
+ //Check for enough skill in inscription
+ uint32 item_millingskilllevel = m_targets.getItemTarget()->GetProto()->RequiredSkillRank;
+ if(item_millingskilllevel >p_caster->GetSkillValue(SKILL_INSCRIPTION))
+ return SPELL_FAILED_LOW_CASTLEVEL;
+ //make sure the player has the required herbs in inventory
+ if(m_targets.getItemTarget()->GetCount() < 5)
+ return SPELL_FAILED_NEED_MORE_ITEMS;
+
+ if(!LootTemplates_Milling.HaveLootFor(m_targets.getItemTargetEntry()))
+ return SPELL_FAILED_CANT_BE_MILLED;
+
+ break;
+ }
case SPELL_EFFECT_WEAPON_DAMAGE:
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
{
@@ -4969,7 +5513,39 @@ uint8 Spell::CheckItems()
}
}
- return uint8(0);
+ // check weapon presence in slots for main/offhand weapons
+ if(m_spellInfo->EquippedItemClass >=0)
+ {
+ // main hand weapon required
+ if(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
+ {
+ Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
+
+ // skip spell if no weapon in slot or broken
+ if(!item || item->IsBroken() )
+ return m_IsTriggeredSpell? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS;
+
+ // skip spell if weapon not fit to triggered spell
+ if(!item->IsFitToSpellRequirements(m_spellInfo))
+ return m_IsTriggeredSpell? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS;
+ }
+
+ // offhand hand weapon required
+ if(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
+ {
+ Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
+
+ // skip spell if no weapon in slot or broken
+ if(!item || item->IsBroken() )
+ return m_IsTriggeredSpell? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS;
+
+ // skip spell if weapon not fit to triggered spell
+ if(!item->IsFitToSpellRequirements(m_spellInfo))
+ return m_IsTriggeredSpell? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_EQUIPPED_ITEM_CLASS;
+ }
+ }
+
+ return SPELL_CAST_OK;
}
void Spell::Delayed() // only called in DealDamage()
@@ -4980,18 +5556,22 @@ void Spell::Delayed() // only called in DealDamage()
//if (m_spellState == SPELL_STATE_DELAYED)
// return; // spell is active and can't be time-backed
+ if(isDelayableNoMore()) // Spells may only be delayed twice
+ return;
+
// spells not loosing casting time ( slam, dynamites, bombs.. )
//if(!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE))
// return;
- //check resist chance
- int32 resistChance = 100; //must be initialized to 100 for percent modifiers
- ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this);
- resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100;
- if (roll_chance_i(resistChance))
+ //check pushback reduce
+ int32 delaytime = 500; // spellcasting delay is normally 500ms
+ int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
+ ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
+ delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
+ if(delayReduce >= 100)
return;
- int32 delaytime = GetNextDelayAtDamageMsTime();
+ delaytime = delaytime * (100 - delayReduce) / 100;
if(int32(m_timer) + delaytime > m_casttime)
{
@@ -5015,14 +5595,18 @@ void Spell::DelayedChannel()
if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER || getState() != SPELL_STATE_CASTING)
return;
- //check resist chance
- int32 resistChance = 100; //must be initialized to 100 for percent modifiers
- ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,resistChance, this);
- resistChance += m_caster->GetTotalAuraModifier(SPELL_AURA_RESIST_PUSHBACK) - 100;
- if (roll_chance_i(resistChance))
+ if(isDelayableNoMore()) // Spells may only be delayed twice
+ return;
+
+ //check pushback reduce
+ int32 delaytime = GetSpellDuration(m_spellInfo) * 25 / 100; // channeling delay is normally 25% of its time per hit
+ int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
+ ((Player*)m_caster)->ApplySpellMod(m_spellInfo->Id,SPELLMOD_NOT_LOSE_CASTING_TIME,delayReduce, this);
+ delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
+ if(delayReduce >= 100)
return;
- int32 delaytime = GetNextDelayAtDamageMsTime();
+ delaytime = delaytime * (100 - delayReduce) / 100;
if(int32(m_timer) < delaytime)
{
@@ -5041,11 +5625,8 @@ void Spell::DelayedChannel()
Unit* unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
if (unit)
{
- for (int j=0;j<3;j++)
- if( ihit->effectMask & (1<<j) )
- unit->DelayAura(m_spellInfo->Id, j, delaytime);
+ unit->DelayAura(m_spellInfo->Id, m_caster->GetGUID(), delaytime);
}
-
}
}
@@ -5076,17 +5657,12 @@ void Spell::UpdatePointers()
m_targets.Update(m_caster);
}
-bool Spell::IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId)
-{
- return spellmgr.IsAffectedBySpell(m_spellInfo,spellInfo->Id,effectId,spellInfo->EffectItemType[effectId]);
-}
-
bool Spell::CheckTargetCreatureType(Unit* target) const
{
uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType;
// Curse of Doom : not find another way to fix spell target check :/
- if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags == 0x0200000000LL)
+ if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags.IsEqual(0,0x02,0))
{
// not allow cast at player
if(target->GetTypeId()==TYPEID_PLAYER)
@@ -5129,6 +5705,12 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)
return false;
}
+ // Check Aura spell req (need for AoE spells)
+ if(m_spellInfo->targetAuraSpell && !target->HasAura(m_spellInfo->targetAuraSpell))
+ return false;
+ if (m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell))
+ return false;
+
// Check targets for not_selectable unit flag and remove
// A player can cast spells on his pet (or other controlled unit) though in any state
if (target != m_caster && target->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
@@ -5189,7 +5771,13 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)
// all ok by some way or another, skip normal check
break;
default: // normal case
- if(target!=m_caster && !target->IsWithinLOSInMap(m_caster))
+ // Get GO cast coordinates if original caster -> GO
+ WorldObject *caster = NULL;
+ if (IS_GAMEOBJECT_GUID(m_originalCasterGUID))
+ caster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID);
+ if (!caster)
+ caster = m_caster;
+ if(target!=m_caster && !target->IsWithinLOSInMap(caster))
return false;
break;
}
@@ -5197,44 +5785,9 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)
return true;
}
-Unit* Spell::SelectMagnetTarget()
-{
- Unit* target = m_targets.getUnitTarget();
-
- if(target && m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && target->HasAuraType(SPELL_AURA_SPELL_MAGNET)) //Attributes & 0x10 what is this?
- {
- Unit::AuraList const& magnetAuras = target->GetAurasByType(SPELL_AURA_SPELL_MAGNET);
- for(Unit::AuraList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr)
- {
- if(Unit* magnet = (*itr)->GetCaster())
- {
- if((*itr)->m_procCharges>0)
- {
- (*itr)->SetAuraProcCharges((*itr)->m_procCharges-1);
- target = magnet;
- m_targets.setUnitTarget(target);
- AddUnitTarget(target, 0);
- uint64 targetGUID = target->GetGUID();
- for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
- {
- if (targetGUID == ihit->targetGUID) // Found in list
- {
- (*ihit).damage = target->GetHealth();
- break;
- }
- }
- break;
- }
- }
- }
- }
-
- return target;
-}
-
bool Spell::IsNeedSendToClient() const
{
- return m_spellInfo->SpellVisual!=0 || IsChanneledSpell(m_spellInfo) ||
+ return m_spellInfo->SpellVisual[0] || m_spellInfo->SpellVisual[1] || IsChanneledSpell(m_spellInfo) ||
m_spellInfo->speed > 0.0f || !m_triggeredByAuraSpell && !m_IsTriggeredSpell;
}
@@ -5313,9 +5866,6 @@ bool SpellEvent::Execute(uint64 e_time, uint32 p_time)
// another non-melee non-delayed spell is casted now, abort
m_Spell->cancel();
}
- // Check if target of channeled spell still in range
- else if (m_Spell->CheckRange(false))
- m_Spell->cancel();
else
{
// do the action (pass spell to channeling state)
@@ -5418,6 +5968,14 @@ void Spell::CalculateDamageDoneForAllTargets()
}
}
+ bool usesAmmo=true;
+ Unit::AuraEffectList const& Auras = m_caster->GetAurasByType(SPELL_AURA_ABILITY_CONSUME_NO_AMMO);
+ for(Unit::AuraEffectList::const_iterator j = Auras.begin();j != Auras.end(); ++j)
+ {
+ if((*j)->isAffectedOnSpell(m_spellInfo))
+ usesAmmo=false;
+ }
+
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
{
TargetInfo &target = *ihit;
@@ -5427,9 +5985,31 @@ void Spell::CalculateDamageDoneForAllTargets()
continue;
Unit* unit = m_caster->GetGUID()==target.targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target.targetGUID);
- if (!unit)
+ if (!unit) // || !unit->isAlive()) do we need to check alive here?
continue;
+ if (usesAmmo)
+ {
+ bool ammoTaken=false;
+ for (uint8 i=0;i<3;i++)
+ {
+ if (!(mask & 1<<i))
+ continue;
+ switch (m_spellInfo->Effect[i])
+ {
+ case SPELL_EFFECT_SCHOOL_DAMAGE:
+ case SPELL_EFFECT_WEAPON_DAMAGE:
+ case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
+ case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
+ case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
+ ammoTaken=true;
+ TakeAmmo();
+ }
+ if (ammoTaken)
+ break;
+ }
+ }
+
if (target.missCondition==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
target.damage += CalculateDamageDone(unit, mask, multiplier);
else if (target.missCondition == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit)
@@ -5488,6 +6068,68 @@ int32 Spell::CalculateDamageDone(Unit *unit, const uint32 effectMask, float *mul
return damageDone;
}
+SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
+{
+ if(!lockId) // possible case for GO and maybe for items.
+ return SPELL_CAST_OK;
+
+ // Get LockInfo
+ LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
+
+ if (!lockInfo)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ bool reqKey = false; // some locks not have reqs
+
+ for(int j = 0; j < 8; ++j)
+ {
+ switch(lockInfo->Type[j])
+ {
+ // check key item (many fit cases can be)
+ case LOCK_KEY_ITEM:
+ if(lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[j])
+ return SPELL_CAST_OK;
+ reqKey = true;
+ break;
+ // check key skill (only single first fit case can be)
+ case LOCK_KEY_SKILL:
+ {
+ reqKey = true;
+
+ // wrong locktype, skip
+ if(uint32(m_spellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j])
+ continue;
+
+ skillId = SkillByLockType(LockType(lockInfo->Index[j]));
+
+ if ( skillId != SKILL_NONE )
+ {
+ // skill bonus provided by casting spell (mostly item spells)
+ // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value)
+ uint32 spellSkillBonus = uint32(m_currentBasePoints[effIndex]+1);
+ reqSkillValue = lockInfo->Skill[j];
+
+ // castitem check: rogue using skeleton keys. the skill values should not be added in this case.
+ skillValue = m_CastItem || m_caster->GetTypeId()!= TYPEID_PLAYER ?
+ 0 : ((Player*)m_caster)->GetSkillValue(skillId);
+
+ skillValue += spellSkillBonus;
+
+ if (skillValue < reqSkillValue)
+ return SPELL_FAILED_LOW_CASTLEVEL;
+ }
+
+ return SPELL_CAST_OK;
+ }
+ }
+ }
+
+ if(reqKey)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ return SPELL_CAST_OK;
+}
+
void Spell::SetSpellValue(SpellValueMod mod, int32 value)
{
switch(mod)
@@ -5504,6 +6146,9 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value)
m_spellValue->EffectBasePoints[2] = value - int32(m_spellInfo->EffectBaseDice[2]);
m_currentBasePoints[2] = m_spellValue->EffectBasePoints[2];
break;
+ case SPELLVALUE_RADIUS_MOD:
+ m_spellValue->RadiusMod = (float)value / 10000;
+ break;
case SPELLVALUE_MAX_TARGETS:
m_spellValue->MaxAffectedTargets = (uint32)value;
break;
diff --git a/src/game/Spell.h b/src/game/Spell.h
index 94166425675..ef0e3266b4e 100644
--- a/src/game/Spell.h
+++ b/src/game/Spell.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
#define __SPELL_H
#include "GridDefines.h"
+#include "SharedDefines.h"
class Unit;
class Player;
@@ -44,26 +45,51 @@ enum SpellCastTargetFlags
TARGET_FLAG_RESURRECTABLE = 0x8000*/
TARGET_FLAG_SELF = 0x00000000,
+ TARGET_FLAG_UNUSED1 = 0x00000001, // not used in any spells as of 3.0.3 (can be set dynamically)
TARGET_FLAG_UNIT = 0x00000002, // pguid
+ TARGET_FLAG_UNUSED2 = 0x00000004, // not used in any spells as of 3.0.3 (can be set dynamically)
+ TARGET_FLAG_UNUSED3 = 0x00000008, // not used in any spells as of 3.0.3 (can be set dynamically)
TARGET_FLAG_ITEM = 0x00000010, // pguid
TARGET_FLAG_SOURCE_LOCATION = 0x00000020, // 3 float
TARGET_FLAG_DEST_LOCATION = 0x00000040, // 3 float
- TARGET_FLAG_OBJECT_UNK = 0x00000080, // ?
+ TARGET_FLAG_OBJECT_UNK = 0x00000080, // used in 7 spells only
+ TARGET_FLAG_CASTER = 0x00000100, // looks like self target (480 spells)
TARGET_FLAG_PVP_CORPSE = 0x00000200, // pguid
- TARGET_FLAG_OBJECT = 0x00000800, // pguid
- TARGET_FLAG_TRADE_ITEM = 0x00001000, // pguid
- TARGET_FLAG_STRING = 0x00002000, // string
- TARGET_FLAG_UNK1 = 0x00004000, // ?
- TARGET_FLAG_CORPSE = 0x00008000, // pguid
- TARGET_FLAG_UNK2 = 0x00010000 // pguid
+ TARGET_FLAG_UNIT_CORPSE = 0x00000400, // 10 spells (gathering professions)
+ TARGET_FLAG_OBJECT = 0x00000800, // pguid, 2 spells
+ TARGET_FLAG_TRADE_ITEM = 0x00001000, // pguid, 0 spells
+ TARGET_FLAG_STRING = 0x00002000, // string, 0 spells
+ TARGET_FLAG_UNK1 = 0x00004000, // 199 spells, opening object/lock
+ TARGET_FLAG_CORPSE = 0x00008000, // pguid, resurrection spells
+ TARGET_FLAG_UNK2 = 0x00010000, // pguid, not used in any spells as of 3.0.3 (can be set dynamically)
+ TARGET_FLAG_GLYPH = 0x00020000 // used in glyph spells
};
enum SpellCastFlags
{
+ CAST_FLAG_NONE = 0x00000000,
+ CAST_FLAG_UNKNOWN0 = 0x00000001, // may be pending spell cast
CAST_FLAG_UNKNOWN1 = 0x00000002,
+ CAST_FLAG_UNKNOWN11 = 0x00000004,
+ CAST_FLAG_UNKNOWN12 = 0x00000008,
CAST_FLAG_UNKNOWN2 = 0x00000010,
- CAST_FLAG_AMMO = 0x00000020,
- CAST_FLAG_UNKNOWN3 = 0x00000100
+ CAST_FLAG_AMMO = 0x00000020, // Projectiles visual
+ CAST_FLAG_UNKNOWN8 = 0x00000040,
+ CAST_FLAG_UNKNOWN9 = 0x00000080,
+ CAST_FLAG_UNKNOWN3 = 0x00000100,
+ CAST_FLAG_UNKNOWN13 = 0x00000200,
+ CAST_FLAG_UNKNOWN14 = 0x00000400,
+ CAST_FLAG_POWER_LEFT_SELF = 0x00000800, // wotlk
+ CAST_FLAG_UNKNOWN15 = 0x00001000,
+ CAST_FLAG_UNKNOWN16 = 0x00002000,
+ CAST_FLAG_UNKNOWN17 = 0x00004000,
+ CAST_FLAG_UNKNOWN18 = 0x00008000,
+ CAST_FLAG_UNKNOWN19 = 0x00010000,
+ CAST_FLAG_UNKNOWN4 = 0x00020000, // wotlk
+ CAST_FLAG_UNKNOWN10 = 0x00040000,
+ CAST_FLAG_UNKNOWN5 = 0x00080000, // wotlk
+ CAST_FLAG_UNKNOWN20 = 0x00100000,
+ CAST_FLAG_UNKNOWN7 = 0x00200000 // wotlk, rune cooldown list
};
enum SpellRangeFlag
@@ -191,9 +217,11 @@ struct SpellValue
for(uint32 i = 0; i < 3; ++i)
EffectBasePoints[i] = proto->EffectBasePoints[i];
MaxAffectedTargets = proto->MaxAffectedTargets;
+ RadiusMod = 1.0f;
}
int32 EffectBasePoints[3];
uint32 MaxAffectedTargets;
+ float RadiusMod;
};
enum SpellState
@@ -216,6 +244,7 @@ enum ReplenishType
enum SpellTargets
{
+ SPELL_TARGETS_NONE = 0,
SPELL_TARGETS_ALLY,
SPELL_TARGETS_ENEMY,
SPELL_TARGETS_ENTRY,
@@ -244,6 +273,7 @@ class Spell
void EffectHealthLeech(uint32 i);
void EffectQuestComplete(uint32 i);
void EffectCreateItem(uint32 i);
+ void EffectCreateItem2(uint32 i);
void EffectPersistentAA(uint32 i);
void EffectEnergize(uint32 i);
void EffectOpenLock(uint32 i);
@@ -252,16 +282,15 @@ class Spell
void EffectProficiency(uint32 i);
void EffectApplyAreaAura(uint32 i);
void EffectSummonType(uint32 i);
- void EffectSummon(uint32 i);
void EffectLearnSpell(uint32 i);
void EffectDispel(uint32 i);
void EffectDualWield(uint32 i);
void EffectPickPocket(uint32 i);
void EffectAddFarsight(uint32 i);
- void EffectSummonPossessed(uint32 i);
void EffectSummonWild(uint32 i);
- void EffectSummonGuardian(uint32 i);
void EffectHealMechanical(uint32 i);
+ void EffectJump(uint32 i);
+ void EffectJump2(uint32 i);
void EffectTeleUnitsFaceCaster(uint32 i);
void EffectLearnSkill(uint32 i);
void EffectAddHonor(uint32 i);
@@ -286,7 +315,7 @@ class Spell
void EffectStuck(uint32 i);
void EffectSummonPlayer(uint32 i);
void EffectActivateObject(uint32 i);
- void EffectSummonTotem(uint32 i);
+ void EffectApplyGlyph(uint32 i);
void EffectEnchantHeldItem(uint32 i);
void EffectSummonObject(uint32 i);
void EffectResurrect(uint32 i);
@@ -303,6 +332,8 @@ class Spell
void EffectSkinning(uint32 i);
void EffectCharge(uint32 i);
void EffectProspecting(uint32 i);
+ void EffectMilling(uint32 i);
+ void EffectRenamePet(uint32 i);
void EffectSendTaxi(uint32 i);
void EffectSummonCritter(uint32 i);
void EffectKnockBack(uint32 i);
@@ -329,22 +360,30 @@ class Spell
void EffectKillCredit(uint32 i);
void EffectQuestFail(uint32 i);
void EffectRedirectThreat(uint32 i);
+ void EffectWMODamage(uint32 i);
+ void EffectWMORepair(uint32 i);
+ void EffectActivateRune(uint32 i);
+ void EffectTitanGrip(uint32 i);
+ void EffectEnchantItemPrismatic(uint32 i);
Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 originalCasterGUID = 0, Spell** triggeringContainer = NULL, bool skipCheck = false );
~Spell();
- void prepare(SpellCastTargets * targets, Aura* triggeredByAura = NULL);
+ void prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura = NULL);
void cancel();
void update(uint32 difftime);
void cast(bool skipCheck = false);
void finish(bool ok = true);
void TakePower();
+ void TakeAmmo();
+
+ void TakeRunePower();
void TakeReagents();
void TakeCastItem();
void TriggerSpell();
- uint8 CanCast(bool strict);
- int16 PetCanCast(Unit* target);
- bool CanAutoCast(Unit* target);
+
+ SpellCastResult CheckCast(bool strict);
+ SpellCastResult CheckPetCast(Unit* target);
// handlers
void handle_immediate();
@@ -353,10 +392,11 @@ class Spell
void _handle_immediate_phase();
void _handle_finish_phase();
- uint8 CheckItems();
- uint8 CheckRange(bool strict);
- uint8 CheckPower();
- uint8 CheckCasterAuras() const;
+ SpellCastResult CheckItems();
+ SpellCastResult CheckRange(bool strict);
+ SpellCastResult CheckPower();
+ SpellCastResult CheckRuneCost(uint32 runeCostID);
+ SpellCastResult CheckCasterAuras() const;
int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(m_spellInfo,i,m_currentBasePoints[i],target); }
int32 CalculatePowerCost();
@@ -364,24 +404,24 @@ class Spell
bool HaveTargetsForEffect(uint8 effect) const;
void Delayed();
void DelayedChannel();
- inline uint32 getState() const { return m_spellState; }
+ uint32 getState() const { return m_spellState; }
void setState(uint32 state) { m_spellState = state; }
void DoCreateItem(uint32 i, uint32 itemtype);
-
void WriteSpellGoTargets( WorldPacket * data );
void WriteAmmoToPacket( WorldPacket * data );
void FillTargetMap();
void SetTargetMap(uint32 i, uint32 cur);
- Unit* SelectMagnetTarget();
- bool CheckTarget(Unit* target, uint32 eff);
+ template<typename T> WorldObject* FindCorpseUsing();
+ bool CheckTarget( Unit* target, uint32 eff );
+ bool CanAutoCast(Unit* target);
void CheckSrc() { if(!m_targets.HasSrc()) m_targets.setSrc(m_caster); }
void CheckDst() { if(!m_targets.HasDst()) m_targets.setDestination(m_caster); }
- void SendCastResult(uint8 result);
+ void SendCastResult(SpellCastResult result);
void SendSpellStart();
void SendSpellGo();
void SendSpellCooldown();
@@ -392,7 +432,7 @@ class Spell
void SendResurrectRequest(Player* target);
void SendPlaySpellVisual(uint32 SpellID);
- void HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float DamageMultiplier = 1.0);
+ void HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i);
void HandleThreatSpells(uint32 spellId);
//void HandleAddAura(Unit* Target);
@@ -401,6 +441,8 @@ class Spell
Item* m_CastItem;
uint64 m_castItemGUID;
uint8 m_cast_count;
+ uint32 m_glyphIndex;
+ uint32 m_preCastSpell;
SpellCastTargets m_targets;
int32 GetCastTime() const { return m_casttime; }
@@ -409,11 +451,7 @@ class Spell
void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; }
bool IsNextMeleeSwingSpell() const
{
- return m_spellInfo->Attributes & (SPELL_ATTR_ON_NEXT_SWING_1|SPELL_ATTR_ON_NEXT_SWING_2);
- }
- bool IsRangedSpell() const
- {
- return m_spellInfo->Attributes & SPELL_ATTR_RANGED;
+ return m_spellInfo->Attributes & SPELL_ATTR_ON_NEXT_SWING;
}
bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; }
bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); }
@@ -422,7 +460,7 @@ class Spell
bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; }
void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; }
bool IsInterruptable() const { return !m_executedCurrently; }
- void SetExecutedCurrently(bool yes) { m_executedCurrently = yes; }
+ void SetExecutedCurrently(bool yes) {m_executedCurrently = yes;}
uint64 GetDelayStart() const { return m_delayStart; }
void SetDelayStart(uint64 m_time) { m_delayStart = m_time; }
uint64 GetDelayMoment() const { return m_delayMoment; }
@@ -437,8 +475,6 @@ class Spell
void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc)
- bool IsAffectedBy(SpellEntry const *spellInfo, uint32 effectId);
-
bool CheckTargetCreatureType(Unit* target) const;
void AddTriggeredSpell(SpellEntry const* spell) { m_TriggerSpells.push_back(spell); }
@@ -446,6 +482,7 @@ class Spell
void CleanupTargetList();
void SetSpellValue(SpellValueMod mod, int32 value);
+ //void SetSpellValue(SpellValueMod mod, float value);
protected:
void SendLoot(uint64 guid, LootType loottype);
@@ -468,9 +505,17 @@ class Spell
int32 m_casttime; // Calculated spell cast time initialized only in Spell::prepare
bool m_canReflect; // can reflect this spell?
bool m_autoRepeat;
+ uint8 m_runesState;
uint8 m_delayAtDamageCount;
- int32 GetNextDelayAtDamageMsTime() { return m_delayAtDamageCount < 5 ? 1000 - (m_delayAtDamageCount++)* 200 : 200; }
+ bool isDelayableNoMore()
+ {
+ if(m_delayAtDamageCount >= 2)
+ return true;
+
+ m_delayAtDamageCount++;
+ return false;
+ }
// Delayed spells system
uint64 m_delayStart; // time of spell delay start, filled by event handler, zero = just started
@@ -481,6 +526,7 @@ class Spell
bool m_referencedFromCurrentSpell; // mark as references to prevent deleted and access by dead pointers
bool m_executedCurrently; // mark as executed to prevent deleted and access by dead pointers
bool m_needSpellLog; // need to send spell log?
+ bool m_needComboPoints;
uint8 m_applyMultiplierMask; // by effect: damage multiplier needed?
float m_damageMultipliers[3]; // by effect: damage multiplier
@@ -489,6 +535,7 @@ class Spell
Item* itemTarget;
GameObject* gameObjTarget;
int32 damage;
+ Aura * m_spellAura; // only used in DoAllEffectOnTarget
// this is set in Spell Hit, but used in Apply Aura handler
DiminishingLevels m_diminishLevel;
@@ -505,17 +552,16 @@ class Spell
//******************************************
// Spell trigger system
//******************************************
- bool m_canTrigger; // Can start trigger (m_IsTriggeredSpell can`t use for this)
uint32 m_procAttacker; // Attacker trigger flags
uint32 m_procVictim; // Victim trigger flags
- void prepareDataForTriggerSystem();
+ uint32 m_procEx;
+ bool m_canTrigger;
+ void prepareDataForTriggerSystem(AuraEffect * triggeredByAura);
//*****************************************
// Spell target subsystem
//*****************************************
// Targets store structures and data
- uint32 m_countOfHit;
- uint32 m_countOfMiss;
struct TargetInfo
{
uint64 targetGUID;
@@ -524,6 +570,7 @@ class Spell
SpellMissInfo reflectResult:8;
uint8 effectMask:8;
bool processed:1;
+ bool alive:1;
int32 damage;
};
std::list<TargetInfo> m_UniqueTargetInfo;
@@ -551,11 +598,12 @@ class Spell
void AddGOTarget(uint64 goGUID, uint32 effIndex);
void AddItemTarget(Item* target, uint32 effIndex);
void DoAllEffectOnTarget(TargetInfo *target);
- void DoSpellHitOnUnit(Unit *unit, uint32 effectMask);
+ SpellMissInfo DoSpellHitOnUnit(Unit *unit, uint32 effectMask);
+ void DoTriggersOnSpellHit(Unit *unit);
void DoAllEffectOnTarget(GOTargetInfo *target);
void DoAllEffectOnTarget(ItemTargetInfo *target);
- bool IsAliveUnitPresentInTargetList();
- void SearchAreaTarget(std::list<Unit*> &unitList, float radius, const uint32 type, SpellTargets TargetType, uint32 entry = 0);
+ bool UpdateChanneledTargetList();
+ void SearchAreaTarget(std::list<Unit*> &unitList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0);
void SearchChainTarget(std::list<Unit*> &unitList, float radius, uint32 unMaxTargets, SpellTargets TargetType);
WorldObject* SearchNearbyTarget(float range, SpellTargets TargetType);
bool IsValidSingleTargetEffect(Unit const* target, Targets type) const;
@@ -565,6 +613,11 @@ class Spell
void SpellDamageSchoolDmg(uint32 i);
void SpellDamageWeaponDmg(uint32 i);
void SpellDamageHeal(uint32 i);
+
+ void GetSummonPosition(uint32 i, float &x, float &y, float &z, float radius = 0.0f, uint32 count = 0);
+ void SummonGuardian (uint32 entry, SummonPropertiesEntry const *properties);
+
+ SpellCastResult CanOpenLock(uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
// -------------------------------------------
//List For Triggered Spells
@@ -589,6 +642,7 @@ class Spell
uint32 m_customAttr;
bool m_skipCheck;
+ uint32 m_effectMask;
};
namespace Trinity
@@ -597,84 +651,84 @@ namespace Trinity
{
std::list<Unit*> *i_data;
Spell &i_spell;
- const uint32& i_push_type;
+ SpellNotifyPushType i_push_type;
float i_radius, i_radiusSq;
SpellTargets i_TargetType;
- Unit* i_caster;
+ Unit* i_source;
uint32 i_entry;
float i_x, i_y, i_z;
- SpellNotifierCreatureAndPlayer(Spell &spell, std::list<Unit*> &data, float radius, const uint32 &type,
+ SpellNotifierCreatureAndPlayer(Spell &spell, std::list<Unit*> &data, float radius, SpellNotifyPushType type,
SpellTargets TargetType = SPELL_TARGETS_ENEMY, uint32 entry = 0, float x = 0, float y = 0, float z = 0)
: i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_radiusSq(radius*radius)
, i_TargetType(TargetType), i_entry(entry), i_x(x), i_y(y), i_z(z)
{
- i_caster = spell.GetCaster();
+ i_source = spell.GetCaster();
+ assert(i_source);
}
template<class T> inline void Visit(GridRefManager<T> &m)
{
- assert(i_data);
-
- if(!i_caster)
- return;
-
for(typename GridRefManager<T>::iterator itr = m.begin(); itr != m.end(); ++itr)
{
- if( !itr->getSource()->isAlive() || (itr->getSource()->GetTypeId() == TYPEID_PLAYER && ((Player*)itr->getSource())->isInFlight()))
+ Unit *target = (Unit*)itr->getSource();
+
+ // mostly phase check
+ if(!itr->getSource()->IsInMap(i_source))
continue;
switch (i_TargetType)
{
- case SPELL_TARGETS_ALLY:
- if (!itr->getSource()->isAttackableByAOE() || !i_caster->IsFriendlyTo( itr->getSource() ))
- continue;
- break;
case SPELL_TARGETS_ENEMY:
- {
- if(itr->getSource()->GetTypeId()==TYPEID_UNIT && ((Creature*)itr->getSource())->isTotem())
+ if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isTotem())
continue;
- if(!itr->getSource()->isAttackableByAOE())
+ if(!target->isAttackableByAOE())
continue;
-
- Unit* check = i_caster->GetCharmerOrOwnerOrSelf();
-
- if( check->GetTypeId()==TYPEID_PLAYER )
+ if(i_source->IsControlledByPlayer())
{
- if (check->IsFriendlyTo( itr->getSource() ))
+ if(i_source->IsFriendlyTo(target))
continue;
}
else
{
- if (!check->IsHostileTo( itr->getSource() ))
+ if(!i_source->IsHostileTo(target))
continue;
}
- }break;
+ break;
+ case SPELL_TARGETS_ALLY:
+ if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isTotem())
+ continue;
+ if(!target->isAttackableByAOE() || !i_source->IsFriendlyTo(target))
+ continue;
+ break;
case SPELL_TARGETS_ENTRY:
- {
- if(itr->getSource()->GetEntry()!= i_entry)
+ if(target->GetEntry()!= i_entry)
continue;
- }break;
- default: continue;
+ break;
+ default:
+ continue;
}
switch(i_push_type)
{
+ case PUSH_SRC_CENTER:
+ case PUSH_DST_CENTER:
+ case PUSH_CHAIN:
+ default:
+ if((target->GetDistanceSq(i_x, i_y, i_z) < i_radiusSq))
+ i_data->push_back(target);
+ break;
case PUSH_IN_FRONT:
- if(i_caster->isInFront((Unit*)(itr->getSource()), i_radius, M_PI/3 ))
- i_data->push_back(itr->getSource());
+ if(i_source->isInFrontInMap(target, i_radius, M_PI/3))
+ i_data->push_back(target);
break;
case PUSH_IN_BACK:
- if(i_caster->isInBack((Unit*)(itr->getSource()), i_radius, M_PI/3 ))
- i_data->push_back(itr->getSource());
+ if(i_source->isInBackInMap(target, i_radius, M_PI/3))
+ i_data->push_back(target);
break;
case PUSH_IN_LINE:
- if(i_caster->isInLine((Unit*)(itr->getSource()), i_radius ))
- i_data->push_back(itr->getSource());
- break;
- default:
- if((itr->getSource()->GetDistanceSq(i_x, i_y, i_z) < i_radiusSq))
- i_data->push_back(itr->getSource());
+ if(i_source->isInLine(target, i_radius))
+ i_data->push_back(target);
break;
}
}
diff --git a/src/game/SpellAuraDefines.h b/src/game/SpellAuraDefines.h
index d8a9d73cf46..494bdc68a88 100644
--- a/src/game/SpellAuraDefines.h
+++ b/src/game/SpellAuraDefines.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,14 +20,20 @@
#ifndef TRINITY_SPELLAURADEFINES_H
#define TRINITY_SPELLAURADEFINES_H
-#define MAX_AURAS 56
-#define MAX_POSITIVE_AURAS 40
+#define MAX_AURAS 64 // client support up to 255, but it will cause problems with group auras updating
+#define FRIENDLY_AA_REMOVE_TIME 2*IN_MILISECONDS
enum AURA_FLAGS
{
- AFLAG_NEGATIVE = 0x09,
- AFLAG_POSITIVE = 0x1F,
- AFLAG_MASK = 0xFF
+ AFLAG_NONE = 0x00,
+ AFLAG_EFF_INDEX_0 = 0x01,
+ AFLAG_EFF_INDEX_1 = 0x02,
+ AFLAG_EFF_INDEX_2 = 0x04,
+ AFLAG_CASTER = 0x08,
+ AFLAG_POSITIVE = 0x10,
+ AFLAG_DURATION = 0x20,
+ AFLAG_UNK2 = 0x40,
+ AFLAG_NEGATIVE = 0x80
};
//m_schoolAbsorb
@@ -60,7 +66,7 @@ enum AuraType
SPELL_AURA_MOD_INVISIBILITY = 18,
SPELL_AURA_MOD_INVISIBILITY_DETECTION = 19,
SPELL_AURA_OBS_MOD_HEALTH = 20, //20,21 unofficial
- SPELL_AURA_OBS_MOD_MANA = 21,
+ SPELL_AURA_OBS_MOD_ENERGY = 21,
SPELL_AURA_MOD_RESISTANCE = 22,
SPELL_AURA_PERIODIC_TRIGGER_SPELL = 23,
SPELL_AURA_PERIODIC_ENERGIZE = 24,
@@ -85,11 +91,11 @@ enum AuraType
SPELL_AURA_PROC_TRIGGER_DAMAGE = 43,
SPELL_AURA_TRACK_CREATURES = 44,
SPELL_AURA_TRACK_RESOURCES = 45,
- SPELL_AURA_MOD_PARRY_SKILL = 46,
+ SPELL_AURA_46 = 46, // Ignore all Gear test spells
SPELL_AURA_MOD_PARRY_PERCENT = 47,
- SPELL_AURA_MOD_DODGE_SKILL = 48,
+ SPELL_AURA_48 = 48, // One periodic spell
SPELL_AURA_MOD_DODGE_PERCENT = 49,
- SPELL_AURA_MOD_BLOCK_SKILL = 50,
+ SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT = 50,
SPELL_AURA_MOD_BLOCK_PERCENT = 51,
SPELL_AURA_MOD_CRIT_PERCENT = 52,
SPELL_AURA_PERIODIC_LEECH = 53,
@@ -102,9 +108,9 @@ enum AuraType
SPELL_AURA_MOD_PACIFY_SILENCE = 60,
SPELL_AURA_MOD_SCALE = 61,
SPELL_AURA_PERIODIC_HEALTH_FUNNEL = 62,
- SPELL_AURA_PERIODIC_MANA_FUNNEL = 63,
+ SPELL_AURA_63 = 63, // old SPELL_AURA_PERIODIC_MANA_FUNNEL
SPELL_AURA_PERIODIC_MANA_LEECH = 64,
- SPELL_AURA_MOD_CASTING_SPEED = 65,
+ SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK = 65,
SPELL_AURA_FEIGN_DEATH = 66,
SPELL_AURA_MOD_DISARM = 67,
SPELL_AURA_MOD_STALKED = 68,
@@ -129,7 +135,7 @@ enum AuraType
SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN = 87,
SPELL_AURA_MOD_HEALTH_REGEN_PERCENT = 88,
SPELL_AURA_PERIODIC_DAMAGE_PERCENT = 89,
- SPELL_AURA_MOD_RESIST_CHANCE = 90,
+ SPELL_AURA_90 = 90, // old SPELL_AURA_MOD_RESIST_CHANCE
SPELL_AURA_MOD_DETECT_RANGE = 91,
SPELL_AURA_PREVENTS_FLEEING = 92,
SPELL_AURA_MOD_UNATTACKABLE = 93,
@@ -158,7 +164,7 @@ enum AuraType
SPELL_AURA_MOD_REGEN_DURING_COMBAT = 116,
SPELL_AURA_MOD_MECHANIC_RESISTANCE = 117,
SPELL_AURA_MOD_HEALING_PCT = 118,
- SPELL_AURA_SHARE_PET_TRACKING = 119,
+ SPELL_AURA_119 = 119, // old SPELL_AURA_SHARE_PET_TRACKING
SPELL_AURA_UNTRACKABLE = 120,
SPELL_AURA_EMPATHY = 121,
SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT = 122,
@@ -184,11 +190,11 @@ enum AuraType
SPELL_AURA_MOD_BASE_RESISTANCE_PCT = 142,
SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE = 143,
SPELL_AURA_SAFE_FALL = 144,
- SPELL_AURA_CHARISMA = 145,
- SPELL_AURA_PERSUADED = 146,
- SPELL_AURA_ADD_CREATURE_IMMUNITY = 147,
+ SPELL_AURA_MOD_PET_TALENT_POINTS = 145,
+ SPELL_AURA_ALLOW_TAME_PET_TYPE = 146,
+ SPELL_AURA_MECHANIC_IMMUNITY_MASK = 147,
SPELL_AURA_RETAIN_COMBO_POINTS = 148,
- SPELL_AURA_RESIST_PUSHBACK = 149, // Resist Pushback
+ SPELL_AURA_REDUCE_PUSHBACK = 149, // Reduce Pushback
SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT = 150,
SPELL_AURA_TRACK_STEALTHED = 151, // Track Stealthed
SPELL_AURA_MOD_DETECTED_RANGE = 152, // Mod Detected Range
@@ -212,15 +218,15 @@ enum AuraType
SPELL_AURA_DETECT_AMORE = 170,
SPELL_AURA_MOD_SPEED_NOT_STACK = 171,
SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK = 172,
- SPELL_AURA_ALLOW_CHAMPION_SPELLS = 173,
- SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT = 174, // by default intellect, dependent from SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
+ SPELL_AURA_173 = 173, // old SPELL_AURA_ALLOW_CHAMPION_SPELLS
+ SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT = 174, // by defeult intelect, dependent from SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT = 175,
SPELL_AURA_SPIRIT_OF_REDEMPTION = 176,
SPELL_AURA_AOE_CHARM = 177,
SPELL_AURA_MOD_DEBUFF_RESISTANCE = 178,
SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE = 179,
SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS = 180,
- SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS = 181, // unused - possible flat spell crit damage versus
+ SPELL_AURA_181 = 181, // old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS - possible flat spell crit damage versus
SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT = 182,
SPELL_AURA_MOD_CRITICAL_THREAT = 183,
SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE = 184,
@@ -233,23 +239,23 @@ enum AuraType
SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED = 191,
SPELL_AURA_HASTE_MELEE = 192,
SPELL_AURA_MELEE_SLOW = 193,
- SPELL_AURA_MOD_DEPRICATED_1 = 194, // not used now, old SPELL_AURA_MOD_SPELL_DAMAGE_OF_INTELLECT
- SPELL_AURA_MOD_DEPRICATED_2 = 195, // not used now, old SPELL_AURA_MOD_SPELL_HEALING_OF_INTELLECT
+ SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL = 194,
+ SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL = 195,
SPELL_AURA_MOD_COOLDOWN = 196, // only 24818 Noxious Breath
SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE = 197,
- SPELL_AURA_MOD_ALL_WEAPON_SKILLS = 198,
+ SPELL_AURA_198 = 198, // old SPELL_AURA_MOD_ALL_WEAPON_SKILLS
SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT = 199,
SPELL_AURA_MOD_XP_PCT = 200,
SPELL_AURA_FLY = 201,
SPELL_AURA_IGNORE_COMBAT_RESULT = 202,
SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE = 203,
SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE = 204,
- SPELL_AURA_205 = 205, // unused
- SPELL_AURA_MOD_SPEED_MOUNTED = 206, // ? used in strange spells
- SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED = 207,
- SPELL_AURA_MOD_SPEED_FLIGHT = 208,
- SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS = 209,
- SPELL_AURA_210 = 210, // unused
+ SPELL_AURA_205 = 205, // school vunderability?
+ SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED = 206,
+ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED = 207,
+ SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED = 208,
+ SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS = 209,
+ SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS = 210,
SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK = 211,
SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT = 212,
SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT = 213,
@@ -262,20 +268,20 @@ enum AuraType
SPELL_AURA_MOD_RATING_FROM_STAT = 220,
SPELL_AURA_221 = 221,
SPELL_AURA_222 = 222,
- SPELL_AURA_223 = 223,
+ SPELL_AURA_RAID_PROC_FROM_CHARGE = 223,
SPELL_AURA_224 = 224,
- SPELL_AURA_PRAYER_OF_MENDING = 225,
+ SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE = 225,
SPELL_AURA_PERIODIC_DUMMY = 226,
- SPELL_AURA_227 = 227,
+ SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE = 227,
SPELL_AURA_DETECT_STEALTH = 228,
SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE = 229,
SPELL_AURA_230 = 230,
- SPELL_AURA_231 = 231,
+ SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE = 231,
SPELL_AURA_MECHANIC_DURATION_MOD = 232,
SPELL_AURA_233 = 233,
SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK = 234,
SPELL_AURA_MOD_DISPEL_RESIST = 235,
- SPELL_AURA_236 = 236,
+ SPELL_AURA_CONTROL_VEHICLE = 236,
SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER = 237,
SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER = 238,
SPELL_AURA_MOD_SCALE_2 = 239,
@@ -284,29 +290,57 @@ enum AuraType
SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING = 242,
SPELL_AURA_243 = 243,
SPELL_AURA_COMPREHEND_LANGUAGE = 244,
- SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS = 245,
- SPELL_AURA_246 = 246,
+ SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL = 245,
+ SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK = 246,
SPELL_AURA_247 = 247,
SPELL_AURA_MOD_COMBAT_RESULT_CHANCE = 248,
- SPELL_AURA_249 = 249,
+ SPELL_AURA_CONVERT_RUNE = 249,
SPELL_AURA_MOD_INCREASE_HEALTH_2 = 250,
SPELL_AURA_MOD_ENEMY_DODGE = 251,
SPELL_AURA_252 = 252,
- SPELL_AURA_253 = 253,
- SPELL_AURA_254 = 254,
- SPELL_AURA_255 = 255,
- SPELL_AURA_256 = 256,
- SPELL_AURA_257 = 257,
+ SPELL_AURA_MOD_BLOCK_CRIT_CHANCE = 253,
+ SPELL_AURA_MOD_DISARM_OFFHAND = 254,
+ SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT = 255,
+ SPELL_AURA_NO_REAGENT_USE = 256,
+ SPELL_AURA_MOD_TARGET_RESIST_BY_SPELL_CLASS = 257,
SPELL_AURA_258 = 258,
- SPELL_AURA_259 = 259,
- SPELL_AURA_260 = 260,
- SPELL_AURA_261 = 261,
- TOTAL_AURAS=262
+ SPELL_AURA_MOD_HOT_PCT = 259,
+ SPELL_AURA_SCREEN_EFFECT = 260,
+ SPELL_AURA_PHASE = 261,
+ SPELL_AURA_ABILITY_IGNORE_AURASTATE = 262,
+ SPELL_AURA_ALLOW_ONLY_ABILITY = 263,
+ SPELL_AURA_264 = 264,
+ SPELL_AURA_265 = 265,
+ SPELL_AURA_266 = 266,
+ SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL = 267,
+ SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT = 268,
+ SPELL_AURA_MOD_IGNORE_TARGET_RESIST = 269,
+ SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST = 270, // Possibly need swap vs 195 aura used only in 1 spell Chaos Bolt Passive
+ SPELL_AURA_MOD_DAMAGE_FROM_CASTER = 271,
+ SPELL_AURA_272 = 272,
+ SPELL_AURA_273 = 273,
+ SPELL_AURA_ABILITY_CONSUME_NO_AMMO = 274,
+ SPELL_AURA_MOD_IGNORE_SHAPESHIFT = 275,
+ SPELL_AURA_276 = 276, // Only "Test Mod Damage % Mechanic" spell, possible mod damage done
+ SPELL_AURA_MOD_MAX_AFFECTED_TARGETS = 277,
+ SPELL_AURA_MOD_DISARM_RANGED = 278,
+ SPELL_AURA_279 = 279,
+ SPELL_AURA_MOD_WEAPONTYPE_IGNORE_TARGET_RESISTANCE = 280,
+ SPELL_AURA_MOD_HONOR_GAIN_PCT = 281,
+ SPELL_AURA_MOD_BASE_HEALTH_PCT = 282,
+ SPELL_AURA_MOD_HEALING_RECEIVED = 283, // Possibly only for some spell family class spells
+ SPELL_AURA_284,
+ SPELL_AURA_285,
+ SPELL_AURA_286,
+ SPELL_AURA_DEFLECT_SPELLS,
+ SPELL_AURA_288,
+ TOTAL_AURAS = 289
};
enum AreaAuraType
{
AREA_AURA_PARTY,
+ AREA_AURA_RAID,
AREA_AURA_FRIEND,
AREA_AURA_ENEMY,
AREA_AURA_PET,
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index a775ccdd3f8..e66c33ea49b 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,11 +31,9 @@
#include "Player.h"
#include "Unit.h"
#include "Spell.h"
-#include "SpellAuras.h"
#include "DynamicObject.h"
#include "Group.h"
#include "UpdateData.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Policies/SingletonImp.h"
#include "Totem.h"
@@ -45,425 +43,518 @@
#include "OutdoorPvP.h"
#include "OutdoorPvPMgr.h"
#include "CreatureAI.h"
+#include "ScriptCalls.h"
#include "Util.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
+#include "Vehicle.h"
#include "CellImpl.h"
-#define NULL_AURA_SLOT 0xFF
-
pAuraHandler AuraHandler[TOTAL_AURAS]=
{
- &Aura::HandleNULL, // 0 SPELL_AURA_NONE
- &Aura::HandleBindSight, // 1 SPELL_AURA_BIND_SIGHT
- &Aura::HandleModPossess, // 2 SPELL_AURA_MOD_POSSESS
- &Aura::HandlePeriodicDamage, // 3 SPELL_AURA_PERIODIC_DAMAGE
- &Aura::HandleAuraDummy, // 4 SPELL_AURA_DUMMY
- &Aura::HandleModConfuse, // 5 SPELL_AURA_MOD_CONFUSE
- &Aura::HandleModCharm, // 6 SPELL_AURA_MOD_CHARM
- &Aura::HandleModFear, // 7 SPELL_AURA_MOD_FEAR
- &Aura::HandlePeriodicHeal, // 8 SPELL_AURA_PERIODIC_HEAL
- &Aura::HandleModAttackSpeed, // 9 SPELL_AURA_MOD_ATTACKSPEED
- &Aura::HandleModThreat, // 10 SPELL_AURA_MOD_THREAT
- &Aura::HandleModTaunt, // 11 SPELL_AURA_MOD_TAUNT
- &Aura::HandleAuraModStun, // 12 SPELL_AURA_MOD_STUN
- &Aura::HandleModDamageDone, // 13 SPELL_AURA_MOD_DAMAGE_DONE
- &Aura::HandleNoImmediateEffect, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
- &Aura::HandleNoImmediateEffect, // 15 SPELL_AURA_DAMAGE_SHIELD implemented in Unit::DoAttackDamage
- &Aura::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH
- &Aura::HandleNoImmediateEffect, // 17 SPELL_AURA_MOD_STEALTH_DETECT
- &Aura::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY
- &Aura::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION
- &Aura::HandleAuraModTotalHealthPercentRegen, // 20 SPELL_AURA_OBS_MOD_HEALTH
- &Aura::HandleAuraModTotalManaPercentRegen, // 21 SPELL_AURA_OBS_MOD_MANA
- &Aura::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE
- &Aura::HandlePeriodicTriggerSpell, // 23 SPELL_AURA_PERIODIC_TRIGGER_SPELL
- &Aura::HandlePeriodicEnergize, // 24 SPELL_AURA_PERIODIC_ENERGIZE
- &Aura::HandleAuraModPacify, // 25 SPELL_AURA_MOD_PACIFY
- &Aura::HandleAuraModRoot, // 26 SPELL_AURA_MOD_ROOT
- &Aura::HandleAuraModSilence, // 27 SPELL_AURA_MOD_SILENCE
- &Aura::HandleNoImmediateEffect, // 28 SPELL_AURA_REFLECT_SPELLS implement in Unit::SpellHitResult
- &Aura::HandleAuraModStat, // 29 SPELL_AURA_MOD_STAT
- &Aura::HandleAuraModSkill, // 30 SPELL_AURA_MOD_SKILL
- &Aura::HandleAuraModIncreaseSpeed, // 31 SPELL_AURA_MOD_INCREASE_SPEED
- &Aura::HandleAuraModIncreaseMountedSpeed, // 32 SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
- &Aura::HandleAuraModDecreaseSpeed, // 33 SPELL_AURA_MOD_DECREASE_SPEED
- &Aura::HandleAuraModIncreaseHealth, // 34 SPELL_AURA_MOD_INCREASE_HEALTH
- &Aura::HandleAuraModIncreaseEnergy, // 35 SPELL_AURA_MOD_INCREASE_ENERGY
- &Aura::HandleAuraModShapeshift, // 36 SPELL_AURA_MOD_SHAPESHIFT
- &Aura::HandleAuraModEffectImmunity, // 37 SPELL_AURA_EFFECT_IMMUNITY
- &Aura::HandleAuraModStateImmunity, // 38 SPELL_AURA_STATE_IMMUNITY
- &Aura::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY
- &Aura::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY
- &Aura::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY
- &Aura::HandleAuraProcTriggerSpell, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell
- &Aura::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor
- &Aura::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES
- &Aura::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES
- &Aura::HandleUnused, // 46 SPELL_AURA_MOD_PARRY_SKILL obsolete?
- &Aura::HandleAuraModParryPercent, // 47 SPELL_AURA_MOD_PARRY_PERCENT
- &Aura::HandleUnused, // 48 SPELL_AURA_MOD_DODGE_SKILL obsolete?
- &Aura::HandleAuraModDodgePercent, // 49 SPELL_AURA_MOD_DODGE_PERCENT
- &Aura::HandleUnused, // 50 SPELL_AURA_MOD_BLOCK_SKILL obsolete?
- &Aura::HandleAuraModBlockPercent, // 51 SPELL_AURA_MOD_BLOCK_PERCENT
- &Aura::HandleAuraModCritPercent, // 52 SPELL_AURA_MOD_CRIT_PERCENT
- &Aura::HandlePeriodicLeech, // 53 SPELL_AURA_PERIODIC_LEECH
- &Aura::HandleModHitChance, // 54 SPELL_AURA_MOD_HIT_CHANCE
- &Aura::HandleModSpellHitChance, // 55 SPELL_AURA_MOD_SPELL_HIT_CHANCE
- &Aura::HandleAuraTransform, // 56 SPELL_AURA_TRANSFORM
- &Aura::HandleModSpellCritChance, // 57 SPELL_AURA_MOD_SPELL_CRIT_CHANCE
- &Aura::HandleAuraModIncreaseSwimSpeed, // 58 SPELL_AURA_MOD_INCREASE_SWIM_SPEED
- &Aura::HandleNoImmediateEffect, // 59 SPELL_AURA_MOD_DAMAGE_DONE_CREATURE implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
- &Aura::HandleAuraModPacifyAndSilence, // 60 SPELL_AURA_MOD_PACIFY_SILENCE
- &Aura::HandleAuraModScale, // 61 SPELL_AURA_MOD_SCALE
- &Aura::HandleNULL, // 62 SPELL_AURA_PERIODIC_HEALTH_FUNNEL
- &Aura::HandleUnused, // 63 SPELL_AURA_PERIODIC_MANA_FUNNEL obsolete?
- &Aura::HandlePeriodicManaLeech, // 64 SPELL_AURA_PERIODIC_MANA_LEECH
- &Aura::HandleModCastingSpeed, // 65 SPELL_AURA_MOD_CASTING_SPEED
- &Aura::HandleFeignDeath, // 66 SPELL_AURA_FEIGN_DEATH
- &Aura::HandleAuraModDisarm, // 67 SPELL_AURA_MOD_DISARM
- &Aura::HandleAuraModStalked, // 68 SPELL_AURA_MOD_STALKED
- &Aura::HandleSchoolAbsorb, // 69 SPELL_AURA_SCHOOL_ABSORB implemented in Unit::CalcAbsorbResist
- &Aura::HandleUnused, // 70 SPELL_AURA_EXTRA_ATTACKS Useless, used by only one spell that has only visual effect
- &Aura::HandleModSpellCritChanceShool, // 71 SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
- &Aura::HandleModPowerCostPCT, // 72 SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT
- &Aura::HandleModPowerCost, // 73 SPELL_AURA_MOD_POWER_COST_SCHOOL
- &Aura::HandleNoImmediateEffect, // 74 SPELL_AURA_REFLECT_SPELLS_SCHOOL implemented in Unit::SpellHitResult
- &Aura::HandleNoImmediateEffect, // 75 SPELL_AURA_MOD_LANGUAGE
- &Aura::HandleFarSight, // 76 SPELL_AURA_FAR_SIGHT
- &Aura::HandleModMechanicImmunity, // 77 SPELL_AURA_MECHANIC_IMMUNITY
- &Aura::HandleAuraMounted, // 78 SPELL_AURA_MOUNTED
- &Aura::HandleModDamagePercentDone, // 79 SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
- &Aura::HandleModPercentStat, // 80 SPELL_AURA_MOD_PERCENT_STAT
- &Aura::HandleNoImmediateEffect, // 81 SPELL_AURA_SPLIT_DAMAGE_PCT
- &Aura::HandleWaterBreathing, // 82 SPELL_AURA_WATER_BREATHING
- &Aura::HandleModBaseResistance, // 83 SPELL_AURA_MOD_BASE_RESISTANCE
- &Aura::HandleModRegen, // 84 SPELL_AURA_MOD_REGEN
- &Aura::HandleModPowerRegen, // 85 SPELL_AURA_MOD_POWER_REGEN
- &Aura::HandleChannelDeathItem, // 86 SPELL_AURA_CHANNEL_DEATH_ITEM
- &Aura::HandleNoImmediateEffect, // 87 SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
- &Aura::HandleNoImmediateEffect, // 88 SPELL_AURA_MOD_HEALTH_REGEN_PERCENT
- &Aura::HandlePeriodicDamagePCT, // 89 SPELL_AURA_PERIODIC_DAMAGE_PERCENT
- &Aura::HandleUnused, // 90 SPELL_AURA_MOD_RESIST_CHANCE Useless
- &Aura::HandleNoImmediateEffect, // 91 SPELL_AURA_MOD_DETECT_RANGE implemented in Creature::GetAttackDistance
- &Aura::HandlePreventFleeing, // 92 SPELL_AURA_PREVENTS_FLEEING
- &Aura::HandleModUnattackable, // 93 SPELL_AURA_MOD_UNATTACKABLE
- &Aura::HandleNoImmediateEffect, // 94 SPELL_AURA_INTERRUPT_REGEN implemented in Player::RegenerateAll
- &Aura::HandleAuraGhost, // 95 SPELL_AURA_GHOST
- &Aura::HandleNoImmediateEffect, // 96 SPELL_AURA_SPELL_MAGNET implemented in Spell::SelectMagnetTarget
- &Aura::HandleManaShield, // 97 SPELL_AURA_MANA_SHIELD implemented in Unit::CalcAbsorbResist
- &Aura::HandleAuraModSkill, // 98 SPELL_AURA_MOD_SKILL_TALENT
- &Aura::HandleAuraModAttackPower, // 99 SPELL_AURA_MOD_ATTACK_POWER
- &Aura::HandleUnused, //100 SPELL_AURA_AURAS_VISIBLE obsolete? all player can see all auras now
- &Aura::HandleModResistancePercent, //101 SPELL_AURA_MOD_RESISTANCE_PCT
- &Aura::HandleNoImmediateEffect, //102 SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus
- &Aura::HandleAuraModTotalThreat, //103 SPELL_AURA_MOD_TOTAL_THREAT
- &Aura::HandleAuraWaterWalk, //104 SPELL_AURA_WATER_WALK
- &Aura::HandleAuraFeatherFall, //105 SPELL_AURA_FEATHER_FALL
- &Aura::HandleAuraHover, //106 SPELL_AURA_HOVER
- &Aura::HandleAddModifier, //107 SPELL_AURA_ADD_FLAT_MODIFIER
- &Aura::HandleAddModifier, //108 SPELL_AURA_ADD_PCT_MODIFIER
- &Aura::HandleNoImmediateEffect, //109 SPELL_AURA_ADD_TARGET_TRIGGER
- &Aura::HandleModPowerRegenPCT, //110 SPELL_AURA_MOD_POWER_REGEN_PERCENT
- &Aura::HandleNULL, //111 SPELL_AURA_ADD_CASTER_HIT_TRIGGER
- &Aura::HandleNoImmediateEffect, //112 SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
- &Aura::HandleNoImmediateEffect, //113 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //114 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //115 SPELL_AURA_MOD_HEALING implemented in Unit::SpellBaseHealingBonusForVictim
- &Aura::HandleNoImmediateEffect, //116 SPELL_AURA_MOD_REGEN_DURING_COMBAT
- &Aura::HandleNoImmediateEffect, //117 SPELL_AURA_MOD_MECHANIC_RESISTANCE implemented in Unit::MagicSpellHitResult
- &Aura::HandleNoImmediateEffect, //118 SPELL_AURA_MOD_HEALING_PCT implemented in Unit::SpellHealingBonus
- &Aura::HandleUnused, //119 SPELL_AURA_SHARE_PET_TRACKING useless
- &Aura::HandleAuraUntrackable, //120 SPELL_AURA_UNTRACKABLE
- &Aura::HandleAuraEmpathy, //121 SPELL_AURA_EMPATHY
- &Aura::HandleModOffhandDamagePercent, //122 SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT
- &Aura::HandleModTargetResistance, //123 SPELL_AURA_MOD_TARGET_RESISTANCE
- &Aura::HandleAuraModRangedAttackPower, //124 SPELL_AURA_MOD_RANGED_ATTACK_POWER
- &Aura::HandleNoImmediateEffect, //125 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //126 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //127 SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
- &Aura::HandleModPossessPet, //128 SPELL_AURA_MOD_POSSESS_PET
- &Aura::HandleAuraModIncreaseSpeed, //129 SPELL_AURA_MOD_SPEED_ALWAYS
- &Aura::HandleAuraModIncreaseMountedSpeed, //130 SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
- &Aura::HandleNoImmediateEffect, //131 SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus
- &Aura::HandleAuraModIncreaseEnergyPercent, //132 SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT
- &Aura::HandleAuraModIncreaseHealthPercent, //133 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT
- &Aura::HandleAuraModRegenInterrupt, //134 SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
- &Aura::HandleModHealingDone, //135 SPELL_AURA_MOD_HEALING_DONE
- &Aura::HandleNoImmediateEffect, //136 SPELL_AURA_MOD_HEALING_DONE_PERCENT implemented in Unit::SpellHealingBonus
- &Aura::HandleModTotalPercentStat, //137 SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
- &Aura::HandleHaste, //138 SPELL_AURA_MOD_HASTE
- &Aura::HandleForceReaction, //139 SPELL_AURA_FORCE_REACTION
- &Aura::HandleAuraModRangedHaste, //140 SPELL_AURA_MOD_RANGED_HASTE
- &Aura::HandleRangedAmmoHaste, //141 SPELL_AURA_MOD_RANGED_AMMO_HASTE
- &Aura::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT
- &Aura::HandleAuraModResistanceExclusive, //143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE
- &Aura::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes
- &Aura::HandleUnused, //145 SPELL_AURA_CHARISMA obsolete?
- &Aura::HandleUnused, //146 SPELL_AURA_PERSUADED obsolete?
- &Aura::HandleNULL, //147 SPELL_AURA_ADD_CREATURE_IMMUNITY
- &Aura::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
- &Aura::HandleNoImmediateEffect, //149 SPELL_AURA_RESIST_PUSHBACK
- &Aura::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
- &Aura::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED
- &Aura::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance
- &Aura::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT
- &Aura::HandleNoImmediateEffect, //154 SPELL_AURA_MOD_STEALTH_LEVEL
- &Aura::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING
- &Aura::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN
- &Aura::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI
- &Aura::HandleShieldBlockValue, //158 SPELL_AURA_MOD_SHIELD_BLOCKVALUE
- &Aura::HandleNoImmediateEffect, //159 SPELL_AURA_NO_PVP_CREDIT only for Honorless Target spell
- &Aura::HandleNoImmediateEffect, //160 SPELL_AURA_MOD_AOE_AVOIDANCE implemented in Unit::MagicSpellHitResult
- &Aura::HandleNoImmediateEffect, //161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT
- &Aura::HandleAuraPowerBurn, //162 SPELL_AURA_POWER_BURN_MANA
- &Aura::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
- &Aura::HandleUnused, //164 useless, only one test spell
- &Aura::HandleNoImmediateEffect, //165 SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
- &Aura::HandleAuraModAttackPowerPercent, //166 SPELL_AURA_MOD_ATTACK_POWER_PCT
- &Aura::HandleAuraModRangedAttackPowerPercent, //167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT
- &Aura::HandleNoImmediateEffect, //168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //169 SPELL_AURA_MOD_CRIT_PERCENT_VERSUS implemented in Unit::DealDamageBySchool, Unit::DoAttackDamage, Unit::SpellCriticalBonus
- &Aura::HandleNULL, //170 SPELL_AURA_DETECT_AMORE only for Detect Amore spell
- &Aura::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK
- &Aura::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
- &Aura::HandleUnused, //173 SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell
- &Aura::HandleModSpellDamagePercentFromStat, //174 SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT implemented in Unit::SpellBaseDamageBonus (by default intellect, dependent from SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT)
- &Aura::HandleModSpellHealingPercentFromStat, //175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT implemented in Unit::SpellBaseHealingBonus
- &Aura::HandleSpiritOfRedemption, //176 SPELL_AURA_SPIRIT_OF_REDEMPTION only for Spirit of Redemption spell, die at aura end
- &Aura::HandleNULL, //177 SPELL_AURA_AOE_CHARM
- &Aura::HandleNoImmediateEffect, //178 SPELL_AURA_MOD_DEBUFF_RESISTANCE implemented in Unit::MagicSpellHitResult
- &Aura::HandleNoImmediateEffect, //179 SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE implemented in Unit::SpellCriticalBonus
- &Aura::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonus
- &Aura::HandleUnused, //181 SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS unused
- &Aura::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
- &Aura::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT
- &Aura::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
- &Aura::HandleNoImmediateEffect, //185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
- &Aura::HandleNoImmediateEffect, //186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE implemented in Unit::MagicSpellHitResult
- &Aura::HandleNoImmediateEffect, //187 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
- &Aura::HandleNoImmediateEffect, //188 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
- &Aura::HandleModRating, //189 SPELL_AURA_MOD_RATING
- &Aura::HandleNULL, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN
- &Aura::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
- &Aura::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_HASTE_MELEE
- &Aura::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct)
- &Aura::HandleUnused, //194 SPELL_AURA_MOD_DEPRICATED_1 not used now (old SPELL_AURA_MOD_SPELL_DAMAGE_OF_INTELLECT)
- &Aura::HandleUnused, //195 SPELL_AURA_MOD_DEPRICATED_2 not used now (old SPELL_AURA_MOD_SPELL_HEALING_OF_INTELLECT)
- &Aura::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN
- &Aura::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::GetUnitCriticalChance
- &Aura::HandleUnused, //198 SPELL_AURA_MOD_ALL_WEAPON_SKILLS
- &Aura::HandleNoImmediateEffect, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT implemented in Unit::MagicSpellHitResult
- &Aura::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_XP_PCT implemented in Player::GiveXP
- &Aura::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode...
- &Aura::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst
- &Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
- &Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
- &Aura::HandleNULL, //205 vulnerable to school dmg?
- &Aura::HandleNULL, //206 SPELL_AURA_MOD_SPEED_MOUNTED
- &Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
- &Aura::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_SPEED_FLIGHT, used only in spell: Flight Form (Passive)
- &Aura::HandleAuraModIncreaseFlightSpeed, //209 SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
- &Aura::HandleNULL, //210 Commentator's Command
- &Aura::HandleAuraModIncreaseFlightSpeed, //211 SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
- &Aura::HandleAuraModRangedAttackPowerOfStatPercent, //212 SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
- &Aura::HandleNoImmediateEffect, //213 SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT implemented in Player::RewardRage
- &Aura::HandleNULL, //214 Tamed Pet Passive
- &Aura::HandleArenaPreparation, //215 SPELL_AURA_ARENA_PREPARATION
- &Aura::HandleModCastingSpeed, //216 SPELL_AURA_HASTE_SPELLS
- &Aura::HandleUnused, //217 unused
- &Aura::HandleAuraModRangedHaste, //218 SPELL_AURA_HASTE_RANGED
- &Aura::HandleModManaRegen, //219 SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
- &Aura::HandleNULL, //220 SPELL_AURA_MOD_RATING_FROM_STAT
- &Aura::HandleNULL, //221 ignored
- &Aura::HandleUnused, //222 unused
- &Aura::HandleNULL, //223 Cold Stare
- &Aura::HandleUnused, //224 unused
- &Aura::HandleNoImmediateEffect, //225 SPELL_AURA_PRAYER_OF_MENDING
- &Aura::HandleAuraPeriodicDummy, //226 SPELL_AURA_PERIODIC_DUMMY
- &Aura::HandleNULL, //227 periodic trigger spell
- &Aura::HandleNoImmediateEffect, //228 stealth detection
- &Aura::HandleNULL, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
- &Aura::HandleAuraModIncreaseMaxHealth, //230 Commanding Shout
- &Aura::HandleNULL, //231
- &Aura::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateSpellDuration
- &Aura::HandleNULL, //233 set model id to the one of the creature with id m_modifier.m_miscvalue
- &Aura::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateSpellDuration
- &Aura::HandleAuraModDispelResist, //235 SPELL_AURA_MOD_DISPEL_RESIST implement in Unit::MagicSpellHitResult
- &Aura::HandleUnused, //236 unused
- &Aura::HandleModSpellDamagePercentFromAttackPower, //237 SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER implemented in Unit::SpellBaseDamageBonus
- &Aura::HandleModSpellHealingPercentFromAttackPower, //238 SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER implemented in Unit::SpellBaseHealingBonus
- &Aura::HandleAuraModScale, //239 SPELL_AURA_MOD_SCALE_2 only in Noggenfogger Elixir (16595) before 2.3.0 aura 61
- &Aura::HandleAuraModExpertise, //240 SPELL_AURA_MOD_EXPERTISE
- &Aura::HandleForceMoveForward, //241 Forces the player to move forward
- &Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING
- &Aura::HandleUnused, //243 used by two test spells
- &Aura::HandleComprehendLanguage, //244 Comprehend language
- &Aura::HandleUnused, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS
- &Aura::HandleUnused, //246 unused
- &Aura::HandleUnused, //247 unused
- &Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
- &Aura::HandleNULL, //249
- &Aura::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2
- &Aura::HandleNULL, //251 SPELL_AURA_MOD_ENEMY_DODGE
- &Aura::HandleUnused, //252 unused
- &Aura::HandleUnused, //253 unused
- &Aura::HandleUnused, //254 unused
- &Aura::HandleUnused, //255 unused
- &Aura::HandleUnused, //256 unused
- &Aura::HandleUnused, //257 unused
- &Aura::HandleUnused, //258 unused
- &Aura::HandleUnused, //259 unused
- &Aura::HandleUnused, //260 unused
- &Aura::HandleNULL //261 SPELL_AURA_261 some phased state (44856 spell)
+ &AuraEffect::HandleNULL, // 0 SPELL_AURA_NONE
+ &AuraEffect::HandleBindSight, // 1 SPELL_AURA_BIND_SIGHT
+ &AuraEffect::HandleModPossess, // 2 SPELL_AURA_MOD_POSSESS
+ &AuraEffect::HandlePeriodicDamage, // 3 SPELL_AURA_PERIODIC_DAMAGE
+ &AuraEffect::HandleAuraDummy, // 4 SPELL_AURA_DUMMY
+ &AuraEffect::HandleModConfuse, // 5 SPELL_AURA_MOD_CONFUSE
+ &AuraEffect::HandleModCharm, // 6 SPELL_AURA_MOD_CHARM
+ &AuraEffect::HandleModFear, // 7 SPELL_AURA_MOD_FEAR
+ &AuraEffect::HandlePeriodicHeal, // 8 SPELL_AURA_PERIODIC_HEAL
+ &AuraEffect::HandleModAttackSpeed, // 9 SPELL_AURA_MOD_ATTACKSPEED
+ &AuraEffect::HandleModThreat, // 10 SPELL_AURA_MOD_THREAT
+ &AuraEffect::HandleModTaunt, // 11 SPELL_AURA_MOD_TAUNT
+ &AuraEffect::HandleAuraModStun, // 12 SPELL_AURA_MOD_STUN
+ &AuraEffect::HandleModDamageDone, // 13 SPELL_AURA_MOD_DAMAGE_DONE
+ &AuraEffect::HandleNoImmediateEffect, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
+ &AuraEffect::HandleNoImmediateEffect, // 15 SPELL_AURA_DAMAGE_SHIELD implemented in Unit::DoAttackDamage
+ &AuraEffect::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH
+ &AuraEffect::HandleNoImmediateEffect, // 17 SPELL_AURA_MOD_STEALTH_DETECT
+ &AuraEffect::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY
+ &AuraEffect::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION
+ &AuraEffect::HandleAuraModTotalHealthPercentRegen, // 20 SPELL_AURA_OBS_MOD_HEALTH
+ &AuraEffect::HandleAuraModTotalEnergyPercentRegen, // 21 SPELL_AURA_OBS_MOD_ENERGY
+ &AuraEffect::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE
+ &AuraEffect::HandlePeriodicTriggerSpell, // 23 SPELL_AURA_PERIODIC_TRIGGER_SPELL
+ &AuraEffect::HandlePeriodicEnergize, // 24 SPELL_AURA_PERIODIC_ENERGIZE
+ &AuraEffect::HandleAuraModPacify, // 25 SPELL_AURA_MOD_PACIFY
+ &AuraEffect::HandleAuraModRoot, // 26 SPELL_AURA_MOD_ROOT
+ &AuraEffect::HandleAuraModSilence, // 27 SPELL_AURA_MOD_SILENCE
+ &AuraEffect::HandleNoImmediateEffect, // 28 SPELL_AURA_REFLECT_SPELLS implement in Unit::SpellHitResult
+ &AuraEffect::HandleAuraModStat, // 29 SPELL_AURA_MOD_STAT
+ &AuraEffect::HandleAuraModSkill, // 30 SPELL_AURA_MOD_SKILL
+ &AuraEffect::HandleAuraModIncreaseSpeed, // 31 SPELL_AURA_MOD_INCREASE_SPEED
+ &AuraEffect::HandleAuraModIncreaseMountedSpeed, // 32 SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
+ &AuraEffect::HandleAuraModDecreaseSpeed, // 33 SPELL_AURA_MOD_DECREASE_SPEED
+ &AuraEffect::HandleAuraModIncreaseHealth, // 34 SPELL_AURA_MOD_INCREASE_HEALTH
+ &AuraEffect::HandleAuraModIncreaseEnergy, // 35 SPELL_AURA_MOD_INCREASE_ENERGY
+ &AuraEffect::HandleAuraModShapeshift, // 36 SPELL_AURA_MOD_SHAPESHIFT
+ &AuraEffect::HandleAuraModEffectImmunity, // 37 SPELL_AURA_EFFECT_IMMUNITY
+ &AuraEffect::HandleAuraModStateImmunity, // 38 SPELL_AURA_STATE_IMMUNITY
+ &AuraEffect::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY
+ &AuraEffect::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY
+ &AuraEffect::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY
+ &AuraEffect::HandleAuraProcTriggerSpell, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell
+ &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor
+ &AuraEffect::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES
+ &AuraEffect::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES
+ &AuraEffect::HandleUnused, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a)
+ &AuraEffect::HandleAuraModParryPercent, // 47 SPELL_AURA_MOD_PARRY_PERCENT
+ &AuraEffect::HandleNULL, // 48 SPELL_AURA_48 spell Napalm (area damage spell with additional delayed damage effect)
+ &AuraEffect::HandleAuraModDodgePercent, // 49 SPELL_AURA_MOD_DODGE_PERCENT
+ &AuraEffect::HandleNoImmediateEffect, // 50 SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT implemented in Unit::SpellCriticalHealingBonus
+ &AuraEffect::HandleAuraModBlockPercent, // 51 SPELL_AURA_MOD_BLOCK_PERCENT
+ &AuraEffect::HandleAuraModCritPercent, // 52 SPELL_AURA_MOD_CRIT_PERCENT
+ &AuraEffect::HandlePeriodicLeech, // 53 SPELL_AURA_PERIODIC_LEECH
+ &AuraEffect::HandleModHitChance, // 54 SPELL_AURA_MOD_HIT_CHANCE
+ &AuraEffect::HandleModSpellHitChance, // 55 SPELL_AURA_MOD_SPELL_HIT_CHANCE
+ &AuraEffect::HandleAuraTransform, // 56 SPELL_AURA_TRANSFORM
+ &AuraEffect::HandleModSpellCritChance, // 57 SPELL_AURA_MOD_SPELL_CRIT_CHANCE
+ &AuraEffect::HandleAuraModIncreaseSwimSpeed, // 58 SPELL_AURA_MOD_INCREASE_SWIM_SPEED
+ &AuraEffect::HandleNoImmediateEffect, // 59 SPELL_AURA_MOD_DAMAGE_DONE_CREATURE implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
+ &AuraEffect::HandleAuraModPacifyAndSilence, // 60 SPELL_AURA_MOD_PACIFY_SILENCE
+ &AuraEffect::HandleAuraModScale, // 61 SPELL_AURA_MOD_SCALE
+ &AuraEffect::HandlePeriodicHealthFunnel, // 62 SPELL_AURA_PERIODIC_HEALTH_FUNNEL
+ &AuraEffect::HandleUnused, // 63 unused (3.0.8a) old SPELL_AURA_PERIODIC_MANA_FUNNEL
+ &AuraEffect::HandlePeriodicManaLeech, // 64 SPELL_AURA_PERIODIC_MANA_LEECH
+ &AuraEffect::HandleModCastingSpeed, // 65 SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK
+ &AuraEffect::HandleFeignDeath, // 66 SPELL_AURA_FEIGN_DEATH
+ &AuraEffect::HandleAuraModDisarm, // 67 SPELL_AURA_MOD_DISARM
+ &AuraEffect::HandleAuraModStalked, // 68 SPELL_AURA_MOD_STALKED
+ &AuraEffect::HandleSchoolAbsorb, // 69 SPELL_AURA_SCHOOL_ABSORB implemented in Unit::CalcAbsorbResist
+ &AuraEffect::HandleUnused, // 70 SPELL_AURA_EXTRA_ATTACKS Useless, used by only one spell that has only visual effect
+ &AuraEffect::HandleModSpellCritChanceShool, // 71 SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
+ &AuraEffect::HandleModPowerCostPCT, // 72 SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT
+ &AuraEffect::HandleModPowerCost, // 73 SPELL_AURA_MOD_POWER_COST_SCHOOL
+ &AuraEffect::HandleNoImmediateEffect, // 74 SPELL_AURA_REFLECT_SPELLS_SCHOOL implemented in Unit::SpellHitResult
+ &AuraEffect::HandleNoImmediateEffect, // 75 SPELL_AURA_MOD_LANGUAGE
+ &AuraEffect::HandleFarSight, // 76 SPELL_AURA_FAR_SIGHT
+ &AuraEffect::HandleModMechanicImmunity, // 77 SPELL_AURA_MECHANIC_IMMUNITY
+ &AuraEffect::HandleAuraMounted, // 78 SPELL_AURA_MOUNTED
+ &AuraEffect::HandleModDamagePercentDone, // 79 SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
+ &AuraEffect::HandleModPercentStat, // 80 SPELL_AURA_MOD_PERCENT_STAT
+ &AuraEffect::HandleNoImmediateEffect, // 81 SPELL_AURA_SPLIT_DAMAGE_PCT
+ &AuraEffect::HandleWaterBreathing, // 82 SPELL_AURA_WATER_BREATHING
+ &AuraEffect::HandleModBaseResistance, // 83 SPELL_AURA_MOD_BASE_RESISTANCE
+ &AuraEffect::HandleModRegen, // 84 SPELL_AURA_MOD_REGEN
+ &AuraEffect::HandleModPowerRegen, // 85 SPELL_AURA_MOD_POWER_REGEN
+ &AuraEffect::HandleChannelDeathItem, // 86 SPELL_AURA_CHANNEL_DEATH_ITEM
+ &AuraEffect::HandleNoImmediateEffect, // 87 SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
+ &AuraEffect::HandleNoImmediateEffect, // 88 SPELL_AURA_MOD_HEALTH_REGEN_PERCENT
+ &AuraEffect::HandlePeriodicDamagePCT, // 89 SPELL_AURA_PERIODIC_DAMAGE_PERCENT
+ &AuraEffect::HandleUnused, // 90 unused (3.0.8a) old SPELL_AURA_MOD_RESIST_CHANCE
+ &AuraEffect::HandleNoImmediateEffect, // 91 SPELL_AURA_MOD_DETECT_RANGE implemented in Creature::GetAttackDistance
+ &AuraEffect::HandlePreventFleeing, // 92 SPELL_AURA_PREVENTS_FLEEING
+ &AuraEffect::HandleModUnattackable, // 93 SPELL_AURA_MOD_UNATTACKABLE
+ &AuraEffect::HandleNoImmediateEffect, // 94 SPELL_AURA_INTERRUPT_REGEN implemented in Player::RegenerateAll
+ &AuraEffect::HandleAuraGhost, // 95 SPELL_AURA_GHOST
+ &AuraEffect::HandleNoImmediateEffect, // 96 SPELL_AURA_SPELL_MAGNET implemented in Unit::SelectMagnetTarget
+ &AuraEffect::HandleManaShield, // 97 SPELL_AURA_MANA_SHIELD implemented in Unit::CalcAbsorbResist
+ &AuraEffect::HandleAuraModSkill, // 98 SPELL_AURA_MOD_SKILL_TALENT
+ &AuraEffect::HandleAuraModAttackPower, // 99 SPELL_AURA_MOD_ATTACK_POWER
+ &AuraEffect::HandleUnused, //100 SPELL_AURA_AURAS_VISIBLE obsolete? all player can see all auras now, but still have spells including GM-spell
+ &AuraEffect::HandleModResistancePercent, //101 SPELL_AURA_MOD_RESISTANCE_PCT
+ &AuraEffect::HandleNoImmediateEffect, //102 SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus
+ &AuraEffect::HandleAuraModTotalThreat, //103 SPELL_AURA_MOD_TOTAL_THREAT
+ &AuraEffect::HandleAuraWaterWalk, //104 SPELL_AURA_WATER_WALK
+ &AuraEffect::HandleAuraFeatherFall, //105 SPELL_AURA_FEATHER_FALL
+ &AuraEffect::HandleAuraHover, //106 SPELL_AURA_HOVER
+ &AuraEffect::HandleAddModifier, //107 SPELL_AURA_ADD_FLAT_MODIFIER
+ &AuraEffect::HandleAddModifier, //108 SPELL_AURA_ADD_PCT_MODIFIER
+ &AuraEffect::HandleAddTargetTrigger, //109 SPELL_AURA_ADD_TARGET_TRIGGER
+ &AuraEffect::HandleModPowerRegenPCT, //110 SPELL_AURA_MOD_POWER_REGEN_PERCENT
+ &AuraEffect::HandleNoImmediateEffect, //111 SPELL_AURA_ADD_CASTER_HIT_TRIGGER implemented in Unit::SelectMagnetTarget
+ &AuraEffect::HandleNoImmediateEffect, //112 SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
+ &AuraEffect::HandleNoImmediateEffect, //113 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus
+ &AuraEffect::HandleNoImmediateEffect, //114 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus
+ &AuraEffect::HandleNoImmediateEffect, //115 SPELL_AURA_MOD_HEALING implemented in Unit::SpellBaseHealingBonusForVictim
+ &AuraEffect::HandleNoImmediateEffect, //116 SPELL_AURA_MOD_REGEN_DURING_COMBAT
+ &AuraEffect::HandleNoImmediateEffect, //117 SPELL_AURA_MOD_MECHANIC_RESISTANCE implemented in Unit::MagicSpellHitResult
+ &AuraEffect::HandleNoImmediateEffect, //118 SPELL_AURA_MOD_HEALING_PCT implemented in Unit::SpellHealingBonus
+ &AuraEffect::HandleUnused, //119 unused (3.0.8a) old SPELL_AURA_SHARE_PET_TRACKING
+ &AuraEffect::HandleAuraUntrackable, //120 SPELL_AURA_UNTRACKABLE
+ &AuraEffect::HandleAuraEmpathy, //121 SPELL_AURA_EMPATHY
+ &AuraEffect::HandleModOffhandDamagePercent, //122 SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT
+ &AuraEffect::HandleModTargetResistance, //123 SPELL_AURA_MOD_TARGET_RESISTANCE
+ &AuraEffect::HandleAuraModRangedAttackPower, //124 SPELL_AURA_MOD_RANGED_ATTACK_POWER
+ &AuraEffect::HandleNoImmediateEffect, //125 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus
+ &AuraEffect::HandleNoImmediateEffect, //126 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus
+ &AuraEffect::HandleNoImmediateEffect, //127 SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
+ &AuraEffect::HandleModPossessPet, //128 SPELL_AURA_MOD_POSSESS_PET
+ &AuraEffect::HandleAuraModIncreaseSpeed, //129 SPELL_AURA_MOD_SPEED_ALWAYS
+ &AuraEffect::HandleAuraModIncreaseMountedSpeed, //130 SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
+ &AuraEffect::HandleNoImmediateEffect, //131 SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus
+ &AuraEffect::HandleAuraModIncreaseEnergyPercent, //132 SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT
+ &AuraEffect::HandleAuraModIncreaseHealthPercent, //133 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT
+ &AuraEffect::HandleAuraModRegenInterrupt, //134 SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
+ &AuraEffect::HandleModHealingDone, //135 SPELL_AURA_MOD_HEALING_DONE
+ &AuraEffect::HandleNoImmediateEffect, //136 SPELL_AURA_MOD_HEALING_DONE_PERCENT implemented in Unit::SpellHealingBonus
+ &AuraEffect::HandleModTotalPercentStat, //137 SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
+ &AuraEffect::HandleHaste, //138 SPELL_AURA_MOD_HASTE
+ &AuraEffect::HandleForceReaction, //139 SPELL_AURA_FORCE_REACTION
+ &AuraEffect::HandleAuraModRangedHaste, //140 SPELL_AURA_MOD_RANGED_HASTE
+ &AuraEffect::HandleRangedAmmoHaste, //141 SPELL_AURA_MOD_RANGED_AMMO_HASTE
+ &AuraEffect::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT
+ &AuraEffect::HandleAuraModResistanceExclusive, //143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE
+ &AuraEffect::HandleAuraSafeFall, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes
+ &AuraEffect::HandleAuraModPetTalentsPoints, //145 SPELL_AURA_MOD_PET_TALENT_POINTS
+ &AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE
+ &AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
+ &AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
+ &AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK
+ &AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
+ &AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED
+ &AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance
+ &AuraEffect::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT
+ &AuraEffect::HandleNoImmediateEffect, //154 SPELL_AURA_MOD_STEALTH_LEVEL
+ &AuraEffect::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING
+ &AuraEffect::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN
+ &AuraEffect::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI
+ &AuraEffect::HandleShieldBlockValue, //158 SPELL_AURA_MOD_SHIELD_BLOCKVALUE
+ &AuraEffect::HandleNoImmediateEffect, //159 SPELL_AURA_NO_PVP_CREDIT only for Honorless Target spell
+ &AuraEffect::HandleNoImmediateEffect, //160 SPELL_AURA_MOD_AOE_AVOIDANCE implemented in Unit::MagicSpellHitResult
+ &AuraEffect::HandleNoImmediateEffect, //161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT
+ &AuraEffect::HandleAuraPowerBurn, //162 SPELL_AURA_POWER_BURN_MANA
+ &AuraEffect::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
+ &AuraEffect::HandleUnused, //164 unused (3.0.8a), only one test spell
+ &AuraEffect::HandleNoImmediateEffect, //165 SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
+ &AuraEffect::HandleAuraModAttackPowerPercent, //166 SPELL_AURA_MOD_ATTACK_POWER_PCT
+ &AuraEffect::HandleAuraModRangedAttackPowerPercent, //167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT
+ &AuraEffect::HandleNoImmediateEffect, //168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus
+ &AuraEffect::HandleNoImmediateEffect, //169 SPELL_AURA_MOD_CRIT_PERCENT_VERSUS implemented in Unit::DealDamageBySchool, Unit::DoAttackDamage, Unit::SpellCriticalBonus
+ &AuraEffect::HandleNULL, //170 SPELL_AURA_DETECT_AMORE different spells that ignore transformation effects
+ &AuraEffect::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK
+ &AuraEffect::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
+ &AuraEffect::HandleUnused, //173 unused (3.0.8a) no spells, old SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell
+ &AuraEffect::HandleModSpellDamagePercentFromStat, //174 SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT implemented in Unit::SpellBaseDamageBonus
+ &AuraEffect::HandleModSpellHealingPercentFromStat, //175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT implemented in Unit::SpellBaseHealingBonus
+ &AuraEffect::HandleSpiritOfRedemption, //176 SPELL_AURA_SPIRIT_OF_REDEMPTION only for Spirit of Redemption spell, die at aura end
+ &AuraEffect::HandleNULL, //177 SPELL_AURA_AOE_CHARM
+ &AuraEffect::HandleNoImmediateEffect, //178 SPELL_AURA_MOD_DEBUFF_RESISTANCE implemented in Unit::MagicSpellHitResult
+ &AuraEffect::HandleNoImmediateEffect, //179 SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE implemented in Unit::SpellCriticalBonus
+ &AuraEffect::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonus
+ &AuraEffect::HandleUnused, //181 unused (3.0.8a) old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS
+ &AuraEffect::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
+ &AuraEffect::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746
+ &AuraEffect::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
+ &AuraEffect::HandleNoImmediateEffect, //185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
+ &AuraEffect::HandleNoImmediateEffect, //186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE implemented in Unit::MagicSpellHitResult
+ &AuraEffect::HandleNoImmediateEffect, //187 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
+ &AuraEffect::HandleNoImmediateEffect, //188 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
+ &AuraEffect::HandleModRating, //189 SPELL_AURA_MOD_RATING
+ &AuraEffect::HandleNoImmediateEffect, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN implemented in Player::CalculateReputationGain
+ &AuraEffect::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
+ &AuraEffect::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_HASTE_MELEE
+ &AuraEffect::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct)
+ &AuraEffect::HandleNULL, //194 SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist
+ &AuraEffect::HandleNoImmediateEffect, //195 SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist
+ &AuraEffect::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN
+ &AuraEffect::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::GetUnitCriticalChance
+ &AuraEffect::HandleUnused, //198 unused (3.0.8a) old SPELL_AURA_MOD_ALL_WEAPON_SKILLS
+ &AuraEffect::HandleNoImmediateEffect, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT implemented in Unit::MagicSpellHitResult
+ &AuraEffect::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_XP_PCT implemented in Player::GiveXP
+ &AuraEffect::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode...
+ &AuraEffect::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst
+ &AuraEffect::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
+ &AuraEffect::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
+ &AuraEffect::HandleNULL, //205 vulnerable to school dmg?
+ &AuraEffect::HandleAuraModIncreaseFlightSpeed, //206 SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED
+ &AuraEffect::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
+ &AuraEffect::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
+ &AuraEffect::HandleAuraModIncreaseFlightSpeed, //209 SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS
+ &AuraEffect::HandleAuraModIncreaseFlightSpeed, //210 SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS
+ &AuraEffect::HandleAuraModIncreaseFlightSpeed, //211 SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
+ &AuraEffect::HandleAuraModRangedAttackPowerOfStatPercent, //212 SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
+ &AuraEffect::HandleNoImmediateEffect, //213 SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT implemented in Player::RewardRage
+ &AuraEffect::HandleNULL, //214 Tamed Pet Passive
+ &AuraEffect::HandleArenaPreparation, //215 SPELL_AURA_ARENA_PREPARATION
+ &AuraEffect::HandleModCastingSpeed, //216 SPELL_AURA_HASTE_SPELLS
+ &AuraEffect::HandleUnused, //217 unused (3.0.8a)
+ &AuraEffect::HandleAuraModRangedHaste, //218 SPELL_AURA_HASTE_RANGED
+ &AuraEffect::HandleModManaRegen, //219 SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
+ &AuraEffect::HandleModRatingFromStat, //220 SPELL_AURA_MOD_RATING_FROM_STAT
+ &AuraEffect::HandleNULL, //221 ignored
+ &AuraEffect::HandleUnused, //222 unused (3.0.8a) only for spell 44586 that not used in real spell cast
+ &AuraEffect::HandleNoImmediateEffect, //223 SPELL_AURA_RAID_PROC_FROM_CHARGE
+ &AuraEffect::HandleUnused, //224 unused (3.0.8a)
+ &AuraEffect::HandleNoImmediateEffect, //225 SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE
+ &AuraEffect::HandleAuraPeriodicDummy, //226 SPELL_AURA_PERIODIC_DUMMY
+ &AuraEffect::HandlePeriodicTriggerSpellWithValue, //227 SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE
+ &AuraEffect::HandleNoImmediateEffect, //228 stealth detection
+ &AuraEffect::HandleNULL, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
+ &AuraEffect::HandleAuraModIncreaseHealth, //230 SPELL_AURA_MOD_INCREASE_HEALTH_2
+ &AuraEffect::HandleNoImmediateEffect, //231 SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE
+ &AuraEffect::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateSpellDuration
+ &AuraEffect::HandleNULL, //233 set model id to the one of the creature with id GetMiscValue()
+ &AuraEffect::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateSpellDuration
+ &AuraEffect::HandleNoImmediateEffect, //235 SPELL_AURA_MOD_DISPEL_RESIST implement in Unit::MagicSpellHitResult
+ &AuraEffect::HandleAuraControlVehicle, //236 SPELL_AURA_CONTROL_VEHICLE
+ &AuraEffect::HandleModSpellDamagePercentFromAttackPower, //237 SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER implemented in Unit::SpellBaseDamageBonus
+ &AuraEffect::HandleModSpellHealingPercentFromAttackPower, //238 SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER implemented in Unit::SpellBaseHealingBonus
+ &AuraEffect::HandleAuraModScale, //239 SPELL_AURA_MOD_SCALE_2 only in Noggenfogger Elixir (16595) before 2.3.0 aura 61
+ &AuraEffect::HandleAuraModExpertise, //240 SPELL_AURA_MOD_EXPERTISE
+ &AuraEffect::HandleForceMoveForward, //241 Forces the player to move forward
+ &AuraEffect::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING
+ &AuraEffect::HandleNULL, //243 faction reaction override spells
+ &AuraEffect::HandleComprehendLanguage, //244 Comprehend language
+ &AuraEffect::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL
+ &AuraEffect::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK implemented in Spell::EffectApplyAura
+ &AuraEffect::HandleNULL, //247 target to become a clone of the caster
+ &AuraEffect::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
+ &AuraEffect::HandleAuraConvertRune, //249 SPELL_AURA_CONVERT_RUNE
+ &AuraEffect::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2
+ &AuraEffect::HandleNoImmediateEffect, //251 SPELL_AURA_MOD_ENEMY_DODGE
+ &AuraEffect::HandleNULL, //252 haste all?
+ &AuraEffect::HandleNoImmediateEffect, //253 SPELL_AURA_MOD_BLOCK_CRIT_CHANCE implemented in Unit::isBlockCritical
+ &AuraEffect::HandleAuraModDisarm, //254 SPELL_AURA_MOD_DISARM_OFFHAND
+ &AuraEffect::HandleNoImmediateEffect, //255 SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT implemented in Unit::SpellDamageBonus
+ &AuraEffect::HandleNoReagentUseAura, //256 SPELL_AURA_NO_REAGENT_USE Use SpellClassMask for spell select
+ &AuraEffect::HandleNULL, //257 SPELL_AURA_MOD_TARGET_RESIST_BY_SPELL_CLASS Use SpellClassMask for spell select
+ &AuraEffect::HandleNULL, //258 SPELL_AURA_MOD_SPELL_VISUAL
+ &AuraEffect::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_HOT_PCT implemented in Unit::SpellHealingBonus
+ &AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code
+ &AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE undetactable invisibility? implemented in Unit::isVisibleForOrDetect
+ &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast
+ &AuraEffect::HandleAuraAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask
+ &AuraEffect::HandleUnused, //264 unused (3.0.8a)
+ &AuraEffect::HandleUnused, //265 unused (3.0.8a)
+ &AuraEffect::HandleUnused, //266 unused (3.0.8a)
+ &AuraEffect::HandleNoImmediateEffect, //267 SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL implemented in Unit::IsImmunedToSpellEffect
+ &AuraEffect::HandleAuraModAttackPowerOfStatPercent, //268 SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
+ &AuraEffect::HandleNoImmediateEffect, //269 SPELL_AURA_MOD_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage
+ &AuraEffect::HandleNoImmediateEffect, //270 SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage
+ &AuraEffect::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonus
+ &AuraEffect::HandleNULL, //272 reduce spell cast time?
+ &AuraEffect::HandleUnused, //273 clientside
+ &AuraEffect::HandleNoImmediateEffect, //274 SPELL_AURA_CONSUME_NO_AMMO implemented in spell::CalculateDamageDoneForAllTargets
+ &AuraEffect::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select
+ &AuraEffect::HandleNULL, //276 mod damage % mechanic?
+ &AuraEffect::HandleNoImmediateEffect, //277 SPELL_AURA_MOD_ABILITY_AFFECTED_TARGETS implemented in spell::settargetmap
+ &AuraEffect::HandleAuraModDisarm, //278 SPELL_AURA_MOD_DISARM_RANGED disarm ranged weapon
+ &AuraEffect::HandleNULL, //279 visual effects? 58836 and 57507
+ &AuraEffect::HandleNoImmediateEffect, //280 SPELL_AURA_MOD_WEAPONTYPE_IGNORE_TARGET_RESISTANCE
+ &AuraEffect::HandleNoImmediateEffect, //281 SPELL_AURA_MOD_HONOR_GAIN_PCT implemented in Player::RewardHonor
+ &AuraEffect::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT
+ &AuraEffect::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus
+ &AuraEffect::HandleUnused, //284 not used by any spells (3.08a)
+ &AuraEffect::HandleUnused, //285 not used by any spells (3.08a)
+ &AuraEffect::HandleUnused, //286 not used by any spells (3.08a)
+ &AuraEffect::HandleNoImmediateEffect, //287 SPELL_AURA_DEFLECT_SPELLS implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult
+ &AuraEffect::HandleUnused, //288 not used by any spells (3.09) except 1 test spell.
};
-Aura::Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem) :
-m_procCharges(0), m_stackAmount(1), m_spellmod(NULL), m_effIndex(eff), m_caster_guid(0), m_target(target),
-m_timeCla(1000), m_castItemGuid(castItem?castItem->GetGUID():0), m_auraSlot(MAX_AURAS),
-m_positive(false), m_permanent(false), m_isPeriodic(false), m_isTrigger(false), m_isAreaAura(false),
-m_isPersistent(false), m_updated(false), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_isRemovedOnShapeLost(true), m_in_use(false),
-m_periodicTimer(0), m_PeriodicEventId(0), m_AuraDRGroup(DIMINISHING_NONE)
-,m_tickNumber(0)
+Aura::Aura(SpellEntry const* spellproto, uint32 effMask, int32 *currentBasePoints, Unit *target, WorldObject *source, Unit *caster, Item* castItem) :
+m_caster_guid(0), m_castItemGuid(castItem?castItem->GetGUID():0), m_target(target),
+m_timeCla(1000), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE),
+m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_auraStateMask(0), m_updated(false), m_isRemoved(false)
{
assert(target);
assert(spellproto && spellproto == sSpellStore.LookupEntry( spellproto->Id ) && "`info` must be pointer to sSpellStore element");
- m_spellProto = spellproto;
+ m_auraFlags = effMask;
- int32 damage;
- if(currentBasePoints)
- {
- damage = *currentBasePoints;
- m_currentBasePoints = damage - 1;
- }
- else
- {
- m_currentBasePoints = m_spellProto->EffectBasePoints[eff];
- if(caster)
- damage = caster->CalculateSpellDamage(m_spellProto, m_effIndex, m_currentBasePoints, target);
- else
- damage = m_currentBasePoints + 1;
- }
+ m_spellProto = spellproto;
m_isPassive = IsPassiveSpell(GetId());
- m_positive = IsPositiveEffect(GetId(), m_effIndex);
- m_applyTime = time(NULL);
+ m_auraStateMask = 0;
m_isSingleTargetAura = IsSingleTargetSpell(m_spellProto);
+ m_applyTime = time(NULL);
+
if(!caster)
{
m_caster_guid = target->GetGUID();
//damage = m_currentBasePoints+1; // stored value-1
- m_maxduration = target->CalculateSpellDuration(m_spellProto, m_effIndex, target);
+ m_maxduration = target->CalcSpellDuration(m_spellProto);
}
else
{
m_caster_guid = caster->GetGUID();
//damage = caster->CalculateSpellDamage(m_spellProto,m_effIndex,m_currentBasePoints,target);
- m_maxduration = caster->CalculateSpellDuration(m_spellProto, m_effIndex, target);
-
- if (!damage && castItem && castItem->GetItemSuffixFactor())
- {
- ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(castItem->GetItemRandomPropertyId()));
- if(item_rand_suffix)
- {
- for (int k=0; k<3; k++)
- {
- SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(item_rand_suffix->enchant_id[k]);
- if(pEnchant)
- {
- for (int t=0; t<3; t++)
- if(pEnchant->spellid[t] == m_spellProto->Id)
- {
- damage = uint32((item_rand_suffix->prefix[k]*castItem->GetItemSuffixFactor()) / 10000 );
- break;
- }
- }
-
- if(damage)
- break;
- }
- }
- }
+ m_maxduration = caster->CalcSpellDuration(m_spellProto);
}
if(m_maxduration == -1 || m_isPassive && m_spellProto->DurationIndex == 0)
m_permanent = true;
+ else
+ m_permanent = false;
Player* modOwner = caster ? caster->GetSpellModOwner() : NULL;
if(!m_permanent && modOwner)
+ {
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, m_maxduration);
+ // Get zero duration aura after - need set m_maxduration > 0 for apply/remove aura work
+ if (m_maxduration<=0)
+ m_maxduration = 1;
+ }
m_duration = m_maxduration;
- if(modOwner)
- modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_periodicTimer);
-
- sLog.outDebug("Aura: construct Spellid : %u, Aura : %u Duration : %d Target : %d Damage : %d", m_spellProto->Id, m_spellProto->EffectApplyAuraName[eff], m_maxduration, m_spellProto->EffectImplicitTargetA[eff],damage);
+ m_isDeathPersist = IsDeathPersistentSpell(m_spellProto);
- m_effIndex = eff;
- SetModifier(AuraType(m_spellProto->EffectApplyAuraName[eff]), damage, m_spellProto->EffectAmplitude[eff], m_spellProto->EffectMiscValue[eff]);
+ m_procCharges = m_spellProto->procCharges;
+ if(modOwner)
+ modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
- m_isDeathPersist = IsDeathPersistentSpell(m_spellProto);
+ m_isRemovedOnShapeLost = (m_caster_guid==m_target->GetGUID() &&
+ m_spellProto->Stances &&
+ !(m_spellProto->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) &&
+ !(m_spellProto->Attributes & SPELL_ATTR_NOT_SHAPESHIFT));
- if(m_spellProto->procCharges)
+ for (uint8 i=0 ;i<MAX_SPELL_EFFECTS;++i)
{
- m_procCharges = m_spellProto->procCharges;
-
- if(modOwner)
- modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
+ if (m_auraFlags & (uint8(1) << i))
+ {
+ if (currentBasePoints)
+ m_partAuras[i] = CreateAuraEffect(this, i, currentBasePoints + i, caster, NULL, source);
+ else
+ m_partAuras[i] = CreateAuraEffect(this, i, NULL, caster, NULL, source);
+ // correct flags if aura couldn't be created
+ if (!m_partAuras[i])
+ m_auraFlags &= uint8(~(1<< i));
+ }
+ else
+ {
+ m_partAuras[i]=NULL;
+ }
}
- else
- m_procCharges = -1;
- m_isRemovedOnShapeLost = (m_caster_guid==m_target->GetGUID() && m_spellProto->Stances &&
- !(m_spellProto->AttributesEx2 & 0x80000) && !(m_spellProto->Attributes & 0x10000));
+ // Aura is positive when it is casted by friend and at least one aura is positive
+ // or when it is casted by enemy and at least one aura is negative
+ bool swap=false;
+ if (!caster || caster==target) // caster == target - 1 negative effect is enough for aura to be negative
+ m_positive = false;
+ else
+ m_positive = !caster->IsHostileTo(m_target);
+ for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i)
+ {
+ if (!(1<<i & GetEffectMask()))
+ continue;
+ if (m_positive == IsPositiveEffect(GetId(), i))
+ {
+ swap = true;
+ break;
+ }
+ }
+ if (!swap)
+ m_positive=!m_positive;
}
Aura::~Aura()
{
+ // free part auras memory
+ for (uint8 i=0 ; i<MAX_SPELL_EFFECTS;++i)
+ if (m_partAuras[i])
+ delete m_partAuras[i];
+}
+
+AuraEffect::AuraEffect(Aura * parentAura, uint8 effIndex, int32 * currentBasePoints , Unit *caster, Item* castItem, WorldObject *source) :
+m_parentAura(parentAura), m_spellmod(NULL), m_periodicTimer(0), m_isPeriodic(false), m_isAreaAura(false), m_isPersistent(false),
+m_target(parentAura->GetTarget()), m_tickNumber(0)
+{
+ m_spellProto = parentAura->GetSpellProto();
+ m_effIndex = effIndex;
+ m_auraName = AuraType(m_spellProto->EffectApplyAuraName[m_effIndex]);
+
+ if(currentBasePoints)
+ m_currentBasePoints = *currentBasePoints;
+ else
+ m_currentBasePoints = m_spellProto->EffectBasePoints[m_effIndex];
+
+ if(caster)
+ m_amount = caster->CalculateSpellDamage(m_spellProto, m_effIndex, m_currentBasePoints, m_target);
+ else
+ m_amount = m_currentBasePoints + 1;
+
+ if (!m_amount && castItem && castItem->GetItemSuffixFactor())
+ {
+ ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(castItem->GetItemRandomPropertyId()));
+ if(item_rand_suffix)
+ {
+ for (int k=0; k<3; k++)
+ {
+ SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(item_rand_suffix->enchant_id[k]);
+ if(pEnchant)
+ {
+ for (int t=0; t<3; t++)
+ if(pEnchant->spellid[t] == m_spellProto->Id)
+ {
+ m_amount = uint32((item_rand_suffix->prefix[k]*castItem->GetItemSuffixFactor()) / 10000 );
+ break;
+ }
+ }
+
+ if(m_amount)
+ break;
+ }
+ }
+ }
+
+ Player* modOwner = caster ? caster->GetSpellModOwner() : NULL;
+ m_sourceGUID = source ? source->GetGUID() : (caster ? caster->GetGUID() : 0);
+ m_amplitude = m_spellProto->EffectAmplitude[m_effIndex];
+
+ //apply casting time mods for channeled spells
+ if (modOwner && m_amplitude && IsChanneledSpell(m_spellProto))
+ modOwner->ModSpellCastTime(m_spellProto, m_amplitude);
+
+ // Apply periodic time mod
+ if(modOwner && m_amplitude)
+ modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_amplitude);
+
+ // Start periodic on next tick or at aura apply
+ if (!(m_spellProto->AttributesEx5 & SPELL_ATTR_EX5_START_PERIODIC_AT_APPLY))
+ m_periodicTimer += m_amplitude;
}
-AreaAura::AreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target,
-Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, target, caster, castItem)
+AreaAuraEffect::AreaAuraEffect(Aura * parentAura, uint32 effIndex, int32 * currentBasePoints, Unit * caster, Item * castItem, Unit * source)
+: AuraEffect(parentAura, effIndex, currentBasePoints, caster, castItem, source)
{
+ m_removeTime = FRIENDLY_AA_REMOVE_TIME;
m_isAreaAura = true;
- // caster==NULL in constructor args if target==caster in fact
- Unit* caster_ptr = caster ? caster : target;
+ Unit* caster_ptr = caster ? caster : source ? source : m_target;
+
+ if (m_spellProto->Effect[effIndex] == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY)
+ m_radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[m_effIndex]));
+ else
+ m_radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[m_effIndex]));
- m_radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[m_effIndex]));
if(Player* modOwner = caster_ptr->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_RADIUS, m_radius);
- switch(spellproto->Effect[eff])
+ switch(m_spellProto->Effect[effIndex])
{
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
m_areaAuraType = AREA_AURA_PARTY;
- if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isTotem())
- m_modifier.m_auraname = SPELL_AURA_NONE;
+ if(m_target->GetTypeId() == TYPEID_UNIT && ((Creature*)m_target)->isTotem())
+ m_auraName = SPELL_AURA_NONE;
+ break;
+ case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
+ m_areaAuraType = AREA_AURA_RAID;
+ if(m_target->GetTypeId() == TYPEID_UNIT && ((Creature*)m_target)->isTotem())
+ m_auraName = SPELL_AURA_NONE;
break;
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
m_areaAuraType = AREA_AURA_FRIEND;
break;
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
m_areaAuraType = AREA_AURA_ENEMY;
- if(target == caster_ptr)
- m_modifier.m_auraname = SPELL_AURA_NONE; // Do not do any effect on self
+ if(m_target == caster_ptr)
+ m_auraName = SPELL_AURA_NONE; // Do not do any effect on self
break;
case SPELL_EFFECT_APPLY_AREA_AURA_PET:
m_areaAuraType = AREA_AURA_PET;
break;
case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
m_areaAuraType = AREA_AURA_OWNER;
- if(target == caster_ptr)
- m_modifier.m_auraname = SPELL_AURA_NONE;
+ if(m_target == caster_ptr)
+ m_auraName = SPELL_AURA_NONE;
break;
default:
sLog.outError("Wrong spell effect in AreaAura constructor");
@@ -472,26 +563,35 @@ Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, target,
}
}
-AreaAura::~AreaAura()
+AreaAuraEffect::~AreaAuraEffect()
{
}
-PersistentAreaAura::PersistentAreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target,
-Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, target, caster, castItem)
+PersistentAreaAuraEffect::PersistentAreaAuraEffect(Aura * parentAura, uint32 effIndex, int32 * currentBasePoints, Unit * caster,Item * castItem, DynamicObject *source)
+: AuraEffect(parentAura, effIndex, currentBasePoints, caster, castItem, source)
{
m_isPersistent = true;
}
-PersistentAreaAura::~PersistentAreaAura()
+PersistentAreaAuraEffect::~PersistentAreaAuraEffect()
{
}
-Aura* CreateAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem)
+AuraEffect* CreateAuraEffect(Aura * parentAura, uint32 effIndex, int32 *currentBasePoints, Unit * caster, Item * castItem, WorldObject* source)
{
- if (IsAreaAuraEffect(spellproto->Effect[eff]))
- return new AreaAura(spellproto, eff, currentBasePoints, target, caster, castItem);
-
- return new Aura(spellproto, eff, currentBasePoints, target, caster, castItem);
+ // TODO: source should belong to aura, but not areaeffect. multiple areaaura/persistent aura should use one source
+ assert(parentAura);
+ if (IsAreaAuraEffect(parentAura->GetSpellProto()->Effect[effIndex]))
+ {
+ //TODO: determine source here
+ if(source && source->isType(TYPEMASK_UNIT))
+ return new AreaAuraEffect(parentAura, effIndex, currentBasePoints, caster, castItem, (Unit*)source);
+ }
+ else if (parentAura->GetSpellProto()->Effect[effIndex] == SPELL_EFFECT_APPLY_AURA)
+ return new AuraEffect(parentAura, effIndex, currentBasePoints, caster, castItem, source);
+ else if (parentAura->GetSpellProto()->Effect[effIndex] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
+ return new PersistentAreaAuraEffect(parentAura, effIndex, currentBasePoints, caster, castItem);
+ return NULL;
}
Unit* Aura::GetCaster() const
@@ -505,12 +605,16 @@ Unit* Aura::GetCaster() const
return unit && unit->IsInWorld() ? unit : NULL;
}
-void Aura::SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue)
+Unit* AuraEffect::GetSource() const
{
- m_modifier.m_auraname = t;
- m_modifier.m_amount = a;
- m_modifier.m_miscvalue = miscValue;
- m_modifier.periodictime = pt;
+ if(m_sourceGUID == m_target->GetGUID())
+ return m_target;
+
+ //return ObjectAccessor::GetUnit(*m_target,m_caster_guid);
+ //must return caster even if it's in another grid/map
+ Unit *unit = ObjectAccessor::GetObjectInWorld(m_sourceGUID, (Unit*)NULL);
+ //only player can be not in world while in objectaccessor
+ return unit && unit->IsInWorld() ? unit : NULL;
}
void Aura::Update(uint32 diff)
@@ -520,121 +624,101 @@ void Aura::Update(uint32 diff)
m_duration -= diff;
if (m_duration < 0)
m_duration = 0;
- m_timeCla -= diff;
- // GetEffIndex()==0 prevent double/triple apply manaPerSecond/manaPerSecondPerLevel to same spell with many auras
// all spells with manaPerSecond/manaPerSecondPerLevel have aura in effect 0
- if(GetEffIndex()==0 && m_timeCla <= 0)
+ if(m_timeCla > 0)
+ m_timeCla -= diff;
+ if(m_timeCla <= 0)
{
if(Unit* caster = GetCaster())
{
- Powers powertype = Powers(m_spellProto->powerType);
- int32 manaPerSecond = m_spellProto->manaPerSecond + m_spellProto->manaPerSecondPerLevel * caster->getLevel();
- m_timeCla = 1000;
- if (manaPerSecond)
+ if(int32 manaPerSecond = m_spellProto->manaPerSecond + m_spellProto->manaPerSecondPerLevel * caster->getLevel())
{
- if(powertype==POWER_HEALTH)
- caster->ModifyHealth(-manaPerSecond);
+ m_timeCla = 1000;
+
+ Powers powertype = Powers(m_spellProto->powerType);
+ if(powertype == POWER_HEALTH)
+ {
+ if (caster->GetHealth() > manaPerSecond)
+ caster->ModifyHealth(-manaPerSecond);
+ else
+ {
+ m_target->RemoveAura(this);
+ return;
+ }
+ }
else
- caster->ModifyPower(powertype,-manaPerSecond);
+ {
+ if (caster->GetPower(powertype) >= manaPerSecond)
+ caster->ModifyPower(powertype, -manaPerSecond);
+ else
+ {
+ m_target->RemoveAura(this);
+ return;
+ }
+ }
}
}
}
}
- // Channeled aura required check distance from caster except in possessed cases
- if(IsChanneledSpell(m_spellProto) && m_caster_guid != m_target->GetGUID() && !m_target->isPossessed())
- {
- Unit* caster = GetCaster();
- if(!caster)
- {
- m_target->RemoveAura(GetId(),GetEffIndex());
- return;
- }
-
- // Get spell range
- float radius;
- SpellModOp mod;
- if (m_spellProto->EffectRadiusIndex[GetEffIndex()])
- {
- radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellProto->EffectRadiusIndex[GetEffIndex()]));
- mod = SPELLMOD_RADIUS;
- }
- else
- {
- radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellProto->rangeIndex));
- mod = SPELLMOD_RANGE;
- }
-
- if(Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetId(), mod, radius,NULL);
-
- if(!caster->IsWithinDistInMap(m_target,radius))
- {
- m_target->RemoveAura(GetId(),GetEffIndex());
- return;
- }
- }
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (m_partAuras[i])
+ m_partAuras[i]->Update(diff);
+}
- if(m_isPeriodic && (m_duration >= 0 || m_isPassive || m_permanent))
+void AuraEffect::Update(uint32 diff)
+{
+ if (m_isPeriodic && (GetParentAura()->GetAuraDuration() >=0 || GetParentAura()->IsPassive() || GetParentAura()->IsPermanent()))
{
m_periodicTimer -= diff;
- if(m_periodicTimer <= 0) // tick also at m_periodicTimer==0 to prevent lost last tick in case max m_duration == (max m_periodicTimer)*N
+ if(m_periodicTimer <= 0) // tick also at m_periodicTimer==0 to prevent lost last tick in case max m_duration == (max m_periodicTimer)*N
{
++m_tickNumber;
- if( m_modifier.m_auraname == SPELL_AURA_MOD_REGEN ||
- m_modifier.m_auraname == SPELL_AURA_MOD_POWER_REGEN ||
- // Cannibalize, eating items and other spells
- m_modifier.m_auraname == SPELL_AURA_OBS_MOD_HEALTH ||
- // Eating items and other spells
- m_modifier.m_auraname == SPELL_AURA_OBS_MOD_MANA )
- {
- ApplyModifier(true);
- return;
- }
// update before applying (aura can be removed in TriggerSpell or PeriodicTick calls)
- m_periodicTimer += m_modifier.periodictime;
+ m_periodicTimer += m_amplitude;
if(!m_target->hasUnitState(UNIT_STAT_ISOLATED))
- {
- if(m_isTrigger)
- TriggerSpell();
- else
- PeriodicTick();
- }
+ PeriodicTick();
}
}
}
-void AreaAura::Update(uint32 diff)
+void AreaAuraEffect::Update(uint32 diff)
{
// update for the caster of the aura
- if(m_caster_guid == m_target->GetGUID())
+ if(m_sourceGUID == m_target->GetGUID())
{
- Unit* caster = m_target;
+ Unit *source = m_target;
+ Unit *caster = GetCaster();
+ if (!caster)
+ m_target->RemoveAura(GetParentAura());
- if( !caster->hasUnitState(UNIT_STAT_ISOLATED) )
+ if( !source->hasUnitState(UNIT_STAT_ISOLATED) )
{
std::list<Unit *> targets;
switch(m_areaAuraType)
{
case AREA_AURA_PARTY:
- caster->GetPartyMember(targets, m_radius);
+ source->GetPartyMember(targets, m_radius);
+ break;
+ case AREA_AURA_RAID:
+ source->GetRaidMember(targets, m_radius);
break;
case AREA_AURA_FRIEND:
{
- Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(caster, caster, m_radius);
- Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(targets, u_check);
- caster->VisitNearbyObject(m_radius, searcher);
+ Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(source, caster, m_radius);
+ Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(source, targets, u_check);
+ source->VisitNearbyObject(m_radius, searcher);
break;
}
case AREA_AURA_ENEMY:
{
- Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(caster, caster, m_radius); // No GetCharmer in searcher
- Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(targets, u_check);
- caster->VisitNearbyObject(m_radius, searcher);
+ Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(source, caster, m_radius); // No GetCharmer in searcher
+ Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(source, targets, u_check);
+ source->VisitNearbyObject(m_radius, searcher);
break;
}
case AREA_AURA_OWNER:
@@ -646,10 +730,28 @@ void AreaAura::Update(uint32 diff)
}
}
- for(std::list<Unit *>::iterator tIter = targets.begin(); tIter != targets.end(); tIter++)
+ for(std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end(); tIter++)
{
- if((*tIter)->HasAura(GetId(), m_effIndex))
- continue;
+ if(Aura *aur = (*tIter)->GetAura(GetId(), GetCasterGUID()))
+ {
+ if(aur->HasEffect(GetEffIndex()))
+ continue;
+ }
+ else
+ {
+ bool skip = false;
+ for(Unit::AuraMap::iterator iter = (*tIter)->GetAuras().begin(); iter != (*tIter)->GetAuras().end();++iter)
+ {
+ bool samecaster = iter->second->GetCasterGUID() == GetCasterGUID();
+ if(spellmgr.IsNoStackSpellDueToSpell(GetId(), iter->first, samecaster))
+ {
+ skip = true;
+ break;
+ }
+ }
+ if(skip)
+ continue;
+ }
if(SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(GetSpellProto(), (*tIter)->getLevel()))
{
@@ -657,152 +759,218 @@ void AreaAura::Update(uint32 diff)
// recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?)
//if(actualSpellInfo != GetSpellProto())
// actualBasePoints = actualSpellInfo->EffectBasePoints[m_effIndex];
- AreaAura *aur;
- if(actualSpellInfo == GetSpellProto())
- aur = new AreaAura(actualSpellInfo, m_effIndex, &m_modifier.m_amount, (*tIter), caster, NULL);
- else
- aur = new AreaAura(actualSpellInfo, m_effIndex, NULL, (*tIter), caster, NULL);
- (*tIter)->AddAura(aur);
+ (*tIter)->AddAuraEffect(actualSpellInfo, GetEffIndex(), caster, &m_currentBasePoints, source);
if(m_areaAuraType == AREA_AURA_ENEMY)
caster->CombatStart(*tIter);
}
}
}
- Aura::Update(diff);
+ AuraEffect::Update(diff);
}
else // aura at non-caster
{
- Unit * tmp_target = m_target;
- Unit* caster = GetCaster();
- uint32 tmp_spellId = GetId(), tmp_effIndex = m_effIndex;
-
// WARNING: the aura may get deleted during the update
// DO NOT access its members after update!
- Aura::Update(diff);
+ AuraEffect::Update(diff);
+
+ // Speedup - no need to do more checks
+ if (GetParentAura()->IsRemoved())
+ return;
+
+ // Caster may be deleted due to update
+ Unit *caster = GetCaster();
+ Unit *source = GetSource();
// remove aura if out-of-range from caster (after teleport for example)
// or caster is isolated or caster no longer has the aura
// or caster is (no longer) friendly
bool needFriendly = (m_areaAuraType == AREA_AURA_ENEMY ? false : true);
- if( !caster || caster->hasUnitState(UNIT_STAT_ISOLATED) ||
- !caster->IsWithinDistInMap(tmp_target, m_radius) ||
- !caster->HasAura(tmp_spellId, tmp_effIndex) ||
- caster->IsFriendlyTo(tmp_target) != needFriendly
+ if( !source || !caster ||
+ source->hasUnitState(UNIT_STAT_ISOLATED) || !source->HasAuraEffect(GetId(), m_effIndex) ||
+ caster->IsFriendlyTo(m_target) != needFriendly
)
{
- tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
+ m_target->RemoveAura(GetParentAura());
}
- else if( m_areaAuraType == AREA_AURA_PARTY) // check if in same sub group
+ else if (!source->IsWithinDistInMap(m_target, m_radius))
{
- if(!tmp_target->IsInPartyWith(caster))
- tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
+ if (needFriendly)
+ {
+ m_removeTime -= diff;
+ if (m_removeTime < 0)
+ m_target->RemoveAura(GetParentAura());
+ }
+ else
+ m_target->RemoveAura(GetParentAura());
}
- else if( m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER )
+ else
{
- if( tmp_target->GetGUID() != caster->GetCharmerOrOwnerGUID() )
- tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
+ // Reset aura remove timer
+ m_removeTime = FRIENDLY_AA_REMOVE_TIME;
+ if( m_areaAuraType == AREA_AURA_PARTY) // check if in same sub group
+ {
+ if(!m_target->IsInPartyWith(caster))
+ m_target->RemoveAura(GetParentAura());
+ }
+ else if( m_areaAuraType == AREA_AURA_RAID)
+ {
+ if(!m_target->IsInRaidWith(caster))
+ m_target->RemoveAura(GetParentAura());
+ }
+ else if( m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER )
+ {
+ if( m_target->GetGUID() != caster->GetCharmerOrOwnerGUID() )
+ m_target->RemoveAura(GetParentAura());
+ }
}
}
}
-void PersistentAreaAura::Update(uint32 diff)
+void PersistentAreaAuraEffect::Update(uint32 diff)
{
- bool remove = false;
-
- // remove the aura if its caster or the dynamic object causing it was removed
- // or if the target moves too far from the dynamic object
- Unit *caster = GetCaster();
- if (caster)
+ if(Unit *caster = GetParentAura()->GetCaster())
{
- DynamicObject *dynObj = caster->GetDynObject(GetId(), GetEffIndex());
- if (dynObj)
+ if(DynamicObject *dynObj = caster->GetDynObject(GetId(), GetEffIndex()))
{
- if (!m_target->IsWithinDistInMap(dynObj, dynObj->GetRadius()))
- remove = true;
+ if(m_target->IsWithinDistInMap(dynObj, dynObj->GetRadius()))
+ {
+ AuraEffect::Update(diff);
+ return;
+ }
}
- else
- remove = true;
}
- else
- remove = true;
- Unit *tmp_target = m_target;
- uint32 tmp_id = GetId(), tmp_index = GetEffIndex();
+ // remove the aura if its caster or the dynamic object causing it was removed
+ // or if the target moves too far from the dynamic object
+ m_target->RemoveAura(GetParentAura());
+}
+
+void AuraEffect::ApplyModifier(bool apply, bool Real, bool changeAmount)
+{
+ if (GetParentAura()->IsRemoved())
+ return;
- // WARNING: the aura may get deleted during the update
- // DO NOT access its members after update!
- Aura::Update(diff);
+ if(m_auraName<TOTAL_AURAS)
+ (*this.*AuraHandler [m_auraName])(apply,Real, changeAmount);
+}
- if(remove)
- tmp_target->RemoveAura(tmp_id, tmp_index);
+void AuraEffect::RecalculateAmount(bool applied)
+{
+ Unit *caster = GetParentAura()->GetCaster();
+ int32 amount = GetParentAura()->GetStackAmount() * (caster ? caster->CalculateSpellDamage(m_spellProto, GetEffIndex(), GetBasePoints(), NULL) : GetBasePoints());
+ // Reapply if amount change
+ if (amount!=GetAmount())
+ {
+ // Auras which are applying spellmod should have removed spellmods for real
+ if (applied)
+ ApplyModifier(false,false,true);
+ SetAmount(amount);
+ if (applied)
+ ApplyModifier(true,false,true);
+ }
}
-void Aura::ApplyModifier(bool apply, bool Real)
+void AuraEffect::CleanupTriggeredSpells()
{
- AuraType aura = m_modifier.m_auraname;
+ uint32 tSpellId = m_spellProto->EffectTriggerSpell[GetEffIndex()];
+ if(!tSpellId)
+ return;
- m_in_use = true;
- if(aura<TOTAL_AURAS)
- (*this.*AuraHandler [aura])(apply,Real);
- m_in_use = false;
+ SpellEntry const* tProto = sSpellStore.LookupEntry(tSpellId);
+ if(!tProto)
+ return;
+
+ if(GetSpellDuration(tProto) != -1)
+ return;
+
+ // needed for spell 43680, maybe others
+ // TODO: is there a spell flag, which can solve this in a more sophisticated way?
+ if(m_spellProto->EffectApplyAuraName[GetEffIndex()] == SPELL_AURA_PERIODIC_TRIGGER_SPELL &&
+ GetSpellDuration(m_spellProto) == m_spellProto->EffectAmplitude[GetEffIndex()])
+ return;
+
+ m_target->RemoveAurasDueToSpell(tSpellId, GetCasterGUID());
+}
+
+void Aura::ApplyAllModifiers(bool apply, bool Real)
+{
+ for (uint8 i = 0; i<MAX_SPELL_EFFECTS;++i)
+ if (m_partAuras[i])
+ m_partAuras[i]->ApplyModifier(apply, Real);
}
-void Aura::UpdateAuraDuration()
+void Aura::SendAuraUpdate()
{
- if(m_auraSlot >= MAX_AURAS || m_isPassive)
+ if (m_auraSlot>=MAX_AURAS)
return;
+ WorldPacket data(SMSG_AURA_UPDATE);
- if( m_target->GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_UPDATE_AURA_DURATION, 5);
- data << (uint8)m_auraSlot << (uint32)m_duration;
- ((Player*)m_target)->SendDirectMessage(&data);
+ data.append(m_target->GetPackGUID());
+ data << uint8(m_auraSlot);
- data.Initialize(SMSG_SET_EXTRA_AURA_INFO, (8+1+4+4+4));
- data.append(m_target->GetPackGUID());
- data << uint8(m_auraSlot);
- data << uint32(GetId());
- data << uint32(GetAuraMaxDuration());
- data << uint32(GetAuraDuration());
- ((Player*)m_target)->SendDirectMessage(&data);
+ if(!m_target->GetVisibleAura(m_auraSlot))
+ {
+ data << uint32(0);
+ sLog.outDebug("Aura %u removed slot %u",GetId(), m_auraSlot);
+ m_target->SendMessageToSet(&data, true);
+ return;
}
- // not send in case player loading (will not work anyway until player not added to map), sent in visibility change code
- if(m_target->GetTypeId() == TYPEID_PLAYER && ((Player*)m_target)->GetSession()->PlayerLoading())
- return;
+ data << uint32(GetId());
+ data << uint8(m_auraFlags);
+ data << uint8(m_auraLevel);
+ data << uint8(m_stackAmount>1 ? m_stackAmount : m_procCharges);
- Unit* caster = GetCaster();
+ if(!(m_auraFlags & AFLAG_CASTER))
+ {
+ if (Unit * caster = GetCaster())
+ data.append(caster->GetPackGUID());
+ else
+ data << uint8(0);
+ }
- if(caster && caster->GetTypeId() == TYPEID_PLAYER)
+ if(m_auraFlags & AFLAG_DURATION)
{
- SendAuraDurationForCaster((Player*)caster);
+ data << uint32(m_maxduration);
+ data << uint32(m_duration);
+ }
+
+ m_target->SendMessageToSet(&data, true);
+}
+
+bool Aura::IsVisible() const
+{
+ // passive auras (except totem auras) do not get placed in the slots
+ // area auras with SPELL_AURA_NONE are not shown on target
+ //(m_spellProto->Attributes & 0x80 && GetTalentSpellPos(GetId()))
- Group* CasterGroup = ((Player*)caster)->GetGroup();
- if (CasterGroup && (spellmgr.GetSpellCustomAttr(GetId()) & SPELL_ATTR_CU_AURA_CC))
+ if(!m_isPassive)
+ return true;
+
+ bool noneAreaAura = true;
+ for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if(m_partAuras[i])
{
- for (GroupReference *itr = CasterGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ if(m_partAuras[i]->IsAreaAura())
{
- Player* player = itr->getSource();
- if(player && player != caster)
- SendAuraDurationForCaster(player);
+ if(WorldObject *source = m_partAuras[i]->GetSource())
+ if(source->GetTypeId() == TYPEID_UNIT && ((Creature*)source)->isTotem())
+ return true;
+
+ if(m_partAuras[i]->GetAuraName() != SPELL_AURA_NONE)
+ noneAreaAura = false;
}
+ else
+ noneAreaAura = false;
}
}
-}
-void Aura::SendAuraDurationForCaster(Player* caster)
-{
- if (caster == m_target)
- return;
+ if(noneAreaAura)
+ return false;
- WorldPacket data(SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE, (8+1+4+4+4));
- data.append(m_target->GetPackGUID());
- data << uint8(m_auraSlot);
- data << uint32(GetId());
- data << uint32(GetAuraMaxDuration()); // full
- data << uint32(GetAuraDuration()); // remain
- caster->GetSession()->SendPacket(&data);
+ return IsAuraType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
}
void Aura::_AddAura()
@@ -812,334 +980,645 @@ void Aura::_AddAura()
if(!m_target)
return;
- // we can found aura in NULL_AURA_SLOT and then need store state instead check slot != NULL_AURA_SLOT
- bool secondaura = false;
- uint8 slot = NULL_AURA_SLOT;
+ Unit* caster = GetCaster();
+
+ // set infinity cooldown state for spells
+ if(caster && caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (m_spellProto->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
+ {
+ Item* castItem = m_castItemGuid ? ((Player*)caster)->GetItemByGuid(m_castItemGuid) : NULL;
+ ((Player*)caster)->AddSpellAndCategoryCooldowns(m_spellProto,castItem ? castItem->GetEntry() : 0, NULL,true);
+ }
+ }
- for(uint8 i = 0; i < 3; i++)
+ if(IsVisible())
{
- Unit::spellEffectPair spair = Unit::spellEffectPair(GetId(), i);
- for(Unit::AuraMap::const_iterator itr = m_target->GetAuras().lower_bound(spair); itr != m_target->GetAuras().upper_bound(spair); ++itr)
+ // Try find slot for aura
+ uint8 slot = MAX_AURAS;
+ // Lookup for auras already applied from spell
+ if (Aura * foundAura = m_target->GetAura(GetId(), GetCasterGUID()))
{
// allow use single slot only by auras from same caster
- if(itr->second->GetCasterGUID()==GetCasterGUID())
+ slot = foundAura->GetAuraSlot();
+ }
+ else
+ {
+ Unit::VisibleAuraMap const * visibleAuras= m_target->GetVisibleAuras();
+ // lookup for free slots in units visibleAuras
+ Unit::VisibleAuraMap::const_iterator itr = visibleAuras->find(0);
+ for(uint32 freeSlot = 0; freeSlot < MAX_AURAS; ++itr , ++freeSlot)
{
- secondaura = true;
- slot = itr->second->GetAuraSlot();
- break;
+ if(itr == visibleAuras->end() || itr->first != freeSlot)
+ {
+ slot = freeSlot;
+ break;
+ }
}
}
- if(secondaura)
- break;
+ // Register Visible Aura
+ if(slot < MAX_AURAS)
+ {
+ m_auraFlags |= (IsPositive() ? AFLAG_POSITIVE : AFLAG_NEGATIVE) |
+ (GetCasterGUID() == m_target->GetGUID() ? AFLAG_CASTER : AFLAG_NONE) |
+ (GetAuraMaxDuration() > 0 ? AFLAG_DURATION : AFLAG_NONE);
+ m_auraLevel = (caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
+ SetAuraSlot( slot );
+ m_target->SetVisibleAura(slot, this);
+ m_target->UpdateAuraForGroup(slot);
+ SendAuraUpdate();
+ sLog.outDebug("Aura: %u Effect: %d put to unit visible auras slot: %u",GetId(), GetEffectMask(), slot);
+ }
+ else
+ sLog.outDebug("Aura: %u Effect: %d could not find empty unit visible slot",GetId(), GetEffectMask());
}
- Unit* caster = GetCaster();
-
- // not call total regen auras at adding
- switch (m_modifier.m_auraname)
- {
- /*case SPELL_AURA_PERIODIC_DAMAGE:
- case SPELL_AURA_PERIODIC_LEECH:
- if(caster)
- m_modifier.m_amount = caster->SpellDamageBonus(m_target, m_spellProto, m_modifier.m_amount, DOT);
- break;
- case SPELL_AURA_PERIODIC_HEAL:
- if(caster)
- m_modifier.m_amount = caster->SpellHealingBonus(m_spellProto, m_modifier.m_amount, DOT, m_target);
- break;*/
- case SPELL_AURA_OBS_MOD_HEALTH:
- case SPELL_AURA_OBS_MOD_MANA:
- m_periodicTimer = m_modifier.periodictime;
- break;
- case SPELL_AURA_MOD_REGEN:
- case SPELL_AURA_MOD_POWER_REGEN:
- case SPELL_AURA_MOD_MANA_REGEN_FROM_STAT:
- m_periodicTimer = 5000;
- break;
- }
+ // Sitdown on apply aura req seated
+ if (m_spellProto->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED && !m_target->IsSitState())
+ m_target->SetStandState(UNIT_STAND_STATE_SIT);
- // register aura
+ // register aura diminishing on apply
if (getDiminishGroup() != DIMINISHING_NONE )
m_target->ApplyDiminishingAura(getDiminishGroup(),true);
- // passive auras (except totem auras) do not get placed in the slots
- // area auras with SPELL_AURA_NONE are not shown on target
- if((!m_isPassive || (caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem())) &&
- (m_spellProto->Effect[GetEffIndex()] != SPELL_EFFECT_APPLY_AREA_AURA_ENEMY || m_target != caster))
+ // Apply linked auras (On first aura apply)
+ uint32 id = GetId();
+ if(spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_AURA)
{
- if(!secondaura) // new slot need
- {
- if (IsPositive()) // empty positive slot
+ if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(id + SPELL_LINK_AURA))
+ for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
{
- for (uint8 i = 0; i < MAX_POSITIVE_AURAS; i++)
- {
- if (m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + i)) == 0)
- {
- slot = i;
- break;
- }
- }
- }
- else // empty negative slot
- {
- for (uint8 i = MAX_POSITIVE_AURAS; i < MAX_AURAS; i++)
- {
- if (m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + i)) == 0)
- {
- slot = i;
- break;
- }
- }
+ if(*itr < 0)
+ m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), true);
+ else if(Unit* caster = GetCaster())
+ caster->AddAura(*itr, m_target);
}
+ }
- SetAuraSlot( slot );
+ //*****************************************************
+ // Update target aura state flag
+ //*****************************************************
- // Not update fields for not first spell's aura, all data already in fields
- if(slot < MAX_AURAS) // slot found
- {
- SetAura(slot, false);
- SetAuraFlag(slot, true);
- SetAuraLevel(slot,caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
- UpdateAuraCharges();
+ // Update Seals information
+ if (IsSealSpell(m_spellProto))
+ SetAuraState(AURA_STATE_JUDGEMENT);
- // update for out of range group members
- m_target->UpdateAuraForGroup(slot);
- }
- }
- else // use found slot
- {
- SetAuraSlot( slot );
- }
+ // Conflagrate aura state on Immolate or Shadowflame
+ if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && (m_spellProto->SpellFamilyFlags[0] & 4
+ || m_spellProto->SpellFamilyFlags[2] & 2))
+ SetAuraState(AURA_STATE_IMMOLATE);
+
+ // Faerie Fire (druid versions)
+ if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[0] & 0x400)
+ SetAuraState(AURA_STATE_FAERIE_FIRE);
- UpdateSlotCounterAndDuration();
+ // Victorious
+ if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags[1] & 0x00040000)
+ SetAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH);
- // Update Seals information
- if( IsSealSpell(GetSpellProto()) )
- m_target->ModifyAuraState(AURA_STATE_JUDGEMENT, true);
+ // Swiftmend state on Regrowth & Rejuvenation
+ if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[0] & 0x50 )
+ SetAuraState(AURA_STATE_SWIFTMEND);
- // Conflagrate aura state
- if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 4))
- m_target->ModifyAuraState(AURA_STATE_IMMOLATE, true);
+ // Deadly poison aura state
+ if(m_spellProto->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellProto->SpellFamilyFlags[0] & 0x10000)
+ SetAuraState(AURA_STATE_DEADLY_POISON);
- if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
- && (GetSpellProto()->SpellFamilyFlags == 0x40 || GetSpellProto()->SpellFamilyFlags == 0x10))
+ // Enrage aura state
+ if(m_spellProto->Dispel == DISPEL_ENRAGE)
+ SetAuraState(AURA_STATE_ENRAGE);
+
+ if(GetSpellSchoolMask(m_spellProto) & SPELL_SCHOOL_MASK_FROST)
+ {
+ for (uint8 i = 0;i<MAX_SPELL_EFFECTS;++i)
{
- m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, true);
+ if (m_spellProto->EffectApplyAuraName[i]==SPELL_AURA_MOD_STUN
+ || m_spellProto->EffectApplyAuraName[i]==SPELL_AURA_MOD_ROOT)
+ {
+ SetAuraState(AURA_STATE_FROZEN);
+ break;
+ }
}
}
+
+ m_target->ApplyModFlag(UNIT_FIELD_AURASTATE, GetAuraStateMask(), true);
+}
+
+bool Aura::SetPartAura(AuraEffect* aurEff, uint8 effIndex)
+{
+ if (IsRemoved())
+ return false;
+ if (m_auraFlags & (1<<effIndex))
+ return false;
+ m_auraFlags |= 1<<effIndex;
+ m_partAuras[effIndex]=aurEff;
+ m_target->HandleAuraEffect(aurEff, true);
+ SendAuraUpdate();
+ return true;
}
void Aura::_RemoveAura()
{
Unit* caster = GetCaster();
- if(caster && IsPersistent())
+ uint8 slot = GetAuraSlot();
+
+ if (Aura * foundAura = m_target->GetAura(GetId(), GetCasterGUID()))
+ {
+ // allow use single slot only by auras from same caster
+ slot = foundAura->GetAuraSlot();
+ if(slot < MAX_AURAS) // slot not set
+ if (Aura *entry = m_target->GetVisibleAura(slot))
+ {
+ // set not valid slot for aura - prevent removing other visible aura
+ slot = MAX_AURAS;
+ }
+ }
+
+ // update for out of range group members
+ if (slot < MAX_AURAS)
{
- DynamicObject *dynObj = caster->GetDynObject(GetId(), GetEffIndex());
- if (dynObj)
- dynObj->RemoveAffected(m_target);
+ m_target->RemoveVisibleAura(slot);
+ m_target->UpdateAuraForGroup(slot);
+ SendAuraUpdate();
}
- // unregister aura
+ // unregister aura diminishing (and store last time)
if (getDiminishGroup() != DIMINISHING_NONE )
m_target->ApplyDiminishingAura(getDiminishGroup(),false);
- //passive auras do not get put in slots
- // Note: but totem can be not accessible for aura target in time remove (to far for find in grid)
- //if(m_isPassive && !(caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem()))
- // return;
-
- uint8 slot = GetAuraSlot();
-
- if(slot >= MAX_AURAS) // slot not set
- return;
+ // Check needed only if aura applies aurastate
+ if(GetAuraStateMask())
+ {
+ uint32 foundMask = 0;
+ Unit::AuraMap& Auras = m_target->GetAuras();
+ // Get mask of all aurastates from remaining auras
+ for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
+ {
+ foundMask|=(*i).second->GetAuraStateMask();
+ }
+ // Remove only aurastates which were not found
+ foundMask = GetAuraStateMask() &~foundMask;
+ if (foundMask)
+ m_target->ApplyModFlag(UNIT_FIELD_AURASTATE, foundMask, false);
+ }
- if(m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + slot)) == 0)
- return;
+ // since now aura cannot apply/remove it's modifiers
+ m_isRemoved = true;
+ // disable client server communication for removed aura
+ SetAuraSlot(MAX_AURAS);
- bool samespell = false;
+ // reset cooldown state for spells
+ if(caster && caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ if ( GetSpellProto()->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE )
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
+ ((Player*)caster)->SendCooldownEvent(GetSpellProto());
+ }
+ uint32 id = GetId();
+ // Remove Linked Auras
+ if(m_removeMode!=AURA_REMOVE_BY_STACK && m_removeMode!=AURA_REMOVE_BY_DEATH && spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_REMOVE)
+ {
+ if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(-(int32)id))
+ for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
+ {
+ if(*itr < 0)
+ m_target->RemoveAurasDueToSpell(-(*itr));
+ else if(Unit* caster = GetCaster())
+ if (m_removeMode!=AURA_REMOVE_BY_DEFAULT)
+ m_target->CastSpell(m_target, *itr, true, 0, 0, caster->GetGUID());
+ }
+ }
+ if(m_removeMode!=AURA_REMOVE_BY_STACK && m_removeMode!=AURA_REMOVE_BY_DEATH && spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_AURA)
+ {
+ if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(id + SPELL_LINK_AURA))
+ for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
+ {
+ if(*itr < 0)
+ m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), false);
+ else
+ m_target->RemoveAurasDueToSpell(*itr);
+ }
+ }
- // find other aura in same slot (current already removed from list)
- for(uint8 i = 0; i < 3; i++)
+ // Proc on aura remove (only spell flags for now)
+ if (caster)
{
- Unit::spellEffectPair spair = Unit::spellEffectPair(GetId(), i);
- for(Unit::AuraMap::const_iterator itr = m_target->GetAuras().lower_bound(spair); itr != m_target->GetAuras().upper_bound(spair); ++itr)
+ uint32 procEx=0;
+ if (m_removeMode == AURA_REMOVE_BY_ENEMY_SPELL)
+ procEx = PROC_EX_AURA_REMOVE_DESTROY;
+ else if (m_removeMode == AURA_REMOVE_BY_EXPIRE || m_removeMode == AURA_REMOVE_BY_CANCEL)
+ procEx = PROC_EX_AURA_REMOVE_EXPIRE;
+ if (procEx)
{
- if(itr->second->GetAuraSlot()==slot)
+ uint32 ProcCaster, ProcVictim;
+ if (IsPositiveSpell(GetId()))
{
- samespell = true;
+ ProcCaster = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;
+ ProcVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL;
+ }
+ else
+ {
+ ProcCaster = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
+ ProcVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
+ }
+ caster->ProcDamageAndSpell(m_target,ProcCaster, ProcVictim, procEx, m_procDamage, BASE_ATTACK, m_spellProto);
+ }
+ }
+}
- break;
+void Aura::SetStackAmount(uint8 stackAmount, bool applied)
+{
+ if (stackAmount != m_stackAmount)
+ {
+ m_stackAmount = stackAmount;
+ for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i)
+ {
+ if (AuraEffect * part = GetPartAura(i))
+ {
+ part->RecalculateAmount(applied);
}
}
- if(samespell)
- break;
}
+ RefreshAura();
+}
+
+bool Aura::modStackAmount(int32 num)
+{
+ // Can`t mod
+ if (!m_spellProto->StackAmount)
+ return true;
- // only remove icon when the last aura of the spell is removed (current aura already removed from list)
- if (!samespell)
+ // Modify stack but limit it
+ int32 stackAmount = m_stackAmount + num;
+ if (stackAmount > m_spellProto->StackAmount)
+ stackAmount = m_spellProto->StackAmount;
+ else if (stackAmount <=0) // Last aura from stack removed
{
- SetAura(slot, true);
- SetAuraFlag(slot, false);
- SetAuraLevel(slot,caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
+ m_stackAmount = 0;
+ return true; // need remove aura
+ }
- SetAuraApplication(slot, 0);
- // update for out of range group members
- m_target->UpdateAuraForGroup(slot);
+ // Update stack amount
+ SetStackAmount(stackAmount);
+ return false;
+}
- if( IsSealSpell(GetSpellProto()) )
- m_target->ModifyAuraState(AURA_STATE_JUDGEMENT,false);
+void Aura::SetAuraDuration(int32 duration, bool withMods)
+{
+ if (withMods)
+ {
+ if (Player * modOwner = m_target->GetSpellModOwner())
+ modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration);
+ }
+ m_duration = duration;
+ //if (duration<0)
+ //m_permanent=true;
+ //else
+ //m_permanent=false;
+ SendAuraUpdate();
+}
- // Conflagrate aura state
- if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 4))
- m_target->ModifyAuraState(AURA_STATE_IMMOLATE, false);
+void Aura::SetAuraCharges(uint8 charges)
+{
+ if (m_procCharges == charges)
+ return;
+ m_procCharges = charges;
+ SendAuraUpdate();
+}
- // Swiftmend aura state
- if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
- && (GetSpellProto()->SpellFamilyFlags == 0x40 || GetSpellProto()->SpellFamilyFlags == 0x10))
- {
- bool found = false;
- Unit::AuraList const& RejorRegr = m_target->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
- for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
- {
- if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
- && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
- {
- found = true;
- break;
- }
- }
- if(!found)
- m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, false);
- }
+void Aura::DropAuraCharge()
+{
+ if(m_procCharges) //auras without charges always have charge = 0
+ {
+ if(--m_procCharges) // Send charge change
+ SendAuraUpdate();
+ else // Last charge dropped
+ m_target->RemoveAura(this, AURA_REMOVE_BY_EXPIRE);
+ }
+}
- // reset cooldown state for spells
- if(caster && caster->GetTypeId() == TYPEID_PLAYER)
- {
- if ( GetSpellProto()->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE )
- ((Player*)caster)->SendCooldownEvent(GetSpellProto());
- }
+bool Aura::IsPersistent() const
+{
+ for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if(m_partAuras[i] && m_partAuras[i]->IsPersistent())
+ return true;
}
+ return false;
}
-void Aura::SetAuraFlag(uint32 slot, bool add)
+bool Aura::IsAreaAura() const
{
- uint32 index = slot / 4;
- uint32 byte = (slot % 4) * 8;
- uint32 val = m_target->GetUInt32Value(UNIT_FIELD_AURAFLAGS + index);
- val &= ~((uint32)AFLAG_MASK << byte);
- if(add)
+ for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (IsPositive())
- val |= ((uint32)AFLAG_POSITIVE << byte);
- else
- val |= ((uint32)AFLAG_NEGATIVE << byte);
+ if(m_partAuras[i] && m_partAuras[i]->IsAreaAura())
+ return true;
}
- m_target->SetUInt32Value(UNIT_FIELD_AURAFLAGS + index, val);
+ return false;
}
-void Aura::SetAuraLevel(uint32 slot,uint32 level)
+bool Aura::IsAuraType(AuraType type) const
{
- uint32 index = slot / 4;
- uint32 byte = (slot % 4) * 8;
- uint32 val = m_target->GetUInt32Value(UNIT_FIELD_AURALEVELS + index);
- val &= ~(0xFF << byte);
- val |= (level << byte);
- m_target->SetUInt32Value(UNIT_FIELD_AURALEVELS + index, val);
+ for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if(m_partAuras[i] && m_partAuras[i]->GetAuraName() == type)
+ return true;
+ }
+ return false;
}
-void Aura::SetAuraApplication(uint32 slot, int8 count)
+void Aura::SetLoadedState(uint64 caster_guid,int32 maxduration,int32 duration,int32 charges, uint8 stackamount, int32 * amount)
{
- uint32 index = slot / 4;
- uint32 byte = (slot % 4) * 8;
- uint32 val = m_target->GetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS + index);
- val &= ~(0xFF << byte);
- val |= ((uint8(count)) << byte);
- m_target->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS + index, val);
+ m_caster_guid = caster_guid;
+ m_maxduration = maxduration;
+ m_duration = duration;
+ m_procCharges = charges;
+ m_stackAmount = stackamount;
+ for (uint8 i=0; i<MAX_SPELL_EFFECTS;++i)
+ if (m_partAuras[i])
+ m_partAuras[i]->SetAmount(amount[i]);
}
-void Aura::UpdateSlotCounterAndDuration()
+void AuraEffect::HandleShapeshiftBoosts(bool apply)
{
- uint8 slot = GetAuraSlot();
- if(slot >= MAX_AURAS)
- return;
+ uint32 spellId = 0;
+ uint32 spellId2 = 0;
+ uint32 HotWSpellId = 0;
+
+ switch(GetMiscValue())
+ {
+ case FORM_CAT:
+ spellId = 3025;
+ HotWSpellId = 24900;
+ break;
+ case FORM_TREE:
+ spellId = 5420;
+ spellId2 = 34123;
+ break;
+ case FORM_TRAVEL:
+ spellId = 5419;
+ break;
+ case FORM_AQUA:
+ spellId = 5421;
+ break;
+ case FORM_BEAR:
+ spellId = 1178;
+ spellId2 = 21178;
+ HotWSpellId = 24899;
+ break;
+ case FORM_DIREBEAR:
+ spellId = 9635;
+ spellId2 = 21178;
+ HotWSpellId = 24899;
+ break;
+ case FORM_BATTLESTANCE:
+ spellId = 21156;
+ break;
+ case FORM_DEFENSIVESTANCE:
+ spellId = 7376;
+ break;
+ case FORM_BERSERKERSTANCE:
+ spellId = 7381;
+ break;
+ case FORM_MOONKIN:
+ spellId = 24905;
+ // aura from effect trigger spell
+ spellId2 = 24907;
+ break;
+ case FORM_FLIGHT:
+ spellId = 33948;
+ spellId2 = 34764;
+ break;
+ case FORM_FLIGHT_EPIC:
+ spellId = 40122;
+ spellId2 = 40121;
+ break;
+ case FORM_METAMORPHOSIS:
+ spellId = 54817;
+ spellId2 = 54879;
+ break;
+ case FORM_SPIRITOFREDEMPTION:
+ spellId = 27792;
+ spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation.
+ break;
+ case FORM_GHOSTWOLF:
+ case FORM_AMBIENT:
+ case FORM_GHOUL:
+ case FORM_SHADOW:
+ case FORM_STEALTH:
+ case FORM_CREATURECAT:
+ case FORM_CREATUREBEAR:
+ spellId = 0;
+ break;
+ }
+
+ uint32 form = GetMiscValue()-1;
- // Three possibilities:
- // Charge = 0; Stack >= 0
- // Charge = 1; Stack >= 0
- // Charge > 1; Stack = 0
- if(m_procCharges < 2)
- SetAuraApplication(slot, m_stackAmount-1);
+ if(apply)
+ {
+ if (spellId) m_target->CastSpell(m_target, spellId, true, NULL, this );
+ if (spellId2) m_target->CastSpell(m_target, spellId2, true, NULL, this);
- UpdateAuraDuration();
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ const PlayerSpellMap& sp_list = ((Player *)m_target)->GetSpellMap();
+ for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ {
+ if(itr->second->state == PLAYERSPELL_REMOVED) continue;
+ if(itr->first==spellId || itr->first==spellId2) continue;
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
+ if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR_PASSIVE | (1<<7)))) continue;
+ if (spellInfo->Stances & (1<<form))
+ m_target->CastSpell(m_target, itr->first, true, NULL, this);
+ }
+ //LotP
+ if (((Player*)m_target)->HasSpell(17007))
+ {
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(24932);
+ if (spellInfo && spellInfo->Stances & (1<<form))
+ m_target->CastSpell(m_target, 24932, true, NULL, this);
+ }
+ // HotW
+ if (HotWSpellId)
+ {
+ Unit::AuraEffectList const& mModTotalStatPct = m_target->GetAurasByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
+ for(Unit::AuraEffectList::const_iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i)
+ {
+ if ((*i)->GetSpellProto()->SpellIconID == 240 && (*i)->GetMiscValue() == 3)
+ {
+ int32 HotWMod = (*i)->GetAmount();
+ if(GetMiscValue() == FORM_CAT)
+ HotWMod /= 2;
+
+ m_target->CastCustomSpell(m_target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ m_target->RemoveAurasDueToSpell(spellId);
+ m_target->RemoveAurasDueToSpell(spellId2);
+
+ Unit::AuraMap& tAuras = m_target->GetAuras();
+ for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
+ {
+ if (itr->second->IsRemovedOnShapeLost())
+ {
+ m_target->RemoveAura(itr);
+ }
+ else
+ {
+ ++itr;
+ }
+ }
+ }
+}
+
+bool AuraEffect::isAffectedOnSpell(SpellEntry const *spell) const
+{
+ if (!spell)
+ return false;
+ // Check family name
+ if (spell->SpellFamilyName != m_spellProto->SpellFamilyName)
+ return false;
+ // Check EffectClassMask
+ if (m_spellProto->EffectSpellClassMask[m_effIndex] & spell->SpellFamilyFlags)
+ return true;
+ return false;
+}
+
+void Aura::UnregisterSingleCastAura()
+{
+ if (IsSingleTarget())
+ {
+ Unit* caster = NULL;
+ caster = GetCaster();
+ if(caster)
+ {
+ caster->GetSingleCastAuras().remove(this);
+ }
+ else
+ {
+ sLog.outError("Couldn't find the caster of the single target aura, may crash later!");
+ assert(false);
+ }
+ m_isSingleTargetAura = false;
+ }
}
/*********************************************************/
/*** BASIC AURA FUNCTION ***/
/*********************************************************/
-void Aura::HandleAddModifier(bool apply, bool Real)
+void AuraEffect::HandleAddModifier(bool apply, bool Real, bool changeAmount)
{
- if(m_target->GetTypeId() != TYPEID_PLAYER || !Real)
+ if(m_target->GetTypeId() != TYPEID_PLAYER || (!Real && !changeAmount))
return;
- SpellEntry const *spellInfo = GetSpellProto();
- if(!spellInfo)
- return;
+ uint32 modOp = GetMiscValue();
- if(m_modifier.m_miscvalue >= MAX_SPELLMOD)
+ if(modOp >= MAX_SPELLMOD)
return;
if (apply)
{
- // Add custom charges for some mod aura
- switch (m_spellProto->Id)
- {
- case 17941: // Shadow Trance
- case 22008: // Netherwind Focus
- case 34936: // Backlash
- m_procCharges = 1;
- break;
- }
-
SpellModifier *mod = new SpellModifier;
- mod->op = SpellModOp(m_modifier.m_miscvalue);
- mod->value = GetModifierValue();
- mod->type = SpellModType(m_modifier.m_auraname); // SpellModType value == spell aura types
+ mod->op = SpellModOp(modOp);
+ mod->value = m_amount;
+ mod->type = SpellModType(m_auraName); // SpellModType value == spell aura types
mod->spellId = GetId();
- mod->effectId = m_effIndex;
- mod->lastAffected = NULL;
- uint64 spellAffectMask = spellmgr.GetSpellAffectMask(GetId(), m_effIndex);
-
- if (spellAffectMask)
- mod->mask = spellAffectMask;
- else
- mod->mask = spellInfo->EffectItemType[m_effIndex];
-
- if (m_procCharges > 0)
- mod->charges = m_procCharges;
- else
- mod->charges = 0;
+ flag96 const *spellAffect = spellmgr.GetSpellAffect(GetId(), m_effIndex);
+ if (!spellAffect)
+ spellAffect = &m_spellProto->EffectSpellClassMask[m_effIndex];
+ mod->mask = *spellAffect;
+ mod->charges = GetParentAura()->GetAuraCharges();
m_spellmod = mod;
}
- uint64 spellFamilyMask = m_spellmod->mask;
-
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
+ // Auras with charges do not mod amount of passive auras
+ if (GetParentAura()->GetAuraCharges())
+ return;
// reapply some passive spells after add/remove related spellmods
- if(spellInfo->SpellFamilyName==SPELLFAMILY_WARRIOR && (spellFamilyMask & 0x0000100000000000LL))
+ // Warning: it is a dead loop if 2 auras each other amount-shouldn't happen
+ switch (modOp)
+ {
+ case SPELLMOD_ALL_EFFECTS:
+ case SPELLMOD_EFFECT1:
+ case SPELLMOD_EFFECT2:
+ case SPELLMOD_EFFECT3:
+ {
+ uint64 guid = m_target->GetGUID();
+ Unit::AuraMap & auras = m_target->GetAuras();
+ for(Unit::AuraMap::iterator iter = auras.begin(); iter != auras.end();++iter)
+ {
+ Aura * aur = iter->second;
+ // only passive auras-active auras should have amount set on spellcast and not be affected
+ // if aura is casted by others, it will not be affected
+ if (aur->IsPassive() && aur->GetCasterGUID() == guid && isAffectedOnSpell(aur->GetSpellProto()))
+ {
+ if (modOp == SPELLMOD_ALL_EFFECTS)
+ {
+ for (uint8 i = 0; i<MAX_SPELL_EFFECTS;++i)
+ {
+ if (AuraEffect * aurEff = aur->GetPartAura(i))
+ aurEff->RecalculateAmount();
+ }
+ }
+ else if (modOp ==SPELLMOD_EFFECT1)
+ {
+ if (AuraEffect * aurEff = aur->GetPartAura(0))
+ aurEff->RecalculateAmount();
+ }
+ else if (modOp ==SPELLMOD_EFFECT2)
+ {
+ if (AuraEffect * aurEff = aur->GetPartAura(1))
+ aurEff->RecalculateAmount();
+ }
+ else //if (modOp ==SPELLMOD_EFFECT3)
+ {
+ if (AuraEffect * aurEff = aur->GetPartAura(2))
+ aurEff->RecalculateAmount();
+ }
+ }
+ }
+ }
+ default:
+ break;
+ }
+}
+void AuraEffect::HandleAddTargetTrigger(bool apply, bool Real, bool /*changeAmount*/)
+{
+ // Use SpellModifier structure for check
+ // used only fields:
+ // spellId, mask, mask2
+ if (apply)
{
- m_target->RemoveAurasDueToSpell(45471);
+ SpellModifier *mod = new SpellModifier;
+ mod->spellId = GetId();
- if(apply)
- m_target->CastSpell(m_target,45471,true);
+ flag96 const *spellAffect = spellmgr.GetSpellAffect(GetId(), m_effIndex);
+ if (!spellAffect)
+ spellAffect = &m_spellProto->EffectSpellClassMask[m_effIndex];
+
+ mod->mask = *spellAffect;
+ m_spellmod = mod;
+ }
+ else
+ {
+ delete m_spellmod;
+ m_spellmod = NULL;
}
}
-void Aura::TriggerSpell()
+void AuraEffect::TriggerSpell()
{
Unit* caster = GetCaster();
Unit* target = GetTriggerTarget();
@@ -1150,8 +1629,6 @@ void Aura::TriggerSpell()
// generic casting code with custom spells and target/caster customs
uint32 trigger_spell_id = GetSpellProto()->EffectTriggerSpell[m_effIndex];
- uint64 originalCasterGUID = GetCasterGUID();
-
SpellEntry const *triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
SpellEntry const *auraSpellInfo = GetSpellProto();
uint32 auraId = auraSpellInfo->Id;
@@ -1190,7 +1667,7 @@ void Aura::TriggerSpell()
}
// remove old enchanting before applying new
((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false);
- item->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, m_modifier.periodictime+1000, 0);
+ item->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, m_amplitude+1000, 0);
// add new enchanting
((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,true);
return;
@@ -1236,8 +1713,7 @@ void Aura::TriggerSpell()
case 23493:
{
int32 heal = caster->GetMaxHealth() / 10;
- caster->ModifyHealth( heal );
- caster->SendHealSpellLog(caster, 23493, heal);
+ caster->DealHeal(caster, heal, auraSpellInfo);
int32 mana = caster->GetMaxPower(POWER_MANA);
if (mana)
@@ -1246,7 +1722,7 @@ void Aura::TriggerSpell()
caster->ModifyPower( POWER_MANA, mana );
caster->SendEnergizeSpellLog(caster, 23493, mana, POWER_MANA);
}
- break;
+ return;
}
// // Stoneclaw Totem Passive TEST
// case 23792: break;
@@ -1303,10 +1779,21 @@ void Aura::TriggerSpell()
} break;
// // Steam Tank Passive
// case 27747: break;
-// // Frost Blast
-// case 27808: break;
-// // Detonate Mana
-// case 27819: break;
+ // Frost Blast
+ case 27808:
+ caster->CastCustomSpell(29879, SPELLVALUE_BASE_POINT0, target->GetMaxHealth()*0.26f, m_target, true, NULL, this);
+ return;
+ // Detonate Mana
+ case 27819:
+ {
+ int32 mana = (uint32)m_target->GetMaxPower(POWER_MANA)*0.25f;
+ if(mana)
+ {
+ mana = m_target->ModifyPower(POWER_MANA, -mana);
+ m_target->CastCustomSpell(27820, SPELLVALUE_BASE_POINT0, -mana*4, NULL, true, NULL, this, caster->GetGUID());
+ }
+ return;
+ }
// // Controller Timer
// case 28095: break;
// // Stalagg Chain
@@ -1325,8 +1812,11 @@ void Aura::TriggerSpell()
// case 28522: break;
// // Silithyst
// case 29519: break;
-// // Inoculate Nestlewood Owlkin
- case 29528: trigger_spell_id = 28713; break;
+ // Inoculate Nestlewood Owlkin
+ case 29528:
+ if(target->GetTypeId()!=TYPEID_UNIT)// prevent error reports in case ignored player target
+ return;
+ break;
// // Overload
// case 29768: break;
// // Return Fire
@@ -1359,32 +1849,15 @@ void Aura::TriggerSpell()
Creature* creature = (Creature*)target;
// missing lootid has been reported on startup - just return
if (!creature->GetCreatureInfo()->SkinLootId)
- {
return;
- }
- Loot *loot = &creature->loot;
- loot->clear();
- loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, NULL);
- for(uint8 i=0;i<loot->items.size();i++)
- {
- LootItem *item = loot->LootItemInSlot(i,player);
- ItemPosCountVec dest;
- uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item->itemid, item->count );
- if ( msg == EQUIP_ERR_OK )
- {
- Item * newitem = player->StoreNewItem( dest, item->itemid, true, item->randomPropertyId);
-
- player->SendNewItem(newitem, uint32(item->count), false, false, true);
- }
- else
- player->SendEquipError( msg, NULL, NULL );
- }
+
+ player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId,LootTemplates_Skinning,true);
+
creature->setDeathState(JUST_DIED);
creature->RemoveCorpse();
creature->SetHealth(0); // just for nice GM-mode view
}
return;
- break;
}
// Quake
case 30576: trigger_spell_id = 30571; break;
@@ -1404,7 +1877,7 @@ void Aura::TriggerSpell()
// Doom
case 31347:
{
- m_target->CastSpell(m_target,31350,true);
+ m_target->CastSpell(m_target,31350,true, NULL, this);
m_target->DealDamage(m_target, m_target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
return;
}
@@ -1434,9 +1907,9 @@ void Aura::TriggerSpell()
{
// cast 24 spells 34269-34289, 34314-34316
for(uint32 spell_id = 34269; spell_id != 34290; ++spell_id)
- caster->CastSpell(m_target,spell_id,true);
+ caster->CastSpell(m_target,spell_id,true, NULL, this);
for(uint32 spell_id = 34314; spell_id != 34317; ++spell_id)
- caster->CastSpell(m_target,spell_id,true);
+ caster->CastSpell(m_target,spell_id,true, NULL, this);
return;
}
// // Gravity Lapse
@@ -1518,7 +1991,7 @@ void Aura::TriggerSpell()
// Eye of Grillok
case 38495:
{
- m_target->CastSpell(m_target, 38530, true);
+ m_target->CastSpell(m_target, 38530, true, NULL, this);
return;
}
// Absorb Eye of Grillok (Zezzak's Shard)
@@ -1527,7 +2000,7 @@ void Aura::TriggerSpell()
if(m_target->GetTypeId() != TYPEID_UNIT)
return;
- caster->CastSpell(caster, 38495, true);
+ caster->CastSpell(caster, 38495, true, NULL, this);
Creature* creatureTarget = (Creature*)m_target;
@@ -1587,13 +2060,13 @@ void Aura::TriggerSpell()
// Aura of Desire
case 41350:
{
- Unit::AuraList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT);
- for(Unit::AuraList::const_iterator i = mMod.begin(); i != mMod.end(); ++i)
+ Unit::AuraEffectList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT);
+ for(Unit::AuraEffectList::const_iterator i = mMod.begin(); i != mMod.end(); ++i)
{
if ((*i)->GetId() == 41350)
{
(*i)->ApplyModifier(false);
- (*i)->GetModifier()->m_amount -= 5;
+ (*i)->SetAmount((*i)->GetAmount()-5);
(*i)->ApplyModifier(true);
break;
}
@@ -1634,11 +2107,8 @@ void Aura::TriggerSpell()
{
// Invisibility
case 66:
- {
- if(!m_duration)
- m_target->CastSpell(m_target, 32612, true, NULL, this);
+ // Here need periodic triger reducing threat spell (or do it manually)
return;
- }
default:
break;
}
@@ -1684,7 +2154,7 @@ void Aura::TriggerSpell()
case 22896:
case 26999:
{
- int32 LifePerRage = GetModifier()->m_amount;
+ int32 LifePerRage = GetAmount();
int32 lRage = m_target->GetPower(POWER_RAGE);
if(lRage > 100) // rage stored as rage*10
@@ -1748,7 +2218,7 @@ void Aura::TriggerSpell()
{
SpellEntry const* spell = itr->second->GetSpellProto();
if( spell->SpellFamilyName == SPELLFAMILY_SHAMAN &&
- spell->SpellFamilyFlags & 0x0000000000000400L)
+ spell->SpellFamilyFlags[0] & 0x400)
return;
}
target->RemoveAurasDueToSpell(28820);
@@ -1758,9 +2228,9 @@ void Aura::TriggerSpell()
case 38443:
{
bool all = true;
- for(int i = 0; i < MAX_TOTEM; ++i)
+ for(int i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
{
- if(!caster->m_TotemSlot[i])
+ if(!caster->m_SummonSlot[i])
{
all = false;
break;
@@ -1768,7 +2238,7 @@ void Aura::TriggerSpell()
}
if(all)
- caster->CastSpell(caster,38437,true);
+ caster->CastSpell(caster,38437,true, NULL, this);
else
caster->RemoveAurasDueToSpell(38437);
return;
@@ -1781,13 +2251,9 @@ void Aura::TriggerSpell()
default:
break;
}
+
// Reget trigger spell proto
triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
- if(triggeredSpellInfo == NULL)
- {
- sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex());
- return;
- }
}
else
{
@@ -1804,22 +2270,22 @@ void Aura::TriggerSpell()
// 2) maybe aura must be replace by new with accumulative stat mods instead stacking
// prevent cast by triggered auras
- if(m_caster_guid == m_target->GetGUID())
+ if(GetCasterGUID() == m_target->GetGUID())
return;
// stop triggering after each affected stats lost > 90
int32 intellectLoss = 0;
int32 spiritLoss = 0;
- Unit::AuraList const& mModStat = m_target->GetAurasByType(SPELL_AURA_MOD_STAT);
- for(Unit::AuraList::const_iterator i = mModStat.begin(); i != mModStat.end(); ++i)
+ Unit::AuraEffectList const& mModStat = m_target->GetAurasByType(SPELL_AURA_MOD_STAT);
+ for(Unit::AuraEffectList::const_iterator i = mModStat.begin(); i != mModStat.end(); ++i)
{
if ((*i)->GetId() == 1010)
{
- switch((*i)->GetModifier()->m_miscvalue)
+ switch((*i)->GetMiscValue())
{
- case STAT_INTELLECT: intellectLoss += (*i)->GetModifierValue(); break;
- case STAT_SPIRIT: spiritLoss += (*i)->GetModifierValue(); break;
+ case STAT_INTELLECT: intellectLoss += (*i)->GetAmount(); break;
+ case STAT_SPIRIT: spiritLoss += (*i)->GetAmount(); break;
default: break;
}
}
@@ -1829,54 +2295,87 @@ void Aura::TriggerSpell()
return;
caster = target;
- originalCasterGUID = 0;
break;
}
// Mana Tide
case 16191:
{
- caster->CastCustomSpell(target, trigger_spell_id, &m_modifier.m_amount, NULL, NULL, true, NULL, this, originalCasterGUID);
+ caster->CastCustomSpell(target, trigger_spell_id, &m_amount, NULL, NULL, true, NULL, this);
return;
}
// Negative Energy Periodic
case 46284:
- {
- caster->CastCustomSpell(trigger_spell_id, SPELLVALUE_MAX_TARGETS, m_tickNumber / 10 + 1, NULL, true, NULL, this, originalCasterGUID);
+ caster->CastCustomSpell(trigger_spell_id, SPELLVALUE_MAX_TARGETS, m_tickNumber / 10 + 1, NULL, true, NULL, this);
+ return;
+ // Poison (Grobbulus)
+ case 28158:
+ case 54362:
+ m_target->CastCustomSpell(trigger_spell_id, SPELLVALUE_RADIUS_MOD, (int32)((((float)m_tickNumber / 60) * 0.9f + 0.1f) * 10000), NULL, true, NULL, this);
+ return;
+ // Mind Sear (target 76/16) if let m_target cast, will damage caster
+ case 48045:
+ case 53023:
+ // Curse of the Plaguebringer (22/15)
+ case 29213:
+ case 54835:
+ caster->CastSpell(m_target, trigger_spell_id, true, NULL, this);
return;
- }
}
}
- if(!GetSpellMaxRange(sSpellRangeStore.LookupEntry(triggeredSpellInfo->rangeIndex)))
- target = m_target; //for druid dispel poison
- m_target->CastSpell(target, triggeredSpellInfo, true, 0, this, originalCasterGUID);
+
+ if(triggeredSpellInfo)
+ {
+ if(!caster->GetSpellMaxRangeForTarget(m_target,sSpellRangeStore.LookupEntry(triggeredSpellInfo->rangeIndex)))
+ target = m_target; //for druid dispel poison
+ m_target->CastSpell(target, triggeredSpellInfo, true, 0, this, GetCasterGUID());
+ }
+ else if(target->GetTypeId()!=TYPEID_UNIT || !Script->EffectDummyCreature(caster, GetId(), GetEffIndex(), (Creature*)target))
+ sLog.outError("AuraEffect::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex());
}
-Unit* Aura::GetTriggerTarget() const
+Unit* AuraEffect::GetTriggerTarget() const
{
- Unit* target = ObjectAccessor::GetUnit(*m_target,
- /*m_target->GetTypeId()==TYPEID_PLAYER ?
- ((Player*)m_target)->GetSelection() :*/
- m_target->GetUInt64Value(UNIT_FIELD_TARGET));
+ Unit* target = ObjectAccessor::GetUnit(*m_target, m_target->GetUInt64Value(UNIT_FIELD_TARGET));
return target ? target : m_target;
}
+void AuraEffect::TriggerSpellWithValue()
+{
+ Unit* caster = GetCaster();
+ Unit* target = GetTriggerTarget();
+
+ if(!caster || !target)
+ return;
+
+ // generic casting code with custom spells and target/caster customs
+ uint32 trigger_spell_id = GetSpellProto()->EffectTriggerSpell[m_effIndex];
+ int32 basepoints0 = this->GetAmount();
+
+ caster->CastCustomSpell(target, trigger_spell_id, &basepoints0, 0, 0, true, 0, this);
+}
+
/*********************************************************/
/*** AURA EFFECTS ***/
/*********************************************************/
-void Aura::HandleAuraDummy(bool apply, bool Real)
+void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
{
- // spells required only Real aura add/remove
- if(!Real)
- return;
-
Unit* caster = GetCaster();
+ // spells required only Real aura add/remove
+ if (Real)
+ {
// AT APPLY
if(apply)
{
switch(GetId())
{
+ // Haunting Spirits - perdiodic trigger demon
+ case 7057:
+ m_isPeriodic = true;
+ m_amplitude = irand (0, 60) + 30;
+ m_amplitude *= IN_MILISECONDS;
+ return;
case 1515: // Tame beast
// FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness
if( caster && m_target->CanHaveThreatList())
@@ -1887,13 +2386,50 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
if(caster)
caster->CastSpell(caster,13138,true,NULL,this);
return;
+ case 34026: // kill command
+ {
+ Unit * pet = m_target->GetGuardianPet();
+ if (!pet)
+ return;
+
+ m_target->CastSpell(m_target,34027,true,NULL,this);
+
+ // set 3 stacks and 3 charges (to make all auras not disappear at once)
+ Aura* owner_aura = m_target->GetAura(34027,GetCasterGUID());
+ Aura* pet_aura = pet->GetAura(58914, GetCasterGUID());
+ if( owner_aura )
+ {
+ owner_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount);
+ }
+ if( pet_aura )
+ {
+ pet_aura->SetAuraCharges(0);
+ pet_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount);
+ }
+ return;
+ }
+ case 55198: // Tidal Force
+ {
+ m_target->CastSpell(m_target,55166,true,NULL,this);
+ // set 3 stacks and 3 charges (to make all auras not disappear at once)
+ Aura* owner_aura = m_target->GetAura(55166,GetCasterGUID());
+ if( owner_aura )
+ {
+ // This aura lasts 2 sec, need this hack to properly proc spells
+ // TODO: drop aura charges for ApplySpellMod in ProcDamageAndSpell
+ GetParentAura()->SetAuraDuration(owner_aura->GetAuraDuration());
+ // Make aura be not charged-this prevents removing charge on not crit spells
+ owner_aura->SetAuraCharges(0);
+ owner_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount);
+ }
+ return;
+ }
case 39850: // Rocket Blast
if(roll_chance_i(20)) // backfire stun
m_target->CastSpell(m_target, 51581, true, NULL, this);
return;
case 43873: // Headless Horseman Laugh
- if(caster->GetTypeId() == TYPEID_PLAYER)
- ((Player*)caster)->SendPlaySound(11965, false);
+ m_target->PlayDistanceSound(11965);
return;
case 46354: // Blood Elf Illusion
if(caster)
@@ -1918,24 +2454,26 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
}
// Earth Shield
- if ( caster && GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN && (GetSpellProto()->SpellFamilyFlags & 0x40000000000LL))
+ if ( caster && GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN && (GetSpellProto()->SpellFamilyFlags[1] & 0x400))
{
// prevent double apply bonuses
if(m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
- m_modifier.m_amount = caster->SpellHealingBonus(GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE, m_target);
+ m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_amount, SPELL_DIRECT_DAMAGE);
return;
}
+ //Druid, Survival Instincts
+ if(GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID && GetSpellProto()->SpellFamilyFlags[2]& 0x40 )
+ {
+ if(!m_target)
+ return;
+
+ int32 bp0 = int32(m_target->GetMaxHealth() * m_amount / 100);
+ m_target->CastCustomSpell(m_target, 50322, &bp0, NULL, NULL, true);
+ }
}
// AT REMOVE
else
{
- if( m_target->GetTypeId() == TYPEID_PLAYER && GetSpellProto()->Effect[0]==72 )
- {
- // spells with SpellEffect=72 and aura=4: 6196, 6197, 21171, 21425
- ((Player*)m_target)->ClearFarsight();
- return;
- }
-
if( (IsQuestTameSpell(GetId())) && caster && caster->isAlive() && m_target->isAlive())
{
uint32 finalSpelId = 0;
@@ -1989,6 +2527,37 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
m_target->SetReducedThreatPercent(0, 0);
return;
}
+
+ // Wrath of the Astromancer
+ if (GetId()==42783)
+ {
+ m_target->CastSpell(m_target,m_amount,true,NULL,this);
+ return;
+ }
+
+ switch(m_spellProto->SpellFamilyName)
+ {
+ case SPELLFAMILY_WARLOCK:
+ // Haunt
+ if(m_spellProto->SpellFamilyFlags[1] & 0x40000)
+ {
+ int32 bp0 = GetParentAura()->GetProcDamage() * m_amount / 100;
+ if(caster)
+ caster->CastCustomSpell(caster, 48210, &bp0, 0, 0, true, NULL, this);
+ return;
+ }
+ break;
+ case SPELLFAMILY_MAGE:
+ // Living Bomb
+ if(m_spellProto->SpellFamilyFlags[1] & 0x20000)
+ {
+ if(caster && (GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL || GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_DEATH || GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE))
+ caster->CastSpell(m_target, GetAmount(), true);
+ return;
+ }
+ break;
+ }
+ }
}
// AT APPLY & REMOVE
@@ -1997,105 +2566,210 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
{
case SPELLFAMILY_GENERIC:
{
- // Unstable Power
- if( GetId()==24658 )
+ if (!Real)
+ break;
+ switch(GetId())
{
- uint32 spellId = 24659;
- if (apply)
+ // Unstable Power
+ case 24658:
{
- const SpellEntry *spell = sSpellStore.LookupEntry(spellId);
- if (!spell)
+ uint32 spellId = 24659;
+ if (apply && caster)
+ {
+ const SpellEntry *spell = sSpellStore.LookupEntry(spellId);
+ if (!spell)
+ return;
+
+ for (int i=0; i < spell->StackAmount; ++i)
+ caster->CastSpell(m_target, spell->Id, true, NULL, NULL, GetCasterGUID());
return;
- for (int i=0; i < spell->StackAmount; ++i)
- caster->CastSpell(m_target, spell->Id, true, NULL, NULL, GetCasterGUID());
+ }
+ m_target->RemoveAurasDueToSpell(spellId);
return;
}
- m_target->RemoveAurasDueToSpell(spellId);
- return;
- }
- // Restless Strength
- if( GetId()==24661 )
- {
- uint32 spellId = 24662;
- if (apply)
+ // Restless Strength
+ case 24661:
{
- const SpellEntry *spell = sSpellStore.LookupEntry(spellId);
- if (!spell)
+ uint32 spellId = 24662;
+ if (apply && caster)
+ {
+ const SpellEntry *spell = sSpellStore.LookupEntry(spellId);
+ if (!spell)
+ return;
+ for (int i=0; i < spell->StackAmount; ++i)
+ caster->CastSpell(m_target, spell->Id, true, NULL, NULL, GetCasterGUID());
return;
- for (int i=0; i < spell->StackAmount; ++i)
- caster->CastSpell(m_target, spell->Id, true, NULL, NULL, GetCasterGUID());
+ }
+ m_target->RemoveAurasDueToSpell(spellId);
return;
}
- m_target->RemoveAurasDueToSpell(spellId);
- return;
- }
- // Victorious
- if(GetId()==32216 && m_target->getClass()==CLASS_WARRIOR)
- {
- m_target->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, apply);
- return;
- }
- //Summon Fire Elemental
- if (GetId() == 40133 && caster)
- {
- Unit *owner = caster->GetOwner();
- if (owner && owner->GetTypeId() == TYPEID_PLAYER)
+ //Summon Fire Elemental
+ case 40133:
{
- if(apply)
- owner->CastSpell(owner,8985,true);
- else
- ((Player*)owner)->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
- }
- return;
- }
+ if (!caster)
+ return;
- //Summon Earth Elemental
- if (GetId() == 40132 && caster)
- {
- Unit *owner = caster->GetOwner();
- if (owner && owner->GetTypeId() == TYPEID_PLAYER)
+ Unit *owner = caster->GetOwner();
+ if (owner && owner->GetTypeId() == TYPEID_PLAYER)
+ {
+ if(apply)
+ owner->CastSpell(owner,8985,true);
+ else
+ ((Player*)owner)->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
+ }
+ return;
+ }
+ //Summon Earth Elemental
+ case 40132 :
{
- if(apply)
- owner->CastSpell(owner,19704,true);
- else
- ((Player*)owner)->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
+ if (!caster)
+ return;
+
+ Unit *owner = caster->GetOwner();
+ if (owner && owner->GetTypeId() == TYPEID_PLAYER)
+ {
+ if(apply)
+ owner->CastSpell(owner,19704,true);
+ else
+ ((Player*)owner)->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
+ }
+ return;
}
- return;
+ // LK Intro VO (1)
+ case 58204:
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ // Play part 1
+ if(apply)
+ m_target->PlayDirectSound(14970, (Player *)m_target);
+ // continue in 58205
+ else
+ m_target->CastSpell(m_target, 58205, true);
+ }
+ return;
+ // LK Intro VO (2)
+ case 58205:
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ // Play part 2
+ if(apply)
+ m_target->PlayDirectSound(14971, (Player *)m_target);
+ // Play part 3
+ else
+ m_target->PlayDirectSound(14972, (Player *)m_target);
+ }
+ return;
}
break;
}
case SPELLFAMILY_MAGE:
{
- // Hypothermia
- if( GetId()==41425 )
+ //if (!Real)
+ //break;
+ break;
+ }
+ case SPELLFAMILY_PRIEST:
+ {
+ if (!Real && !changeAmount)
+ break;
+ // Pain and Suffering
+ if( m_spellProto->SpellIconID == 2874 && m_target->GetTypeId()==TYPEID_PLAYER )
{
- m_target->ModifyAuraState(AURA_STATE_HYPOTHERMIA,apply);
+ if(apply)
+ {
+ // Reduce backfire damage (dot damage) from Shadow Word: Death
+ SpellModifier *mod = new SpellModifier;
+ mod->op = SPELLMOD_DOT;
+ mod->value = m_amount;
+ mod->type = SPELLMOD_PCT;
+ mod->spellId = GetId();
+ mod->mask[1] = 0x00002000;
+ m_spellmod = mod;
+ }
+ ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
return;
}
break;
}
case SPELLFAMILY_DRUID:
{
+ if (!Real && !changeAmount)
+ break;
+ switch(GetId())
+ {
+ case 34246: // Idol of the Emerald Queen
+ case 60779: // Idol of Lush Moss
+ {
+ if (m_target->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if(apply)
+ {
+ SpellModifier *mod = new SpellModifier;
+ mod->op = SPELLMOD_DOT;
+ mod->value = m_amount/7;
+ mod->type = SPELLMOD_FLAT;
+ mod->spellId = GetId();
+ mod->mask[1] = 0x0010;
+
+ m_spellmod = mod;
+ }
+
+ ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
+ return;
+ }
+ case 61336: // Survival Instincts
+ {
+ if (!Real)
+ break;
+ if(apply)
+ {
+ if (!m_target->IsInFeralForm())
+ return;
+
+ int32 bp0 = int32(m_target->GetMaxHealth() * m_amount / 100);
+ m_target->CastCustomSpell(m_target, 50322, &bp0, NULL, NULL, true);
+ }
+ else
+ m_target-> RemoveAurasDueToSpell(50322);
+ return;
+ }
+ }
+
// Lifebloom
- if ( GetSpellProto()->SpellFamilyFlags & 0x1000000000LL )
+ if ( GetSpellProto()->SpellFamilyFlags[1] & 0x10 )
{
if ( apply )
{
if ( caster )
// prevent double apply bonuses
if(m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
- m_modifier.m_amount = caster->SpellHealingBonus(GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE, m_target);
+ m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_amount, SPELL_DIRECT_DAMAGE);
}
- // Do final heal for real !apply
- else if (Real)
+ else
{
- if (GetAuraDuration() <= 0 || m_removeMode==AURA_REMOVE_BY_DISPEL)
+ // Final heal only on dispelled or duration end
+ if (GetParentAura()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetParentAura()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL)
+ return;
+
+ // final heal
+ if(m_target->IsInWorld())
+ m_target->CastCustomSpell(m_target,33778,&m_amount,NULL,NULL,true,NULL,this,GetCasterGUID());
+
+ /*// have a look if there is still some other Lifebloom dummy aura
+ Unit::AuraList auras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::iterator itr = auras.begin(); itr!=auras.end(); ++itr)
+ if((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID &&
+ (*itr)->GetSpellProto()->SpellFamilyFlags & 0x1000000000LL)
+ return;
+
+ // final heal
+ if(m_target->IsInWorld() && m_stackAmount > 0)
{
- // final heal
- if(m_target->IsInWorld())
- m_target->CastCustomSpell(m_target,33778,&m_modifier.m_amount,NULL,NULL,true,NULL,this,GetCasterGUID());
- }
+ int32 amount = m_amount / m_stackAmount;
+ m_target->CastCustomSpell(m_target,33778,&amount,NULL,NULL,true,NULL,this,GetCasterGUID());
+ }*/
}
return;
}
@@ -2106,50 +2780,27 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
((Player*)m_target)->UpdateAttackPowerAndDamage();
return;
}
- // Idol of the Emerald Queen
- if ( GetId() == 34246 && m_target->GetTypeId()==TYPEID_PLAYER )
- {
- if(apply)
- {
- SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_DOT;
- mod->value = m_modifier.m_amount/7;
- mod->type = SPELLMOD_FLAT;
- mod->spellId = GetId();
- mod->effectId = m_effIndex;
- mod->lastAffected = NULL;
- mod->mask = 0x001000000000LL;
- mod->charges = 0;
-
- m_spellmod = mod;
- }
-
- ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
- return;
- }
break;
}
case SPELLFAMILY_HUNTER:
{
- // Improved Aspect of the Viper
- if( GetId()==38390 && m_target->GetTypeId()==TYPEID_PLAYER )
+ if (!Real)
+ break;
+ // Glyph of Aspect of the Monkey
+ if(m_spellProto->Id==56833)
{
if(apply)
{
- // + effect value for Aspect of the Viper
SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_EFFECT1;
- mod->value = m_modifier.m_amount;
+ mod->op = SPELLMOD_CHANCE_OF_SUCCESS;
+ mod->value = 100;
mod->type = SPELLMOD_FLAT;
mod->spellId = GetId();
- mod->effectId = m_effIndex;
- mod->lastAffected = NULL;
- mod->mask = 0x4000000000000LL;
- mod->charges = 0;
-
+ mod->mask[2] = 8192;
+ mod->mask[1] = 0x00000000;
+ mod->mask[0] = 524288;
m_spellmod = mod;
}
-
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
return;
}
@@ -2157,6 +2808,8 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
}
case SPELLFAMILY_SHAMAN:
{
+ if (!Real && !changeAmount)
+ break;
// Improved Weapon Totems
if( GetSpellProto()->SpellIconID == 57 && m_target->GetTypeId()==TYPEID_PLAYER )
{
@@ -2164,21 +2817,18 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
{
SpellModifier *mod = new SpellModifier;
mod->op = SPELLMOD_EFFECT1;
- mod->value = m_modifier.m_amount;
+ mod->value = m_amount;
mod->type = SPELLMOD_PCT;
mod->spellId = GetId();
- mod->effectId = m_effIndex;
- mod->lastAffected = NULL;
switch (m_effIndex)
{
case 0:
- mod->mask = 0x00200000000LL; // Windfury Totem
+ mod->mask[1] = 0x002; // Windfury Totem
break;
case 1:
- mod->mask = 0x00400000000LL; // Flametongue Totem
+ mod->mask[1] = 0x004; // Flametongue Totem
break;
}
- mod->charges = 0;
m_spellmod = mod;
}
@@ -2186,16 +2836,17 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
return;
}
-
+ if (!Real)
+ break;
// Sentry Totem
if (GetId() == 6495 && caster->GetTypeId() == TYPEID_PLAYER)
{
if (apply)
{
- uint64 guid = caster->m_TotemSlot[3];
+ uint64 guid = caster->m_SummonSlot[3];
if (guid)
{
- Creature *totem = ObjectAccessor::GetCreature(*caster, guid);
+ Creature *totem = caster->GetMap()->GetCreature(guid);
if (totem && totem->isTotem())
((Player*)caster)->CastSpell(totem, 6277, true);
}
@@ -2208,54 +2859,44 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
}
}
- // pet auras
- if(PetAura const* petSpell = spellmgr.GetPetAura(GetId()))
- {
- if(apply)
- m_target->AddPetAura(petSpell);
- else
- m_target->RemovePetAura(petSpell);
- return;
- }
-}
-
-void Aura::HandleAuraPeriodicDummy(bool apply, bool Real)
-{
- // spells required only Real aura add/remove
- if(!Real)
- return;
-
- SpellEntry const*spell = GetSpellProto();
- switch( spell->SpellFamilyName)
+ if (Real)
{
- case SPELLFAMILY_ROGUE:
+ // pet auras
+ if(PetAura const* petSpell = spellmgr.GetPetAura(GetId()))
{
- // Master of Subtlety
- if (spell->Id==31666 && !apply && Real)
- {
- m_target->RemoveAurasDueToSpell(31665);
- break;
- }
- break;
+ if(apply)
+ m_target->AddPetAura(petSpell);
+ else
+ m_target->RemovePetAura(petSpell);
+ return;
}
- case SPELLFAMILY_HUNTER:
+
+ if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER)
{
- // Aspect of the Viper
- if (spell->SpellFamilyFlags&0x0004000000000000LL)
+ SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
+ if(saBounds.first != saBounds.second)
{
- // Update regen on remove
- if (!apply && m_target->GetTypeId() == TYPEID_PLAYER)
- ((Player*)m_target)->UpdateManaRegen();
- break;
+ uint32 zone, area;
+ m_target->GetZoneAndAreaId(zone,area);
+
+ for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
+ {
+ // some auras remove at aura remove
+ if(!itr->second->IsFitToRequirements((Player*)m_target,zone,area))
+ m_target->RemoveAurasDueToSpell(itr->second->spellId);
+ // some auras applied at aura apply
+ else if(itr->second->autocast)
+ {
+ if( !m_target->HasAuraEffect(itr->second->spellId,0) )
+ m_target->CastSpell(m_target,itr->second->spellId,true);
+ }
+ }
}
- break;
}
}
-
- m_isPeriodic = apply;
}
-void Aura::HandleAuraMounted(bool apply, bool Real)
+void AuraEffect::HandleAuraMounted(bool apply, bool Real, bool /*changeAmount*/)
{
// only at real add/remove aura
if(!Real)
@@ -2263,10 +2904,10 @@ void Aura::HandleAuraMounted(bool apply, bool Real)
if(apply)
{
- CreatureInfo const* ci = objmgr.GetCreatureTemplate(m_modifier.m_miscvalue);
+ CreatureInfo const* ci = objmgr.GetCreatureTemplate(GetMiscValue());
if(!ci)
{
- sLog.outErrorDb("AuraMounted: `creature_template`='%u' not found in database (only need it modelid)", m_modifier.m_miscvalue);
+ sLog.outErrorDb("AuraMounted: `creature_template`='%u' not found in database (only need it modelid)",GetMiscValue());
return;
}
@@ -2279,6 +2920,11 @@ void Aura::HandleAuraMounted(bool apply, bool Real)
if (minfo)
display_id = minfo->modelid;
+ //some spell has one aura of mount and one of vehicle
+ for(uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if(GetSpellProto()->Effect[i] == SPELL_EFFECT_SUMMON
+ && GetSpellProto()->EffectMiscValue[i] == GetMiscValue())
+ display_id = 0;
m_target->Mount(display_id);
}
else
@@ -2287,7 +2933,7 @@ void Aura::HandleAuraMounted(bool apply, bool Real)
}
}
-void Aura::HandleAuraWaterWalk(bool apply, bool Real)
+void AuraEffect::HandleAuraWaterWalk(bool apply, bool Real, bool /*changeAmount*/)
{
// only at real add/remove aura
if(!Real)
@@ -2303,7 +2949,7 @@ void Aura::HandleAuraWaterWalk(bool apply, bool Real)
m_target->SendMessageToSet(&data,true);
}
-void Aura::HandleAuraFeatherFall(bool apply, bool Real)
+void AuraEffect::HandleAuraFeatherFall(bool apply, bool Real, bool /*changeAmount*/)
{
// only at real add/remove aura
if(!Real)
@@ -2319,7 +2965,7 @@ void Aura::HandleAuraFeatherFall(bool apply, bool Real)
m_target->SendMessageToSet(&data,true);
}
-void Aura::HandleAuraHover(bool apply, bool Real)
+void AuraEffect::HandleAuraHover(bool apply, bool Real, bool /*changeAmount*/)
{
// only at real add/remove aura
if(!Real)
@@ -2335,31 +2981,21 @@ void Aura::HandleAuraHover(bool apply, bool Real)
m_target->SendMessageToSet(&data,true);
}
-void Aura::HandleWaterBreathing(bool apply, bool Real)
+void AuraEffect::HandleWaterBreathing(bool apply, bool Real, bool /*changeAmount*/)
{
- if(apply)
- m_target->waterbreath = true;
- else if(m_target->GetAurasByType(SPELL_AURA_WATER_BREATHING).empty())
- {
- m_target->waterbreath = false;
-
- // update for enable timer in case not moving target
- if(m_target->GetTypeId()==TYPEID_PLAYER && m_target->IsInWorld())
- {
- ((Player*)m_target)->UpdateUnderwaterState(m_target->GetMap(),m_target->GetPositionX(),m_target->GetPositionY(),m_target->GetPositionZ());
- ((Player*)m_target)->HandleDrowning();
- }
- }
+ // update timers in client
+ if(m_target->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_target)->UpdateMirrorTimers();
}
-void Aura::HandleAuraModShapeshift(bool apply, bool Real)
+void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmount)
{
- if(!Real)
+ if(!Real && !changeAmount)
return;
uint32 modelid = 0;
Powers PowerType = POWER_MANA;
- ShapeshiftForm form = ShapeshiftForm(m_modifier.m_miscvalue);
+ ShapeshiftForm form = ShapeshiftForm(GetMiscValue());
switch(form)
{
case FORM_CAT:
@@ -2420,6 +3056,9 @@ void Aura::HandleAuraModShapeshift(bool apply, bool Real)
else
modelid = 21244;
break;
+ case FORM_METAMORPHOSIS:
+ modelid = 25277;
+ break;
case FORM_AMBIENT:
case FORM_SHADOW:
case FORM_STEALTH:
@@ -2436,7 +3075,7 @@ void Aura::HandleAuraModShapeshift(bool apply, bool Real)
modelid = 16031;
break;
default:
- sLog.outError("Auras: Unknown Shapeshift Type: %u", m_modifier.m_miscvalue);
+ sLog.outError("Auras: Unknown Shapeshift Type: %u", GetMiscValue());
}
// remove polymorph before changing display id to keep new display id
@@ -2466,7 +3105,7 @@ void Aura::HandleAuraModShapeshift(bool apply, bool Real)
{
// remove other shapeshift before applying a new one
if(m_target->m_ShapeShiftFormSpellId)
- m_target->RemoveAurasDueToSpell(m_target->m_ShapeShiftFormSpellId,this);
+ m_target->RemoveAurasDueToSpell(m_target->m_ShapeShiftFormSpellId);
m_target->SetByteValue(UNIT_FIELD_BYTES_2, 3, form);
@@ -2486,22 +3125,22 @@ void Aura::HandleAuraModShapeshift(bool apply, bool Real)
case FORM_DIREBEAR:
{
// get furor proc chance
- uint32 FurorChance = 0;
- Unit::AuraList const& mDummy = m_target->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = mDummy.begin(); i != mDummy.end(); ++i)
+ int32 FurorChance = 0;
+ Unit::AuraEffectList const& mDummy = m_target->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator i = mDummy.begin(); i != mDummy.end(); ++i)
{
if ((*i)->GetSpellProto()->SpellIconID == 238)
{
- FurorChance = (*i)->GetModifier()->m_amount;
+ FurorChance = (*i)->GetAmount();
break;
}
}
- if (m_modifier.m_miscvalue == FORM_CAT)
+ if (GetMiscValue() == FORM_CAT)
{
m_target->SetPower(POWER_ENERGY,0);
if(urand(1,100) <= FurorChance)
- m_target->CastSpell(m_target,17099,true,NULL,this);
+ m_target->CastCustomSpell(m_target,17099,&FurorChance, NULL, NULL,true,NULL,this);
}
else
{
@@ -2557,18 +3196,16 @@ void Aura::HandleAuraModShapeshift(bool apply, bool Real)
case FORM_BEAR:
case FORM_DIREBEAR:
case FORM_CAT:
- {
- if(Aura* dummy = m_target->GetDummyAura(37315) )
+ if(AuraEffect* dummy = m_target->GetDummyAura(37315) )
m_target->CastSpell(m_target,37316,true,NULL,dummy);
break;
- }
// Nordrassil Regalia - bonus
case FORM_MOONKIN:
- {
- if(Aura* dummy = m_target->GetDummyAura(37324) )
+ if(AuraEffect* dummy = m_target->GetDummyAura(37324) )
m_target->CastSpell(m_target,37325,true,NULL,dummy);
break;
- }
+ default:
+ break;
}
}
@@ -2578,20 +3215,34 @@ void Aura::HandleAuraModShapeshift(bool apply, bool Real)
if(m_target->GetTypeId()==TYPEID_PLAYER)
((Player*)m_target)->InitDataForForm();
+
+ if(m_target->getClass() == CLASS_DRUID)
+ {
+ if(form == FORM_CAT && apply) // add dash if in cat-from
+ {
+ if(AuraEffect * aurEff =m_target->GetAura(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8))
+ m_target->HandleAuraEffect(aurEff, true);
+ }
+ else // remove dash effect(not buff) if out of cat-from
+ {
+ if(AuraEffect * aurEff =m_target->GetAura(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8))
+ m_target->HandleAuraEffect(aurEff, false);
+ }
+ }
}
-void Aura::HandleAuraTransform(bool apply, bool Real)
+void AuraEffect::HandleAuraTransform(bool apply, bool Real, bool /*changeAmount*/)
{
if (apply)
{
// special case (spell specific functionality)
- if(m_modifier.m_miscvalue==0)
+ if(GetMiscValue()==0)
{
// player applied only
- if(m_target->GetTypeId()!=TYPEID_PLAYER)
+ if (m_target->GetTypeId()!=TYPEID_PLAYER)
return;
- switch(GetId())
+ switch (GetId())
{
// Orb of Deception
case 16739:
@@ -2650,12 +3301,12 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
}
else
{
- CreatureInfo const * ci = objmgr.GetCreatureTemplate(m_modifier.m_miscvalue);
+ CreatureInfo const * ci = objmgr.GetCreatureTemplate(GetMiscValue());
if(!ci)
{
//pig pink ^_^
m_target->SetDisplayId(16358);
- sLog.outError("Auras: unknown creature id = %d (only need its modelid) Form Spell Aura Transform in Spell ID = %d", m_modifier.m_miscvalue, GetId());
+ sLog.outError("Auras: unknown creature id = %d (only need its modelid) Form Spell Aura Transform in Spell ID = %d", GetMiscValue(), GetId());
}
else
{
@@ -2664,41 +3315,44 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
m_target->SetDisplayId(modelid);
// Dragonmaw Illusion (set mount model also)
- if(GetId()==42016 && m_target->GetMountID() && !m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED).empty())
+ if(GetId()==42016 && m_target->GetMountID() && !m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED).empty())
m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314);
}
- m_target->setTransForm(GetId());
}
+ // update active transform spell only not set or not overwriting negative by positive case
+ if (!m_target->getTransForm() || !IsPositiveSpell(GetId()) || IsPositiveSpell(m_target->getTransForm()))
+ m_target->setTransForm(GetId());
+
// polymorph case
- if( Real && m_target->GetTypeId() == TYPEID_PLAYER && m_target->IsPolymorphed())
+ if (Real && m_target->GetTypeId() == TYPEID_PLAYER && m_target->IsPolymorphed())
{
// for players, start regeneration after 1s (in polymorph fast regeneration case)
// only if caster is Player (after patch 2.4.2)
- if(IS_PLAYER_GUID(GetCasterGUID()) )
- ((Player*)m_target)->setRegenTimer(1000);
+ if (IS_PLAYER_GUID(GetCasterGUID()) )
+ ((Player*)m_target)->setRegenTimer(1*IN_MILISECONDS);
//dismount polymorphed target (after patch 2.4.2)
if (m_target->IsMounted())
- m_target->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+ m_target->RemoveAurasByType(SPELL_AURA_MOUNTED);
}
}
else
{
- Unit::AuraList const& otherTransforms = m_target->GetAurasByType(SPELL_AURA_TRANSFORM);
- if(otherTransforms.empty())
- {
- m_target->SetDisplayId(m_target->GetNativeDisplayId());
- m_target->setTransForm(0);
- }
- else
+ // ApplyModifier(true) will reapply it if need
+ m_target->setTransForm(0);
+ m_target->SetDisplayId(m_target->GetNativeDisplayId());
+
+ // re-aplly some from still active with preference negative cases
+ Unit::AuraEffectList const& otherTransforms = m_target->GetAurasByType(SPELL_AURA_TRANSFORM);
+ if (!otherTransforms.empty())
{
// look for other transform auras
- Aura* handledAura = *otherTransforms.begin();
- for(Unit::AuraList::const_iterator i = otherTransforms.begin();i != otherTransforms.end(); ++i)
+ AuraEffect* handledAura = *otherTransforms.begin();
+ for(Unit::AuraEffectList::const_iterator i = otherTransforms.begin();i != otherTransforms.end(); ++i)
{
// negative auras are preferred
- if(!IsPositiveSpell((*i)->GetSpellProto()->Id))
+ if (!IsPositiveSpell((*i)->GetSpellProto()->Id))
{
handledAura = *i;
break;
@@ -2708,11 +3362,11 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
}
// Dragonmaw Illusion (restore mount model)
- if(GetId()==42016 && m_target->GetMountID()==16314)
+ if (GetId()==42016 && m_target->GetMountID()==16314)
{
- if(!m_target->GetAurasByType(SPELL_AURA_MOUNTED).empty())
+ if (!m_target->GetAurasByType(SPELL_AURA_MOUNTED).empty())
{
- uint32 cr_id = m_target->GetAurasByType(SPELL_AURA_MOUNTED).front()->GetModifier()->m_miscvalue;
+ uint32 cr_id = m_target->GetAurasByType(SPELL_AURA_MOUNTED).front()->GetMiscValue();
if(CreatureInfo const* ci = objmgr.GetCreatureTemplate(cr_id))
{
uint32 team = 0;
@@ -2731,54 +3385,42 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
}
}
-void Aura::HandleForceReaction(bool apply, bool Real)
+void AuraEffect::HandleForceReaction(bool apply, bool Real, bool changeAmount)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
- if(!Real)
+ if(!Real && !changeAmount)
return;
Player* player = (Player*)m_target;
- uint32 faction_id = m_modifier.m_miscvalue;
- uint32 faction_rank = m_modifier.m_amount;
-
- if(apply)
- player->m_forcedReactions[faction_id] = ReputationRank(faction_rank);
- else
- player->m_forcedReactions.erase(faction_id);
+ uint32 faction_id = GetMiscValue();
+ uint32 faction_rank = m_amount;
- WorldPacket data;
- data.Initialize(SMSG_SET_FORCED_REACTIONS, 4+player->m_forcedReactions.size()*(4+4));
- data << uint32(player->m_forcedReactions.size());
- for(ForcedReactions::const_iterator itr = player->m_forcedReactions.begin(); itr != player->m_forcedReactions.end(); ++itr)
- {
- data << uint32(itr->first); // faction_id (Faction.dbc)
- data << uint32(itr->second); // reputation rank
- }
- player->SendDirectMessage(&data);
+ player->GetReputationMgr().ApplyForceReaction(faction_id,ReputationRank(faction_rank),apply);
+ player->GetReputationMgr().SendForceReactions();
}
-void Aura::HandleAuraModSkill(bool apply, bool Real)
+void AuraEffect::HandleAuraModSkill(bool apply, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
uint32 prot=GetSpellProto()->EffectMiscValue[m_effIndex];
- int32 points = GetModifierValue();
+ int32 points = m_amount;
- ((Player*)m_target)->ModifySkillBonus(prot,(apply ? points: -points),m_modifier.m_auraname==SPELL_AURA_MOD_SKILL_TALENT);
+ ((Player*)m_target)->ModifySkillBonus(prot,(apply ? points: -points),m_auraName==SPELL_AURA_MOD_SKILL_TALENT);
if(prot == SKILL_DEFENSE)
((Player*)m_target)->UpdateDefenseBonusesMod();
}
-void Aura::HandleChannelDeathItem(bool apply, bool Real)
+void AuraEffect::HandleChannelDeathItem(bool apply, bool Real, bool /*changeAmount*/)
{
if(Real && !apply)
{
Unit* caster = GetCaster();
- Unit* victim = GetTarget();
+ Unit* victim = m_target;
if(!caster || caster->GetTypeId() != TYPEID_PLAYER || !victim)// || m_removeMode!=AURA_REMOVE_BY_DEATH)
return;
@@ -2786,6 +3428,9 @@ void Aura::HandleChannelDeathItem(bool apply, bool Real)
//talent will remove the caster's aura->interrupt channel->remove victim aura
if(victim->GetHealth() > 0)
return;
+ // Item amount
+ if (m_amount <= 0)
+ return;
SpellEntry const *spellInfo = GetSpellProto();
if(spellInfo->EffectItemType[m_effIndex] == 0)
@@ -2796,100 +3441,158 @@ void Aura::HandleChannelDeathItem(bool apply, bool Real)
(victim->getLevel() <= Trinity::XP::GetGrayLevel(caster->getLevel()) ||
victim->GetTypeId()==TYPEID_UNIT && !((Player*)caster)->isAllowedToLoot((Creature*)victim)) )
return;
+ //Adding items
+ uint32 noSpaceForCount = 0;
+ uint32 count = m_amount;
+
ItemPosCountVec dest;
- uint8 msg = ((Player*)caster)->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, spellInfo->EffectItemType[m_effIndex], 1 );
+ uint8 msg = ((Player*)caster)->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, spellInfo->EffectItemType[m_effIndex], count, &noSpaceForCount);
if( msg != EQUIP_ERR_OK )
{
+ count-=noSpaceForCount;
((Player*)caster)->SendEquipError( msg, NULL, NULL );
- return;
+ if (count==0)
+ return;
}
Item* newitem = ((Player*)caster)->StoreNewItem(dest, spellInfo->EffectItemType[m_effIndex], true);
- ((Player*)caster)->SendNewItem(newitem, 1, true, false);
+ ((Player*)caster)->SendNewItem(newitem, count, true, false);
}
}
-void Aura::HandleBindSight(bool apply, bool Real)
+void AuraEffect::HandleBindSight(bool apply, bool Real, bool /*changeAmount*/)
{
+ if (!Real)
+ return;
Unit* caster = GetCaster();
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
- if (apply)
- m_target->AddPlayerToVision((Player*)caster);
- else
- m_target->RemovePlayerFromVision((Player*)caster);
+ ((Player*)caster)->SetViewpoint(m_target, apply);
}
-void Aura::HandleFarSight(bool apply, bool Real)
+void AuraEffect::HandleFarSight(bool apply, bool Real, bool /*changeAmount*/)
{
- Unit* caster = GetCaster();
- if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
- return;
-
- ((Player*)caster)->SetFarSight(apply ? m_target->GetGUID() : NULL);
+ //Handled by client
}
-void Aura::HandleAuraTrackCreatures(bool apply, bool Real)
+void AuraEffect::HandleAuraTrackCreatures(bool apply, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId()!=TYPEID_PLAYER)
return;
- if(apply)
- m_target->RemoveNoStackAurasDueToAura(this);
- m_target->SetUInt32Value(PLAYER_TRACK_CREATURES, apply ? ((uint32)1)<<(m_modifier.m_miscvalue-1) : 0 );
+ m_target->SetUInt32Value(PLAYER_TRACK_CREATURES, apply ? ((uint32)1)<<(GetMiscValue()-1) : 0 );
}
-void Aura::HandleAuraTrackResources(bool apply, bool Real)
+void AuraEffect::HandleAuraTrackResources(bool apply, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId()!=TYPEID_PLAYER)
return;
- if(apply)
- m_target->RemoveNoStackAurasDueToAura(this);
- m_target->SetUInt32Value(PLAYER_TRACK_RESOURCES, apply ? ((uint32)1)<<(m_modifier.m_miscvalue-1): 0 );
+ m_target->SetUInt32Value(PLAYER_TRACK_RESOURCES, apply ? ((uint32)1)<<(GetMiscValue()-1): 0 );
}
-void Aura::HandleAuraTrackStealthed(bool apply, bool Real)
+void AuraEffect::HandleAuraTrackStealthed(bool apply, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId()!=TYPEID_PLAYER)
return;
- if(apply)
- m_target->RemoveNoStackAurasDueToAura(this);
-
m_target->ApplyModFlag(PLAYER_FIELD_BYTES,PLAYER_FIELD_BYTE_TRACK_STEALTHED,apply);
}
-void Aura::HandleAuraModScale(bool apply, bool Real)
+void AuraEffect::HandleAuraModScale(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X,GetModifierValue(),apply);
+ m_target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X,m_amount,apply);
}
-void Aura::HandleModPossess(bool apply, bool Real)
+/*void AuraEffect::HandleModPossess(bool apply, bool Real)
{
if(!Real)
return;
+ if(m_target->getLevel() > m_amount)
+ return;
+
+ // not possess yourself
+ if(GetCasterGUID() == m_target->GetGUID())
+ return;
+
Unit* caster = GetCaster();
- if(caster && caster->GetTypeId() == TYPEID_UNIT)
- {
- HandleModCharm(apply, Real);
+ if(!caster)
return;
- }
- if(apply)
+ if( apply )
{
- if(m_target->getLevel() > m_modifier.m_amount)
- return;
+ m_target->SetCharmerGUID(GetCasterGUID());
+ m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
- m_target->SetCharmedOrPossessedBy(caster, true);
+ caster->SetCharm(m_target);
+
+ if(caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)caster)->SetFarSightGUID(m_target->GetGUID());
+ ((Player*)caster)->SetClientControl(m_target, 1);
+ }
+
+ m_target->CombatStop();
+ m_target->DeleteThreatList();
+ if(m_target->GetTypeId() == TYPEID_UNIT)
+ {
+ m_target->StopMoving();
+ m_target->GetMotionMaster()->Clear();
+ m_target->GetMotionMaster()->MoveIdle();
+ }
+ else if(m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)m_target)->SetClientControl(m_target, 0);
+ }
+
+ if(CharmInfo *charmInfo = m_target->InitCharmInfo(m_target))
+ charmInfo->InitPossessCreateSpells();
+
+ if(caster->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)caster)->PossessSpellInitialize();
}
else
- m_target->RemoveCharmedOrPossessedBy(caster);
+ {
+ m_target->SetCharmerGUID(0);
+ caster->InterruptSpell(CURRENT_CHANNELED_SPELL); // the spell is not automatically canceled when interrupted, do it now
+
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)m_target)->setFactionForRace(m_target->getRace());
+ ((Player*)m_target)->SetClientControl(m_target, 1);
+ }
+ else if(m_target->GetTypeId() == TYPEID_UNIT)
+ {
+ CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
+ m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
+ }
+
+ caster->SetCharm(NULL);
+
+ if(caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)caster)->SetFarSightGUID(0);
+ ((Player*)caster)->SetClientControl(m_target,0);
+
+ WorldPacket data(SMSG_PET_SPELLS, 8+4);
+ data << uint64(0);
+ data << uint32(0);
+ ((Player*)caster)->GetSession()->SendPacket(&data);
+ }
+
+ if(m_target->GetTypeId() == TYPEID_UNIT)
+ {
+ ((Creature*)m_target)->AIM_Initialize();
+
+ if (((Creature*)m_target)->AI())
+ ((Creature*)m_target)->AI()->AttackedBy(caster);
+ }
+ }
}
-void Aura::HandleModPossessPet(bool apply, bool Real)
+void AuraEffect::HandleModPossessPet(bool apply, bool Real)
{
if(!Real)
return;
@@ -2898,46 +3601,155 @@ void Aura::HandleModPossessPet(bool apply, bool Real)
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
+ Pet *pet = caster->GetGuardianPet();
+ if(!pet || pet != m_target)
+ return;
+
if(apply)
- {
- if(caster->GetPet() != m_target)
- return;
+ pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
+ else
+ pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
- m_target->SetCharmedOrPossessedBy(caster, true);
+ ((Player*)caster)->SetFarSightGUID(apply ? pet->GetGUID() : 0);
+ ((Player*)caster)->SetCharm(apply ? pet : NULL);
+ ((Player*)caster)->SetClientControl(pet, apply ? 1 : 0);
+
+ if(apply)
+ {
+ pet->StopMoving();
+ pet->GetMotionMaster()->Clear();
+ pet->GetMotionMaster()->MoveIdle();
}
else
{
- m_target->RemoveCharmedOrPossessedBy(caster);
-
- // Reinitialize the pet bar and make the pet come back to the owner
- ((Player*)caster)->PetSpellInitialize();
- if(!m_target->getVictim())
- {
- m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
- m_target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
- }
+ pet->AttackStop();
+ pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ pet->SetUnitMovementFlags(MOVEMENTFLAG_NONE);
}
+}*/
+
+void AuraEffect::HandleAuraModPetTalentsPoints(bool Apply, bool Real, bool changeAmount)
+{
+ if(!Real && !changeAmount)
+ return;
+
+ if(m_target->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ // Recalculate pet tlaent points
+ if (Pet *pet = ((Player*)m_target)->GetPet())
+ pet->InitTalentForLevel();
}
-void Aura::HandleModCharm(bool apply, bool Real)
+/*void AuraEffect::HandleModCharm(bool apply, bool Real)
{
if(!Real)
return;
+ // not charm yourself
+ if(GetCasterGUID() == m_target->GetGUID())
+ return;
+
Unit* caster = GetCaster();
+ if(!caster)
+ return;
- if(apply)
+ if(int32(m_target->getLevel()) <= m_amount)
{
- if(int32(m_target->getLevel()) > m_modifier.m_amount)
- return;
+ if( apply )
+ {
+ m_target->SetCharmerGUID(GetCasterGUID());
+ m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
+ m_target->CastStop(m_target==caster ? GetId() : 0);
+ caster->SetCharm(m_target);
- m_target->SetCharmedOrPossessedBy(caster, false);
+ m_target->CombatStop();
+ m_target->DeleteThreatList();
+
+ if(m_target->GetTypeId() == TYPEID_UNIT)
+ {
+ ((Creature*)m_target)->AIM_Initialize();
+ CharmInfo *charmInfo = m_target->InitCharmInfo(m_target);
+ charmInfo->InitCharmCreateSpells();
+ charmInfo->SetReactState( REACT_DEFENSIVE );
+
+ if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
+ {
+ CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
+ if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
+ {
+ //to prevent client crash
+ m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048);
+ //just to enable stat window
+ charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true);
+ //if charmed two demons the same session, the 2nd gets the 1st one's name
+ m_target->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
+ }
+ }
+ }
+
+ if(caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)caster)->CharmSpellInitialize();
+ }
+ }
+ else
+ {
+ m_target->SetCharmerGUID(0);
+
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)m_target)->setFactionForRace(m_target->getRace());
+ else
+ {
+ CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
+
+ // restore faction
+ if(((Creature*)m_target)->isPet())
+ {
+ if(Unit* owner = m_target->GetOwner())
+ m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,owner->getFaction());
+ else if(cinfo)
+ m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
+ }
+ else if(cinfo) // normal creature
+ m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
+
+ // restore UNIT_FIELD_BYTES_0
+ if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
+ {
+ CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon();
+ if(cainfo && cainfo->bytes0 != 0)
+ m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
+ else
+ m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);
+
+ if(m_target->GetCharmInfo())
+ m_target->GetCharmInfo()->SetPetNumber(0, true);
+ else
+ sLog.outError("AuraEffect::HandleModCharm: target="I64FMTD" with typeid=%d has a charm aura but no charm info!", m_target->GetGUID(), m_target->GetTypeId());
+ }
+ }
+
+ caster->SetCharm(NULL);
+
+ if(caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ WorldPacket data(SMSG_PET_SPELLS, 8+4);
+ data << uint64(0);
+ data << uint32(0);
+ ((Player*)caster)->GetSession()->SendPacket(&data);
+ }
+ if(m_target->GetTypeId() == TYPEID_UNIT)
+ {
+ ((Creature*)m_target)->AIM_Initialize();
+ if (((Creature*)m_target)->AI())
+ ((Creature*)m_target)->AI()->AttackedBy(caster);
+ }
+ }
}
- else
- m_target->RemoveCharmedOrPossessedBy(caster);
-}
+}*/
-void Aura::HandleModConfuse(bool apply, bool Real)
+void AuraEffect::HandleModConfuse(bool apply, bool Real, bool /*changeAmount*/)
{
if(!Real)
return;
@@ -2946,7 +3758,7 @@ void Aura::HandleModConfuse(bool apply, bool Real)
m_target->SetControlled(apply, UNIT_STAT_CONFUSED);
}
-void Aura::HandleModFear(bool apply, bool Real)
+void AuraEffect::HandleModFear(bool apply, bool Real, bool /*changeAmount*/)
{
if (!Real)
return;
@@ -2955,7 +3767,7 @@ void Aura::HandleModFear(bool apply, bool Real)
m_target->SetControlled(apply, UNIT_STAT_FLEEING);
}
-void Aura::HandleFeignDeath(bool apply, bool Real)
+void AuraEffect::HandleFeignDeath(bool apply, bool Real, bool /*changeAmount*/)
{
if(!Real)
return;
@@ -2974,7 +3786,7 @@ void Aura::HandleFeignDeath(bool apply, bool Real)
std::list<Unit*> targets;
Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_target, m_target, World::GetMaxVisibleDistance());
- Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(targets, u_check);
+ Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(m_target, targets, u_check);
m_target->VisitNearbyObject(World::GetMaxVisibleDistance(), searcher);
for(std::list<Unit*>::iterator iter = targets.begin(); iter != targets.end(); ++iter)
{
@@ -2991,7 +3803,7 @@ void Aura::HandleFeignDeath(bool apply, bool Real)
}
}
// blizz like 2.0.x
- m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN6);
+ m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
// blizz like 2.0.x
m_target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
// blizz like 2.0.x
@@ -2999,10 +3811,10 @@ void Aura::HandleFeignDeath(bool apply, bool Real)
m_target->addUnitState(UNIT_STAT_DIED);
m_target->CombatStop();
- m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_UNATTACKABLE);
+ m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
// prevent interrupt message
- if(m_caster_guid==m_target->GetGUID() && m_target->m_currentSpells[CURRENT_GENERIC_SPELL])
+ if(GetCasterGUID()==m_target->GetGUID() && m_target->m_currentSpells[CURRENT_GENERIC_SPELL])
m_target->m_currentSpells[CURRENT_GENERIC_SPELL]->finish();
m_target->InterruptNonMeleeSpells(true);
m_target->getHostilRefManager().deleteReferences();
@@ -3016,7 +3828,7 @@ void Aura::HandleFeignDeath(bool apply, bool Real)
m_target->SendMessageToSet(&data,true);
*/
// blizz like 2.0.x
- m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN6);
+ m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
// blizz like 2.0.x
m_target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
// blizz like 2.0.x
@@ -3026,221 +3838,142 @@ void Aura::HandleFeignDeath(bool apply, bool Real)
}
}
-void Aura::HandleAuraModDisarm(bool apply, bool Real)
+void AuraEffect::HandleAuraModDisarm(bool apply, bool Real, bool /*changeAmount*/)
{
- if(!Real)
+ if (!Real)
return;
+ AuraType type = AuraType(GetAuraName());
- if(!apply && m_target->HasAuraType(SPELL_AURA_MOD_DISARM))
+ //Prevent handling aura twice
+ if(apply && m_target->GetAurasByType(type).size()>1)
return;
-
- // not sure for it's correctness
+ if(!apply && m_target->HasAuraType(type))
+ return;
+ uint32 field, flag, slot;
+ WeaponAttackType attType;
+ switch (type)
+ {
+ case SPELL_AURA_MOD_DISARM:
+ field=UNIT_FIELD_FLAGS;
+ flag=UNIT_FLAG_DISARMED;
+ slot=EQUIPMENT_SLOT_MAINHAND;
+ attType=BASE_ATTACK;
+ break;
+ case SPELL_AURA_MOD_DISARM_OFFHAND:
+ field=UNIT_FIELD_FLAGS_2;
+ flag=UNIT_FLAG2_DISARM_OFFHAND;
+ slot=EQUIPMENT_SLOT_OFFHAND;
+ attType=OFF_ATTACK;
+ break;
+ case SPELL_AURA_MOD_DISARM_RANGED:
+ field=UNIT_FIELD_FLAGS_2;
+ flag=UNIT_FLAG2_DISARM_RANGED;
+ slot=EQUIPMENT_SLOT_RANGED;
+ attType=RANGED_ATTACK;
+ break;
+ }
if(apply)
- m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED);
+ m_target->SetFlag(field, flag);
else
- m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED);
+ m_target->RemoveFlag(field, flag);
if (m_target->GetTypeId() == TYPEID_PLAYER)
{
- // main-hand attack speed already set to special value for feral form already and don't must change and reset at remove.
- if (((Player *)m_target)->IsInFeralForm())
- return;
-
- if (apply)
- m_target->SetAttackTime(BASE_ATTACK,BASE_ATTACK_TIME);
- else
- ((Player *)m_target)->SetRegularAttackTime();
- }
- else
- {
- // creature does not have equipment
- if(apply && !((Creature*)m_target)->GetCurrentEquipmentId())
+ Item *pItem = ((Player*)m_target)->GetItemByPos( INVENTORY_SLOT_BAG_0, slot );
+ if(!pItem )
return;
+ ((Player*)m_target)->_ApplyItemMods(pItem, slot, !apply);
}
-
- m_target->UpdateDamagePhysical(BASE_ATTACK);
+ else if (((Creature*)m_target)->GetCurrentEquipmentId())
+ m_target->UpdateDamagePhysical(attType);
}
-void Aura::HandleAuraModStun(bool apply, bool Real)
+void AuraEffect::HandleModStealth(bool apply, bool Real, bool /*changeAmount*/)
{
if(!Real)
return;
- m_target->SetControlled(apply, UNIT_STAT_STUNNED);
-}
-
-void Aura::HandleModStealth(bool apply, bool Real)
-{
if(apply)
{
- if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
- {
- // drop flag at stealth in bg
- m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_UNATTACKABLE);
+ // drop flag at stealth in bg
+ m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
- // remove player from the objective's active player count at stealth
- if(OutdoorPvP * pvp = ((Player*)m_target)->GetOutdoorPvP())
- pvp->HandlePlayerActivityChanged((Player*)m_target);
- }
-
- // only at real aura add
- if(Real)
- {
- m_target->SetByteValue(UNIT_FIELD_BYTES_1, 2, 0x02);
- if(m_target->GetTypeId()==TYPEID_PLAYER)
- m_target->SetFlag(PLAYER_FIELD_BYTES2, 0x2000);
-
- // apply only if not in GM invisibility (and overwrite invisibility state)
- if(m_target->GetVisibility()!=VISIBILITY_OFF)
- {
- //m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
- //m_target->SetVisibility(VISIBILITY_OFF);
- m_target->SetVisibility(VISIBILITY_GROUP_STEALTH);
- }
+ m_target->SetStandFlags(UNIT_STAND_FLAGS_CREEP);
+ if(m_target->GetTypeId()==TYPEID_PLAYER)
+ m_target->SetFlag(PLAYER_FIELD_BYTES2, 0x2000);
- // for RACE_NIGHTELF stealth
- if(m_target->GetTypeId()==TYPEID_PLAYER && GetId()==20580)
- m_target->CastSpell(m_target, 21009, true, NULL, this);
- }
+ // apply only if not in GM invisibility (and overwrite invisibility state)
+ if(m_target->GetVisibility() != VISIBILITY_OFF)
+ m_target->SetVisibility(VISIBILITY_GROUP_STEALTH);
}
- else
+ else if(!m_target->HasAuraType(SPELL_AURA_MOD_STEALTH)) // if last SPELL_AURA_MOD_STEALTH
{
- // only at real aura remove
- if(Real)
- {
- // for RACE_NIGHTELF stealth
- if(m_target->GetTypeId()==TYPEID_PLAYER && GetId()==20580)
- m_target->RemoveAurasDueToSpell(21009);
-
- // if last SPELL_AURA_MOD_STEALTH and no GM invisibility
- if(!m_target->HasAuraType(SPELL_AURA_MOD_STEALTH) && m_target->GetVisibility()!=VISIBILITY_OFF)
- {
- m_target->SetByteValue(UNIT_FIELD_BYTES_1, 2, 0x00);
- if(m_target->GetTypeId()==TYPEID_PLAYER)
- m_target->RemoveFlag(PLAYER_FIELD_BYTES2, 0x2000);
-
- // restore invisibility if any
- if(m_target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY))
- {
- //m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
- //m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY);
- m_target->SetVisibility(VISIBILITY_ON);
- }
- else
- {
- m_target->SetVisibility(VISIBILITY_ON);
- if(m_target->GetTypeId() == TYPEID_PLAYER)
- if(OutdoorPvP * pvp = ((Player*)m_target)->GetOutdoorPvP())
- pvp->HandlePlayerActivityChanged((Player*)m_target);
- }
- }
- }
- }
+ m_target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP);
+ if(m_target->GetTypeId()==TYPEID_PLAYER)
+ m_target->RemoveFlag(PLAYER_FIELD_BYTES2, 0x2000);
- // Master of Subtlety
- Unit::AuraList const& mDummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
- {
- if ((*i)->GetSpellProto()->SpellIconID == 2114 && Real)
- {
- if (apply)
- {
- int32 bp = (*i)->GetModifier()->m_amount;
- m_target->CastCustomSpell(m_target,31665,&bp,NULL,NULL,true);
- }
- else
- m_target->CastSpell(m_target,31666,true);
- break;
- }
+ if(m_target->GetVisibility() != VISIBILITY_OFF)
+ m_target->SetVisibility(VISIBILITY_ON);
}
}
-void Aura::HandleInvisibility(bool apply, bool Real)
+void AuraEffect::HandleInvisibility(bool apply, bool Real, bool /*changeAmount*/)
{
if(apply)
{
- m_target->m_invisibilityMask |= (1 << m_modifier.m_miscvalue);
-
- m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_UNATTACKABLE);
+ m_target->m_invisibilityMask |= (1 << GetMiscValue());
- if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
+ if(Real)
{
+ m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
+
// apply glow vision
- m_target->SetFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
- // remove player from the objective's active player count at invisibility
- if(OutdoorPvP * pvp = ((Player*)m_target)->GetOutdoorPvP())
- pvp->HandlePlayerActivityChanged((Player*)m_target);
- }
+ if(m_target->GetTypeId()==TYPEID_PLAYER)
+ m_target->SetFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
- // apply only if not in GM invisibility and not stealth
- if(m_target->GetVisibility()==VISIBILITY_ON)
- {
- // Aura not added yet but visibility code expect temporary add aura
- //m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
- //m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY);
- m_target->SetVisibility(VISIBILITY_ON);
+ m_target->SetToNotify();
}
}
else
{
// recalculate value at modifier remove (current aura already removed)
m_target->m_invisibilityMask = 0;
- Unit::AuraList const& auras = m_target->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
- for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- m_target->m_invisibilityMask |= (1 << m_modifier.m_miscvalue);
+ Unit::AuraEffectList const& auras = m_target->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
+ for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
+ m_target->m_invisibilityMask |= (1 << GetMiscValue());
// only at real aura remove and if not have different invisibility auras.
- if(Real && m_target->m_invisibilityMask==0)
+ if(Real)
{
// remove glow vision
- if(m_target->GetTypeId() == TYPEID_PLAYER)
+ if(!m_target->m_invisibilityMask && m_target->GetTypeId() == TYPEID_PLAYER)
m_target->RemoveFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
- // apply only if not in GM invisibility & not stealthed while invisible
- if(m_target->GetVisibility()!=VISIBILITY_OFF)
- {
- // if have stealth aura then already have stealth visibility
- if(!m_target->HasAuraType(SPELL_AURA_MOD_STEALTH))
- {
- m_target->SetVisibility(VISIBILITY_ON);
- if(m_target->GetTypeId() == TYPEID_PLAYER)
- if(OutdoorPvP * pvp = ((Player*)m_target)->GetOutdoorPvP())
- pvp->HandlePlayerActivityChanged((Player*)m_target);
- }
- }
+ m_target->SetToNotify();
}
}
}
-void Aura::HandleInvisibilityDetect(bool apply, bool Real)
+void AuraEffect::HandleInvisibilityDetect(bool apply, bool Real, bool /*changeAmount*/)
{
if(apply)
{
- m_target->m_detectInvisibilityMask |= (1 << m_modifier.m_miscvalue);
+ m_target->m_detectInvisibilityMask |= (1 << GetMiscValue());
}
else
{
// recalculate value at modifier remove (current aura already removed)
m_target->m_detectInvisibilityMask = 0;
- Unit::AuraList const& auras = m_target->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
- for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- m_target->m_detectInvisibilityMask |= (1 << m_modifier.m_miscvalue);
+ Unit::AuraEffectList const& auras = m_target->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
+ for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
+ m_target->m_detectInvisibilityMask |= (1 << GetMiscValue());
}
if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
//ObjectAccessor::UpdateVisibilityForPlayer((Player*)m_target);
m_target->SetToNotify();
}
-void Aura::HandleAuraModRoot(bool apply, bool Real)
-{
- // only at real add/remove aura
- if(!Real)
- return;
-
- m_target->SetControlled(apply, UNIT_STAT_ROOT);
-}
-
-void Aura::HandleAuraModSilence(bool apply, bool Real)
+void AuraEffect::HandleAuraModSilence(bool apply, bool Real, bool /*changeAmount*/)
{
// only at real add/remove aura
if(!Real)
@@ -3251,38 +3984,8 @@ void Aura::HandleAuraModSilence(bool apply, bool Real)
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED);
// Stop cast only spells vs PreventionType == SPELL_PREVENTION_TYPE_SILENCE
for (uint32 i = CURRENT_MELEE_SPELL; i < CURRENT_MAX_SPELL;i++)
- {
- Spell* currentSpell = m_target->m_currentSpells[i];
- if (currentSpell && currentSpell->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
- {
- uint32 state = currentSpell->getState();
- // Stop spells on prepare or casting state
- if ( state == SPELL_STATE_PREPARING || state == SPELL_STATE_CASTING )
- {
- currentSpell->cancel();
- }
- }
- }
-
- switch (GetId())
- {
- // Arcane Torrent (Energy)
- case 25046:
- {
- Unit * caster = GetCaster();
- if (!caster)
- return;
-
- // Search Mana Tap auras on caster
- Aura * dummy = m_target->GetDummyAura(28734);
- if (dummy)
- {
- int32 bp = dummy->GetStackAmount() * 10;
- caster->CastCustomSpell(caster, 25048, &bp, NULL, NULL, true);
- m_target->RemoveAurasDueToSpell(28734);
- }
- }
- }
+ if (m_target->m_currentSpells[i] && m_target->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
+ m_target->InterruptSpell(i,false); // Stop spells on prepare or casting state
}
else
{
@@ -3294,10 +3997,10 @@ void Aura::HandleAuraModSilence(bool apply, bool Real)
}
}
-void Aura::HandleModThreat(bool apply, bool Real)
+void AuraEffect::HandleModThreat(bool apply, bool Real, bool changeAmount)
{
// only at real add/remove aura
- if(!Real)
+ if(!Real && !changeAmount)
return;
if(!m_target->isAlive())
@@ -3324,22 +4027,22 @@ void Aura::HandleModThreat(bool apply, bool Real)
break;
}
if (level_diff > 0)
- m_modifier.m_amount += multiplier * level_diff;
+ m_amount += multiplier * level_diff;
for(int8 x=0;x < MAX_SPELL_SCHOOL;x++)
{
- if(m_modifier.m_miscvalue & int32(1<<x))
+ if(GetMiscValue() & int32(1<<x))
{
if(m_target->GetTypeId() == TYPEID_PLAYER)
- ApplyPercentModFloatVar(m_target->m_threatModifier[x], m_positive ? GetModifierValue() : -GetModifierValue(), apply);
+ ApplyPercentModFloatVar(m_target->m_threatModifier[x], m_amount, apply);
}
}
}
-void Aura::HandleAuraModTotalThreat(bool apply, bool Real)
+void AuraEffect::HandleAuraModTotalThreat(bool apply, bool Real, bool changeAmount)
{
// only at real add/remove aura
- if(!Real)
+ if(!Real && !changeAmount)
return;
if(!m_target->isAlive() || m_target->GetTypeId()!= TYPEID_PLAYER)
@@ -3352,14 +4055,14 @@ void Aura::HandleAuraModTotalThreat(bool apply, bool Real)
float threatMod = 0.0f;
if(apply)
- threatMod = float(GetModifierValue());
+ threatMod = float(m_amount);
else
- threatMod = float(-GetModifierValue());
+ threatMod = float(-m_amount);
m_target->getHostilRefManager().threatAssist(caster, threatMod);
}
-void Aura::HandleModTaunt(bool apply, bool Real)
+void AuraEffect::HandleModTaunt(bool apply, bool Real, bool /*changeAmount*/)
{
// only at real add/remove aura
if(!Real)
@@ -3385,32 +4088,36 @@ void Aura::HandleModTaunt(bool apply, bool Real)
/*********************************************************/
/*** MODIFY SPEED ***/
/*********************************************************/
-void Aura::HandleAuraModIncreaseSpeed(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModIncreaseSpeed(bool apply, bool Real, bool changeAmount)
{
// all applied/removed only at real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
+ if(apply) // Dash wont work if you are not in cat form
+ if(m_spellProto->SpellFamilyName==SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[2] & 0x8 && m_target->m_form != FORM_CAT )
+ return;
+
m_target->UpdateSpeed(MOVE_RUN, true);
}
-void Aura::HandleAuraModIncreaseMountedSpeed(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModIncreaseMountedSpeed(bool /*apply*/, bool Real, bool changeAmount)
{
// all applied/removed only at real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
m_target->UpdateSpeed(MOVE_RUN, true);
}
-void Aura::HandleAuraModIncreaseFlightSpeed(bool apply, bool Real)
+void AuraEffect::HandleAuraModIncreaseFlightSpeed(bool apply, bool Real, bool changeAmount)
{
// all applied/removed only at real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
// Enable Fly mode for flying mounts
- if (m_modifier.m_auraname == SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED)
+ if (m_auraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)
{
WorldPacket data;
if(apply)
@@ -3426,38 +4133,37 @@ void Aura::HandleAuraModIncreaseFlightSpeed(bool apply, bool Real)
m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_POLYMORPH,apply);
// Dragonmaw Illusion (overwrite mount model, mounted aura already applied)
- if( apply && m_target->HasAura(42016,0) && m_target->GetMountID())
+ if( apply && m_target->HasAuraEffect(42016,0) && m_target->GetMountID())
m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314);
}
m_target->UpdateSpeed(MOVE_FLIGHT, true);
}
-void Aura::HandleAuraModIncreaseSwimSpeed(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModIncreaseSwimSpeed(bool /*apply*/, bool Real, bool changeAmount)
{
// all applied/removed only at real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
m_target->UpdateSpeed(MOVE_SWIM, true);
}
-void Aura::HandleAuraModDecreaseSpeed(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModDecreaseSpeed(bool /*apply*/, bool Real, bool changeAmount)
{
// all applied/removed only at real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
- //m_target->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
m_target->UpdateSpeed(MOVE_RUN, true);
m_target->UpdateSpeed(MOVE_SWIM, true);
m_target->UpdateSpeed(MOVE_FLIGHT, true);
}
-void Aura::HandleAuraModUseNormalSpeed(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModUseNormalSpeed(bool /*apply*/, bool Real, bool changeAmount)
{
// all applied/removed only at real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
m_target->UpdateSpeed(MOVE_RUN, true);
@@ -3469,51 +4175,84 @@ void Aura::HandleAuraModUseNormalSpeed(bool /*apply*/, bool Real)
/*** IMMUNITY ***/
/*********************************************************/
-void Aura::HandleModMechanicImmunity(bool apply, bool Real)
+void AuraEffect::HandleModStateImmunityMask(bool apply, bool Real, bool /*changeAmount*/)
+{
+ if (!Real)
+ return;
+ std::list <AuraType> immunity_list;
+ if (GetMiscValue() & (1<<10))
+ immunity_list.push_back(SPELL_AURA_MOD_STUN);
+ if (GetMiscValue() & (1<<7))
+ immunity_list.push_back(SPELL_AURA_MOD_DISARM);
+ if (GetMiscValue() & (1<<1))
+ immunity_list.push_back(SPELL_AURA_MOD_TAUNT);
+
+ // These flag can be recognized wrong:
+ if (GetMiscValue() & (1<<6))
+ immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
+ if (GetMiscValue() & (1<<0))
+ immunity_list.push_back(SPELL_AURA_MOD_ROOT);
+ if (GetMiscValue() & (1<<2))
+ immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
+ if (GetMiscValue() & (1<<9))
+ immunity_list.push_back(SPELL_AURA_MOD_FEAR);
+
+ // Patch 3.0.3 Bladestorm now breaks all snares and roots on the warrior when activated.
+ // however not all mechanic specified in immunity
+ if (apply && GetId()==46924)
+ {
+ m_target->RemoveAurasByType(SPELL_AURA_MOD_ROOT);
+ m_target->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
+ }
+
+ if(apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
+ {
+ for (std::list <AuraType>::iterator iter = immunity_list.begin(); iter != immunity_list.end();++iter)
+ {
+ m_target->RemoveAurasByType(*iter);
+ }
+ }
+ for (std::list <AuraType>::iterator iter = immunity_list.begin(); iter != immunity_list.end();++iter)
+ {
+ m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,*iter,apply);
+ }
+}
+
+void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeAmount*/)
{
- uint32 mechanic = 1 << m_modifier.m_miscvalue;
+ if (!Real)
+ return;
+ uint32 mechanic;
+ mechanic = 1 << GetMiscValue();
//immune movement impairment and loss of control
- if(GetId()==42292)
+ if(GetId()==42292 || GetId()==59752)
mechanic=IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+ if (!mechanic)
+ return;
if(apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
{
Unit::AuraMap& Auras = m_target->GetAuras();
- for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
+ for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end();)
{
- next = iter;
- ++next;
SpellEntry const *spell = iter->second->GetSpellProto();
- if (!( spell->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) // spells unaffected by invulnerability
- && !iter->second->IsPositive() // only remove negative spells
- && spell->Id != GetId())
+ if (spell->Id != GetId())
{
//check for mechanic mask
- if(GetSpellMechanicMask(spell, iter->second->GetEffIndex()) & mechanic)
+ if(GetAllSpellMechanicMask(spell) & mechanic)
{
- m_target->RemoveAurasDueToSpell(spell->Id);
- if(Auras.empty())
- break;
- else
- next = Auras.begin();
+ m_target->RemoveAura(iter);
}
+ else
+ ++iter;
}
+ else
+ ++iter;
}
}
- m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,m_modifier.m_miscvalue,apply);
-
- // special cases
- switch(m_modifier.m_miscvalue)
- {
- case MECHANIC_INVULNERABILITY:
- m_target->ModifyAuraState(AURA_STATE_FORBEARANCE,apply);
- break;
- case MECHANIC_SHIELD:
- m_target->ModifyAuraState(AURA_STATE_WEAKENED_SOUL,apply);
- break;
- }
+ m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,GetMiscValue(),apply);
// Bestial Wrath
if ( GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->Id == 19574)
@@ -3522,8 +4261,8 @@ void Aura::HandleModMechanicImmunity(bool apply, bool Real)
if ( Unit* owner = m_target->GetOwner() )
{
// Search talent
- Unit::AuraList const& m_dummyAuras = owner->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
+ Unit::AuraEffectList const& m_dummyAuras = owner->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
{
if ( (*i)->GetSpellProto()->SpellIconID == 2229 )
{
@@ -3542,10 +4281,10 @@ void Aura::HandleModMechanicImmunity(bool apply, bool Real)
{
if(apply)
{
- m_target->CastSpell(m_target,24395,true);
- m_target->CastSpell(m_target,24396,true);
- m_target->CastSpell(m_target,24397,true);
- m_target->CastSpell(m_target,26592,true);
+ m_target->CastSpell(m_target,24395,true, NULL, this);
+ m_target->CastSpell(m_target,24396,true, NULL, this);
+ m_target->CastSpell(m_target,24397,true, NULL, this);
+ m_target->CastSpell(m_target,26592,true, NULL, this);
}
else
{
@@ -3555,103 +4294,86 @@ void Aura::HandleModMechanicImmunity(bool apply, bool Real)
m_target->RemoveAurasDueToSpell(26592);
}
}
+
+ // Heroic Fury (remove Intercept cooldown)
+ else if( apply && GetId() == 60970 && m_target->GetTypeId() == TYPEID_PLAYER )
+ {
+ ((Player*)m_target)->RemoveSpellCooldown(20252, true);
+ }
+ // Demonic Empowerment -- voidwalker -- missing movement impairing effects immunity
+ else if (GetId() == 54508)
+ {
+ if (apply)
+ m_target->RemoveMovementImpairingAuras();
+
+ m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,SPELL_AURA_MOD_ROOT,apply);
+ m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,SPELL_AURA_MOD_DECREASE_SPEED,apply);
+ }
}
-void Aura::HandleAuraModEffectImmunity(bool apply, bool Real)
+//this method is called whenever we add / remove aura which gives m_target some imunity to some spell effect
+void AuraEffect::HandleAuraModEffectImmunity(bool apply, bool Real, bool /*changeAmount*/)
{
- if(!apply)
+ // when removing flag aura, handle flag drop
+ if( !apply && m_target->GetTypeId() == TYPEID_PLAYER
+ && (GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION) )
{
if(m_target->GetTypeId() == TYPEID_PLAYER)
{
if(((Player*)m_target)->InBattleGround())
{
- BattleGround *bg = ((Player*)m_target)->GetBattleGround();
- if(bg)
- {
- switch(bg->GetTypeID())
- {
- case BATTLEGROUND_AV:
- {
- break;
- }
- case BATTLEGROUND_WS:
- {
- // Warsong Flag, horde // Silverwing Flag, alliance
- if(GetId() == 23333 || GetId() == 23335)
- bg->EventPlayerDroppedFlag(((Player*)m_target));
- break;
- }
- case BATTLEGROUND_AB:
- {
- break;
- }
- case BATTLEGROUND_EY:
- {
- if(GetId() == 34976)
- bg->EventPlayerDroppedFlag(((Player*)m_target));
- break;
- }
- }
- }
+ if( BattleGround *bg = ((Player*)m_target)->GetBattleGround() )
+ bg->EventPlayerDroppedFlag(((Player*)m_target));
}
else
sOutdoorPvPMgr.HandleDropFlag((Player*)m_target,GetSpellProto()->Id);
}
}
- m_target->ApplySpellImmune(GetId(),IMMUNITY_EFFECT,m_modifier.m_miscvalue,apply);
+ m_target->ApplySpellImmune(GetId(),IMMUNITY_EFFECT,GetMiscValue(),apply);
}
-void Aura::HandleAuraModStateImmunity(bool apply, bool Real)
+void AuraEffect::HandleAuraModStateImmunity(bool apply, bool Real, bool /*changeAmount*/)
{
if(apply && Real && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
{
- Unit::AuraList const& auraList = m_target->GetAurasByType(AuraType(m_modifier.m_miscvalue));
- for(Unit::AuraList::const_iterator itr = auraList.begin(); itr != auraList.end();)
- {
- if (auraList.front() != this) // skip itself aura (it already added)
- {
- m_target->RemoveAurasDueToSpell(auraList.front()->GetId());
- itr = auraList.begin();
- }
- else
- ++itr;
- }
+ m_target->RemoveAurasByType(AuraType(GetMiscValue()), NULL , GetParentAura());
}
- m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,m_modifier.m_miscvalue,apply);
+ m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,GetMiscValue(),apply);
}
-void Aura::HandleAuraModSchoolImmunity(bool apply, bool Real)
+void AuraEffect::HandleAuraModSchoolImmunity(bool apply, bool Real, bool /*changeAmount*/)
{
- if(apply && m_modifier.m_miscvalue == SPELL_SCHOOL_MASK_NORMAL)
- m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_UNATTACKABLE);
+ if(apply && GetMiscValue() == SPELL_SCHOOL_MASK_NORMAL)
+ m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
+
+ m_target->ApplySpellImmune(GetId(),IMMUNITY_SCHOOL,GetMiscValue(),apply);
- m_target->ApplySpellImmune(GetId(),IMMUNITY_SCHOOL,m_modifier.m_miscvalue,apply);
+ // remove all flag auras (they are positive, but they must be removed when you are immune)
+ if( this->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
+ && this->GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_DAMAGE_REDUCED_SHIELD )
+ m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
- if(Real && apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
+ // TODO: optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else
+ if( Real && apply
+ && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
+ && IsPositiveSpell(GetId()) ) //Only positive immunity removes auras
{
- if(IsPositiveSpell(GetId())) //Only positive immunity removes auras
+ uint32 school_mask = GetMiscValue();
+ Unit::AuraMap& Auras = m_target->GetAuras();
+ for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end();)
{
- uint32 school_mask = m_modifier.m_miscvalue;
- Unit::AuraMap& Auras = m_target->GetAuras();
- for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
+ SpellEntry const *spell = iter->second->GetSpellProto();
+ if((GetSpellSchoolMask(spell) & school_mask)//Check for school mask
+ && IsDispelableBySpell(GetSpellProto(),spell->Id, true)
+ && !iter->second->IsPositive() //Don't remove positive spells
+ && spell->Id != GetId() ) //Don't remove self
{
- next = iter;
- ++next;
- SpellEntry const *spell = iter->second->GetSpellProto();
- if((GetSpellSchoolMask(spell) & school_mask)//Check for school mask
- && !( spell->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) //Spells unaffected by invulnerability
- && !iter->second->IsPositive() //Don't remove positive spells
- && spell->Id != GetId() ) //Don't remove self
- {
- m_target->RemoveAurasDueToSpell(spell->Id);
- if(Auras.empty())
- break;
- else
- next = Auras.begin();
- }
+ m_target->RemoveAura(iter);
}
+ else
+ ++iter;
}
}
if( Real && GetSpellProto()->Mechanic == MECHANIC_BANISH )
@@ -3663,40 +4385,27 @@ void Aura::HandleAuraModSchoolImmunity(bool apply, bool Real)
}
}
-void Aura::HandleAuraModDmgImmunity(bool apply, bool Real)
+void AuraEffect::HandleAuraModDmgImmunity(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->ApplySpellImmune(GetId(),IMMUNITY_DAMAGE,m_modifier.m_miscvalue,apply);
+ m_target->ApplySpellImmune(GetId(),IMMUNITY_DAMAGE,GetMiscValue(),apply);
}
-void Aura::HandleAuraModDispelImmunity(bool apply, bool Real)
+void AuraEffect::HandleAuraModDispelImmunity(bool apply, bool Real, bool /*changeAmount*/)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
- m_target->ApplySpellDispelImmunity(m_spellProto, DispelType(m_modifier.m_miscvalue), apply);
+ m_target->ApplySpellDispelImmunity(m_spellProto, DispelType(GetMiscValue()), apply);
}
-void Aura::HandleAuraProcTriggerSpell(bool apply, bool Real)
+void AuraEffect::HandleAuraProcTriggerSpell(bool apply, bool Real, bool /*changeAmount*/)
{
if(!Real)
return;
-
- if(apply)
- {
- // some spell have charges by functionality not have its in spell data
- switch (GetId())
- {
- case 28200: // Ascendance (Talisman of Ascendance trinket)
- m_procCharges = 6;
- UpdateAuraCharges();
- break;
- default: break;
- }
- }
}
-void Aura::HandleAuraModStalked(bool apply, bool Real)
+void AuraEffect::HandleAuraModStalked(bool apply, bool Real, bool /*changeAmount*/)
{
// used by spells: Hunter's Mark, Mind Vision, Syndicate Tracker (MURP) DND
if(apply)
@@ -3709,111 +4418,98 @@ void Aura::HandleAuraModStalked(bool apply, bool Real)
/*** PERIODIC ***/
/*********************************************************/
-void Aura::HandlePeriodicTriggerSpell(bool apply, bool Real)
+void AuraEffect::HandlePeriodicTriggerSpell(bool apply, bool Real, bool /*changeAmount*/)
{
- if (m_periodicTimer <= 0)
- m_periodicTimer += m_modifier.periodictime;
-
m_isPeriodic = apply;
- m_isTrigger = apply;
-
- // Curse of the Plaguebringer
- if (!apply && m_spellProto->Id == 29213 && m_removeMode!=AURA_REMOVE_BY_DISPEL)
+ if (Real && m_spellProto->Id == 66 && !apply)
{
- // Cast Wrath of the Plaguebringer if not dispelled
- m_target->CastSpell(m_target, 29214, true, 0, this);
+ if (GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
+ m_target->CastSpell(m_target, 32612, true, NULL, this);
}
+}
- // Wrath of the Astromancer
- if(!apply && m_spellProto->Id == 42783)
- {
- m_target->CastSpell(m_target, 42787, true, 0, this);
- }
+void AuraEffect::HandlePeriodicTriggerSpellWithValue(bool apply, bool Real, bool /*changeAmount*/)
+{
+ m_isPeriodic = apply;
}
-void Aura::HandlePeriodicEnergize(bool apply, bool Real)
+void AuraEffect::HandlePeriodicEnergize(bool apply, bool Real, bool changeAmount)
{
- if (m_periodicTimer <= 0)
- m_periodicTimer += m_modifier.periodictime;
+ if(!Real && !changeAmount)
+ return;
m_isPeriodic = apply;
+
+ // Replenishment (0.25% from max)
+ // Infinite Replenishment
+ if (m_spellProto->SpellIconID == 3184 && m_spellProto->SpellVisual[0] == 12495)
+ m_amount = m_target->GetMaxPower(POWER_MANA) * 25 / 10000;
}
-void Aura::HandlePeriodicHeal(bool apply, bool Real)
+void AuraEffect::HandleAuraPowerBurn(bool apply, bool Real, bool /*changeAmount*/)
{
- if (m_periodicTimer <= 0)
- m_periodicTimer += m_modifier.periodictime;
-
m_isPeriodic = apply;
+}
- // only at real apply
- if (Real && apply && GetSpellProto()->Mechanic == MECHANIC_BANDAGE)
- {
- // provided m_target as original caster to prevent apply aura caster selection for this negative buff
- m_target->CastSpell(m_target,11196,true,NULL,this,m_target->GetGUID());
- }
+void AuraEffect::HandleAuraPeriodicDummy(bool apply, bool Real, bool changeAmount)
+{
+ // spells required only Real aura add/remove
+ if(!Real && !changeAmount)
+ return;
// For prevent double apply bonuses
bool loading = (m_target->GetTypeId() == TYPEID_PLAYER && ((Player*)m_target)->GetSession()->PlayerLoading());
- if(!loading && apply)
+ Unit* caster = GetCaster();
+
+ SpellEntry const*spell = GetSpellProto();
+ switch( spell->SpellFamilyName)
{
- switch (m_spellProto->SpellFamilyName)
+ case SPELLFAMILY_HUNTER:
{
- case SPELLFAMILY_DRUID:
- {
- // Rejuvenation
- if(m_spellProto->SpellFamilyFlags & 0x0000000000000010LL)
- {
- if(Unit* caster = GetCaster())
- {
- Unit::AuraList const& classScripts = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator k = classScripts.begin(); k != classScripts.end(); ++k)
- {
- int32 tickcount = GetSpellDuration(m_spellProto) / m_spellProto->EffectAmplitude[m_effIndex];
- switch((*k)->GetModifier()->m_miscvalue)
- {
- case 4953: // Increased Rejuvenation Healing - Harold's Rejuvenating Broach Aura
- case 4415: // Increased Rejuvenation Healing - Idol of Rejuvenation Aura
- {
- m_modifier.m_amount += (*k)->GetModifier()->m_amount / tickcount;
- break;
- }
- }
- }
- }
- }
- }
+ // Explosive Shot
+ if (apply && !loading && caster)
+ m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 16 / 100);
+ break;
}
}
+
+ m_isPeriodic = apply;
+}
+
+void AuraEffect::HandlePeriodicHeal(bool apply, bool Real, bool /*changeAmount*/)
+{
+ m_isPeriodic = apply;
}
-void Aura::HandlePeriodicDamage(bool apply, bool Real)
+void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
- if (m_periodicTimer <= 0)
- m_periodicTimer += m_modifier.periodictime;
-
m_isPeriodic = apply;
// For prevent double apply bonuses
bool loading = (m_target->GetTypeId() == TYPEID_PLAYER && ((Player*)m_target)->GetSession()->PlayerLoading());
+ // Custom damage calculation after
+ if (!apply || loading)
+ return;
+
Unit *caster = GetCaster();
+ if (!caster)
+ return;
switch (m_spellProto->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
// Pounce Bleed
- if ( m_spellProto->SpellIconID == 147 && m_spellProto->SpellVisual == 0 )
+ if ( m_spellProto->SpellIconID == 147 && m_spellProto->SpellVisual[0] == 0 )
{
// $AP*0.18/6 bonus per tick
- if (apply && !loading && caster)
- m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100);
+ m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100);
return;
}
break;
@@ -3821,18 +4517,14 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
case SPELLFAMILY_WARRIOR:
{
// Rend
- if (m_spellProto->SpellFamilyFlags & 0x0000000000000020LL)
+ if (m_spellProto->SpellFamilyFlags[0] & 0x20)
{
- // 0.00743*(($MWB+$mwb)/2+$AP/14*$MWS) bonus per tick
- if (apply && !loading && caster)
- {
- float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
- int32 mws = caster->GetAttackTime(BASE_ATTACK);
- float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE);
- float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE);
- // WARNING! in 3.0 multiplier 0.00743f change to 0.6
- m_modifier.m_amount+=int32(((mwb_min+mwb_max)/2+ap*mws/14000)*0.00743f);
- }
+ // $0.2*(($MWB+$mwb)/2+$AP/14*$MWS) bonus per tick
+ float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
+ int32 mws = caster->GetAttackTime(BASE_ATTACK);
+ float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE);
+ float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE);
+ m_amount+=int32(((mwb_min+mwb_max)/2+ap*mws/14000)*0.2f);
return;
}
break;
@@ -3840,92 +4532,80 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
case SPELLFAMILY_DRUID:
{
// Rake
- if (m_spellProto->SpellFamilyFlags & 0x0000000000001000LL)
+ if (m_spellProto->SpellFamilyFlags[0] & 0x1000)
{
- // $AP*0.06/3 bonus per tick
- if (apply && !loading && caster)
- m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 2 / 100);
+ // $AP*0.06 bonus per tick
+ m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 6 / 100);
return;
}
// Lacerate
- if (m_spellProto->SpellFamilyFlags & 0x000000010000000000LL)
+ if (m_spellProto->SpellFamilyFlags[1] & 0x0000000100)
{
// $AP*0.05/5 bonus per tick
- if (apply && !loading && caster)
- m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
+ m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
return;
}
// Rip
- if (m_spellProto->SpellFamilyFlags & 0x000000000000800000LL)
+ if (m_spellProto->SpellFamilyFlags[1] & 0x800000)
{
- // $AP * min(0.06*$cp, 0.24)/6 [Yes, there is no difference, whether 4 or 5 CPs are being used]
- if (apply && !loading && caster && caster->GetTypeId() == TYPEID_PLAYER)
- {
- uint8 cp = ((Player*)caster)->GetComboPoints();
+ // 0.01*$AP*cp
+ if (caster->GetTypeId() != TYPEID_PLAYER)
+ return;
- // Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
- Unit::AuraList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
+ uint8 cp = ((Player*)caster)->GetComboPoints();
+
+ // Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
+ Unit::AuraEffectList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
+ {
+ if((*itr)->GetId()==34241)
{
- if((*itr)->GetId()==34241)
- {
- m_modifier.m_amount += cp * (*itr)->GetModifier()->m_amount;
- break;
- }
+ m_amount += cp * (*itr)->GetAmount();
+ break;
}
-
- if (cp > 4) cp = 4;
- m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100);
}
+ m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100);
+ return;
+ }
+ // Lock Jaw
+ if (m_spellProto->SpellFamilyFlags[1] & 0x10000000)
+ {
+ // 0.15*$AP
+ m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 15 / 100);
return;
}
break;
}
case SPELLFAMILY_ROGUE:
{
- // Deadly poison aura state
- if((m_spellProto->SpellFamilyFlags & 0x10000) && m_spellProto->SpellVisual==5100)
+ // Rupture
+ if (m_spellProto->SpellFamilyFlags[0] & 0x100000)
{
- if(apply)
- m_target->ModifyAuraState(AURA_STATE_DEADLY_POISON,true);
- else
- {
- // current aura already removed, search present of another
- bool found = false;
- Unit::AuraList const& auras = m_target->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
- for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- {
- SpellEntry const* itr_spell = (*itr)->GetSpellProto();
- if(itr_spell && itr_spell->SpellFamilyName==SPELLFAMILY_ROGUE && (itr_spell->SpellFamilyFlags & 0x10000) && itr_spell->SpellVisual==5100)
- {
- found = true;
- break;
- }
- }
- // this has been last deadly poison aura
- if(!found)
- m_target->ModifyAuraState(AURA_STATE_DEADLY_POISON,false);
- }
+ if (caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+ //1 point : ${($m1+$b1*1+0.015*$AP)*4} damage over 8 secs
+ //2 points: ${($m1+$b1*2+0.024*$AP)*5} damage over 10 secs
+ //3 points: ${($m1+$b1*3+0.03*$AP)*6} damage over 12 secs
+ //4 points: ${($m1+$b1*4+0.03428571*$AP)*7} damage over 14 secs
+ //5 points: ${($m1+$b1*5+0.0375*$AP)*8} damage over 16 secs
+ float AP_per_combo[6] = {0.0f, 0.015f, 0.024f, 0.03f, 0.03428571f, 0.0375f};
+ uint8 cp = ((Player*)caster)->GetComboPoints();
+ if (cp > 5) cp = 5;
+ m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * AP_per_combo[cp]);
return;
}
- // Rupture
- if (m_spellProto->SpellFamilyFlags & 0x000000000000100000LL)
+ // Garrote
+ if (m_spellProto->SpellFamilyFlags[0] & 0x100)
{
- // Dmg/tick = $AP*min(0.01*$cp, 0.03) [Like Rip: only the first three CP increase the contribution from AP]
- if (apply && !loading && caster && caster->GetTypeId() == TYPEID_PLAYER)
- {
- uint8 cp = ((Player*)caster)->GetComboPoints();
- if (cp > 3) cp = 3;
- m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100);
- }
+ // $AP*0.07 bonus per tick
+ m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 7 / 100);
return;
}
- // Garrote
- if (m_spellProto->SpellFamilyFlags & 0x000000000000000100LL)
+ // Deadly Poison
+ if (m_spellProto->SpellFamilyFlags[0] & 0x10000)
{
- // $AP*0.18/6 bonus per tick
- if (apply && !loading && caster)
- m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100);
+ // 0.08*$AP / 4 * amount of stack
+ m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 2 * GetParentAura()->GetStackAmount() / 100);
return;
}
break;
@@ -3933,47 +4613,17 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
case SPELLFAMILY_HUNTER:
{
// Serpent Sting
- if (m_spellProto->SpellFamilyFlags & 0x0000000000004000LL)
+ if (m_spellProto->SpellFamilyFlags[0] & 0x4000)
{
// $RAP*0.1/5 bonus per tick
- if (apply && !loading && caster)
- m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
+ m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
return;
}
// Immolation Trap
- if (m_spellProto->SpellFamilyFlags & 0x0000000000000004LL && m_spellProto->SpellIconID == 678)
+ if (m_spellProto->SpellFamilyFlags[0] & 0x4 && m_spellProto->SpellIconID == 678)
{
// $RAP*0.1/5 bonus per tick
- if (apply && !loading && caster)
- m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
- return;
- }
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- // Consecration
- if (m_spellProto->SpellFamilyFlags & 0x0000000000000020LL)
- {
- if (apply && !loading)
- {
- if(Unit* caster = GetCaster())
- {
- Unit::AuraList const& classScripts = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator k = classScripts.begin(); k != classScripts.end(); ++k)
- {
- int32 tickcount = GetSpellDuration(m_spellProto) / m_spellProto->EffectAmplitude[m_effIndex];
- switch((*k)->GetModifier()->m_miscvalue)
- {
- case 5147: // Improved Consecration - Libram of the Eternal Rest
- {
- m_modifier.m_amount += (*k)->GetModifier()->m_amount / tickcount;
- break;
- }
- }
- }
- }
- }
+ m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
return;
}
break;
@@ -3983,27 +4633,23 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
}
}
-void Aura::HandlePeriodicDamagePCT(bool apply, bool Real)
+void AuraEffect::HandlePeriodicDamagePCT(bool apply, bool Real, bool /*changeAmount*/)
{
- if (m_periodicTimer <= 0)
- m_periodicTimer += m_modifier.periodictime;
-
m_isPeriodic = apply;
}
-void Aura::HandlePeriodicLeech(bool apply, bool Real)
+void AuraEffect::HandlePeriodicLeech(bool apply, bool Real, bool /*changeAmount*/)
{
- if (m_periodicTimer <= 0)
- m_periodicTimer += m_modifier.periodictime;
-
m_isPeriodic = apply;
}
-void Aura::HandlePeriodicManaLeech(bool apply, bool Real)
+void AuraEffect::HandlePeriodicManaLeech(bool apply, bool Real, bool /*changeAmount*/)
{
- if (m_periodicTimer <= 0)
- m_periodicTimer += m_modifier.periodictime;
+ m_isPeriodic = apply;
+}
+void AuraEffect::HandlePeriodicHealthFunnel(bool apply, bool Real, bool /*changeAmount*/)
+{
m_isPeriodic = apply;
}
@@ -4015,90 +4661,82 @@ void Aura::HandlePeriodicManaLeech(bool apply, bool Real)
/*** RESISTANCE ***/
/********************************/
-void Aura::HandleAuraModResistanceExclusive(bool apply, bool Real)
+void AuraEffect::HandleAuraModResistanceExclusive(bool apply, bool Rea, bool /*changeAmount*/)
{
for(int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL;x++)
{
- if(m_modifier.m_miscvalue & int32(1<<x))
+ if(GetMiscValue() & int32(1<<x))
{
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, float(m_amount), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER)
- m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,GetModifierValue(), apply);
+ m_target->ApplyResistanceBuffModsMod(SpellSchools(x),GetParentAura()->IsPositive(),m_amount, apply);
}
}
}
-void Aura::HandleAuraModResistance(bool apply, bool Real)
+void AuraEffect::HandleAuraModResistance(bool apply, bool Real, bool /*changeAmount*/)
{
for(int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL;x++)
{
- if(m_modifier.m_miscvalue & int32(1<<x))
+ if(GetMiscValue() & int32(1<<x))
{
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(m_amount), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
- m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,GetModifierValue(), apply);
+ m_target->ApplyResistanceBuffModsMod(SpellSchools(x),GetParentAura()->IsPositive(),m_amount, apply);
}
}
- // Faerie Fire (druid versions)
- if( (m_spellProto->SpellIconID == 109 &&
- m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID &&
- m_spellProto->SpellFamilyFlags & 0x0000000000000400LL)
- || m_spellProto->Id == 35325)
- {
- m_target->ModifyAuraState(AURA_STATE_FAERIE_FIRE,apply);
- }
}
-void Aura::HandleAuraModBaseResistancePCT(bool apply, bool Real)
+void AuraEffect::HandleAuraModBaseResistancePCT(bool apply, bool Real, bool /*changeAmount*/)
{
// only players have base stats
if(m_target->GetTypeId() != TYPEID_PLAYER)
{
//pets only have base armor
- if(((Creature*)m_target)->isPet() && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
- m_target->HandleStatModifier(UNIT_MOD_ARMOR, BASE_PCT, float(GetModifierValue()), apply);
+ if(((Creature*)m_target)->isPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
+ m_target->HandleStatModifier(UNIT_MOD_ARMOR, BASE_PCT, float(m_amount), apply);
}
else
{
for(int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL;x++)
{
- if(m_modifier.m_miscvalue & int32(1<<x))
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetModifierValue()), apply);
+ if(GetMiscValue() & int32(1<<x))
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(m_amount), apply);
}
}
}
-void Aura::HandleModResistancePercent(bool apply, bool Real)
+void AuraEffect::HandleModResistancePercent(bool apply, bool Real, bool /*changeAmount*/)
{
for(int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
{
- if(m_modifier.m_miscvalue & int32(1<<i))
+ if(GetMiscValue() & int32(1<<i))
{
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(m_amount), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
{
- m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),true,GetModifierValue(), apply);
- m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),false,GetModifierValue(), apply);
+ m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),true,m_amount, apply);
+ m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),false,m_amount, apply);
}
}
}
}
-void Aura::HandleModBaseResistance(bool apply, bool Real)
+void AuraEffect::HandleModBaseResistance(bool apply, bool Real, bool /*changeAmount*/)
{
// only players have base stats
if(m_target->GetTypeId() != TYPEID_PLAYER)
{
//only pets have base stats
- if(((Creature*)m_target)->isPet() && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
- m_target->HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(GetModifierValue()), apply);
+ if(((Creature*)m_target)->isPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
+ m_target->HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(m_amount), apply);
}
else
{
for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
- if(m_modifier.m_miscvalue & (1<<i))
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetModifierValue()), apply);
+ if(GetMiscValue() & (1<<i))
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(m_amount), apply);
}
}
@@ -4106,30 +4744,30 @@ void Aura::HandleModBaseResistance(bool apply, bool Real)
/*** STAT ***/
/********************************/
-void Aura::HandleAuraModStat(bool apply, bool Real)
+void AuraEffect::HandleAuraModStat(bool apply, bool Real, bool /*changeAmount*/)
{
- if (m_modifier.m_miscvalue < -2 || m_modifier.m_miscvalue > 4)
+ if (GetMiscValue() < -2 || GetMiscValue() > 4)
{
- sLog.outError("WARNING: Spell %u effect %u have unsupported misc value (%i) for SPELL_AURA_MOD_STAT ",GetId(),GetEffIndex(),m_modifier.m_miscvalue);
+ sLog.outError("WARNING: Spell %u effect %u have unsupported misc value (%i) for SPELL_AURA_MOD_STAT ",GetId(),GetEffIndex(),GetMiscValue());
return;
}
for(int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
// -1 or -2 is all stats ( misc < -2 checked in function beginning )
- if (m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue == i)
+ if (GetMiscValue() < 0 || GetMiscValue() == i)
{
- //m_target->ApplyStatMod(Stats(i), m_modifier.m_amount,apply);
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetModifierValue()), apply);
+ //m_target->ApplyStatMod(Stats(i), m_amount,apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(m_amount), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
- m_target->ApplyStatBuffMod(Stats(i),GetModifierValue(),apply);
+ m_target->ApplyStatBuffMod(Stats(i),m_amount,apply);
}
}
}
-void Aura::HandleModPercentStat(bool apply, bool Real)
+void AuraEffect::HandleModPercentStat(bool apply, bool Real, bool /*changeAmount*/)
{
- if (m_modifier.m_miscvalue < -1 || m_modifier.m_miscvalue > 4)
+ if (GetMiscValue() < -1 || GetMiscValue() > 4)
{
sLog.outError("WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid");
return;
@@ -4141,12 +4779,12 @@ void Aura::HandleModPercentStat(bool apply, bool Real)
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
- if(m_modifier.m_miscvalue == i || m_modifier.m_miscvalue == -1)
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(GetModifierValue()), apply);
+ if(GetMiscValue() == i || GetMiscValue() == -1)
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount), apply);
}
}
-void Aura::HandleModSpellDamagePercentFromStat(bool /*apply*/, bool Real)
+void AuraEffect::HandleModSpellDamagePercentFromStat(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -4157,7 +4795,7 @@ void Aura::HandleModSpellDamagePercentFromStat(bool /*apply*/, bool Real)
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
}
-void Aura::HandleModSpellHealingPercentFromStat(bool /*apply*/, bool Real)
+void AuraEffect::HandleModSpellHealingPercentFromStat(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -4166,16 +4804,7 @@ void Aura::HandleModSpellHealingPercentFromStat(bool /*apply*/, bool Real)
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
}
-void Aura::HandleAuraModDispelResist(bool apply, bool Real)
-{
- if(!Real || !apply)
- return;
-
- if(GetId()==33206)
- m_target->CastSpell(m_target,44416,true,NULL,this,GetCasterGUID());
-}
-
-void Aura::HandleModSpellDamagePercentFromAttackPower(bool /*apply*/, bool Real)
+void AuraEffect::HandleModSpellDamagePercentFromAttackPower(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -4186,7 +4815,7 @@ void Aura::HandleModSpellDamagePercentFromAttackPower(bool /*apply*/, bool Real)
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
}
-void Aura::HandleModSpellHealingPercentFromAttackPower(bool /*apply*/, bool Real)
+void AuraEffect::HandleModSpellHealingPercentFromAttackPower(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -4195,7 +4824,7 @@ void Aura::HandleModSpellHealingPercentFromAttackPower(bool /*apply*/, bool Real
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
}
-void Aura::HandleModHealingDone(bool /*apply*/, bool Real)
+void AuraEffect::HandleModHealingDone(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -4204,9 +4833,9 @@ void Aura::HandleModHealingDone(bool /*apply*/, bool Real)
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
}
-void Aura::HandleModTotalPercentStat(bool apply, bool Real)
+void AuraEffect::HandleModTotalPercentStat(bool apply, bool Real, bool /*changeAmount*/)
{
- if (m_modifier.m_miscvalue < -1 || m_modifier.m_miscvalue > 4)
+ if (GetMiscValue() < -1 || GetMiscValue() > 4)
{
sLog.outError("WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid");
return;
@@ -4218,16 +4847,16 @@ void Aura::HandleModTotalPercentStat(bool apply, bool Real)
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
- if(m_modifier.m_miscvalue == i || m_modifier.m_miscvalue == -1)
+ if(GetMiscValue() == i || GetMiscValue() == -1)
{
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(m_amount), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
- m_target->ApplyStatPercentBuffMod(Stats(i), GetModifierValue(), apply );
+ m_target->ApplyStatPercentBuffMod(Stats(i), m_amount, apply );
}
}
//recalculate current HP/MP after applying aura modifications (only for spells with 0x10 flag)
- if ((m_modifier.m_miscvalue == STAT_STAMINA) && (maxHPValue > 0) && (m_spellProto->Attributes & 0x10))
+ if ((GetMiscValue() == STAT_STAMINA) && (maxHPValue > 0) && (m_spellProto->Attributes & 0x10))
{
// newHP = (curHP / maxHP) * newMaxHP = (newMaxHP * curHP) / maxHP -> which is better because no int -> double -> int conversion is needed
uint32 newHPValue = (m_target->GetMaxHealth() * curHPValue) / maxHPValue;
@@ -4235,12 +4864,12 @@ void Aura::HandleModTotalPercentStat(bool apply, bool Real)
}
}
-void Aura::HandleAuraModResistenceOfStatPercent(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModResistenceOfStatPercent(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
- if(m_modifier.m_miscvalue != SPELL_SCHOOL_MASK_NORMAL)
+ if(GetMiscValue() != SPELL_SCHOOL_MASK_NORMAL)
{
// support required adding replace UpdateArmor by loop by UpdateResistence at intellect update
// and include in UpdateResistence same code as in UpdateArmor for aura mod apply.
@@ -4255,145 +4884,70 @@ void Aura::HandleAuraModResistenceOfStatPercent(bool /*apply*/, bool Real)
/********************************/
/*** HEAL & ENERGIZE ***/
/********************************/
-void Aura::HandleAuraModTotalHealthPercentRegen(bool apply, bool Real)
+void AuraEffect::HandleAuraModTotalHealthPercentRegen(bool apply, bool Real, bool /*changeAmount*/)
{
- /*
- Need additional checking for auras who reduce or increase healing, magic effect like Dumpen Magic,
- so this aura not fully working.
- */
- if(apply)
- {
- if(!m_target->isAlive())
- return;
-
- if((GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) && !m_target->IsSitState())
- m_target->SetStandState(PLAYER_STATE_SIT);
-
- if(m_periodicTimer <= 0)
- {
- m_periodicTimer += m_modifier.periodictime;
-
- if(m_target->GetHealth() < m_target->GetMaxHealth())
- {
- // PeriodicTick can cast triggered spells with stats changes
- PeriodicTick();
- }
- }
- }
-
m_isPeriodic = apply;
}
-void Aura::HandleAuraModTotalManaPercentRegen(bool apply, bool Real)
+void AuraEffect::HandleAuraModTotalEnergyPercentRegen(bool apply, bool Real, bool /*changeAmount*/)
{
- if((GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) && apply && !m_target->IsSitState())
- m_target->SetStandState(PLAYER_STATE_SIT);
- if(apply)
- {
- if(m_modifier.periodictime == 0)
- m_modifier.periodictime = 1000;
- if(m_periodicTimer <= 0 && m_target->getPowerType() == POWER_MANA)
- {
- m_periodicTimer += m_modifier.periodictime;
-
- if(m_target->GetPower(POWER_MANA) < m_target->GetMaxPower(POWER_MANA))
- {
- // PeriodicTick can cast triggered spells with stats changes
- PeriodicTick();
- }
- }
- }
+ if(m_amplitude == 0)
+ m_amplitude = 1000;
+ m_periodicTimer = m_amplitude;
m_isPeriodic = apply;
}
-void Aura::HandleModRegen(bool apply, bool Real) // eating
+void AuraEffect::HandleModRegen(bool apply, bool Real, bool /*changeAmount*/) // eating
{
- if(apply)
- {
- if(!m_target->isAlive())
- return;
-
- if ((GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) && !m_target->IsSitState())
- m_target->SetStandState(PLAYER_STATE_SIT);
-
- if(m_periodicTimer <= 0)
- {
- m_periodicTimer += 5000;
- int32 gain = m_target->ModifyHealth(GetModifierValue());
- Unit *caster = GetCaster();
- if (caster)
- {
- SpellEntry const *spellProto = GetSpellProto();
- if (spellProto)
- m_target->getHostilRefManager().threatAssist(caster, float(gain) * 0.5f, spellProto);
- }
- }
- }
+ if(m_amplitude == 0)
+ m_amplitude = 5000;
+ m_periodicTimer = 5000;
m_isPeriodic = apply;
}
-void Aura::HandleModPowerRegen(bool apply, bool Real) // drinking
+void AuraEffect::HandleModPowerRegen(bool apply, bool Real, bool changeAmount) // drinking
{
- if ((GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) && apply && !m_target->IsSitState())
- m_target->SetStandState(PLAYER_STATE_SIT);
+ if(!Real && !changeAmount)
+ return;
- if(apply && m_periodicTimer <= 0)
+ Powers pt = m_target->getPowerType();
+ if(m_amplitude == 0)
{
-
- Powers pt = m_target->getPowerType();
+ // Anger Management (only spell use this aura for rage)
if (pt == POWER_RAGE)
- m_periodicTimer = 3000;
- else
- m_periodicTimer = 2000;
+ m_amplitude = 3000;
+ else
+ m_amplitude = 2000;
+ }
- if(int32(pt) != m_modifier.m_miscvalue)
- return;
+ m_periodicTimer = 5000;
- if ( GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED )
- {
- // eating anim
- m_target->HandleEmoteCommand(EMOTE_ONESHOT_EAT);
- }
- else if( GetId() == 20577 )
- {
- // cannibalize anim
- m_target->HandleEmoteCommand(398);
- }
+ if (m_target->GetTypeId() == TYPEID_PLAYER && GetMiscValue() == POWER_MANA)
+ ((Player*)m_target)->UpdateManaRegen();
- // Warrior talent, gain 1 rage every 3 seconds while in combat
- // Anger Menagement
- // amount = 1+ 16 = 17 = 3,4*5 = 10,2*5/3
- // so 17 is rounded amount for 5 sec tick grow ~ 1 range grow in 3 sec
- if(pt == POWER_RAGE)
- {
- m_target->ModifyPower(pt, m_modifier.m_amount*3/5);
- }
- }
m_isPeriodic = apply;
- if (Real && m_target->GetTypeId() == TYPEID_PLAYER && m_modifier.m_miscvalue == POWER_MANA)
- ((Player*)m_target)->UpdateManaRegen();
}
-void Aura::HandleModPowerRegenPCT(bool /*apply*/, bool Real)
+void AuraEffect::HandleModPowerRegenPCT(bool /*apply*/, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
if (m_target->GetTypeId() != TYPEID_PLAYER)
return;
// Update manaregen value
- if (m_modifier.m_miscvalue == POWER_MANA)
+ if (GetMiscValue() == POWER_MANA)
((Player*)m_target)->UpdateManaRegen();
}
-void Aura::HandleModManaRegen(bool /*apply*/, bool Real)
+void AuraEffect::HandleModManaRegen(bool /*apply*/, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
if (m_target->GetTypeId() != TYPEID_PLAYER)
@@ -4403,7 +4957,7 @@ void Aura::HandleModManaRegen(bool /*apply*/, bool Real)
((Player*)m_target)->UpdateManaRegen();
}
-void Aura::HandleComprehendLanguage(bool apply, bool Real)
+void AuraEffect::HandleComprehendLanguage(bool apply, bool Real, bool /*changeAmount*/)
{
if(apply)
m_target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG);
@@ -4411,32 +4965,32 @@ void Aura::HandleComprehendLanguage(bool apply, bool Real)
m_target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG);
}
-void Aura::HandleAuraModIncreaseHealth(bool apply, bool Real)
+void AuraEffect::HandleAuraModIncreaseHealth(bool apply, bool Real, bool changeAmount)
{
- if(Real)
+ if(Real || changeAmount)
{
if(apply)
{
- m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetModifierValue()), apply);
- m_target->ModifyHealth(m_modifier.m_amount);
+ m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_amount), apply);
+ m_target->ModifyHealth(m_amount);
}
else
{
- if (int32(m_target->GetHealth()) > m_modifier.m_amount)
- m_target->ModifyHealth(-m_modifier.m_amount);
+ if (int32(m_target->GetHealth()) > m_amount)
+ m_target->ModifyHealth(-m_amount);
else
m_target->SetHealth(1);
- m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_amount), apply);
}
}
}
-void Aura::HandleAuraModIncreaseMaxHealth(bool apply, bool Real)
+void AuraEffect::HandleAuraModIncreaseMaxHealth(bool apply, bool Real, bool /*changeAmount*/)
{
uint32 oldhealth = m_target->GetHealth();
double healthPercentage = (double)oldhealth / (double)m_target->GetMaxHealth();
- m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_amount), apply);
// refresh percentage
if(oldhealth > 0)
@@ -4449,38 +5003,43 @@ void Aura::HandleAuraModIncreaseMaxHealth(bool apply, bool Real)
}
}
-void Aura::HandleAuraModIncreaseEnergy(bool apply, bool Real)
+void AuraEffect::HandleAuraModIncreaseEnergy(bool apply, bool Real, bool /*changeAmount*/)
{
Powers powerType = m_target->getPowerType();
- if(int32(powerType) != m_modifier.m_miscvalue)
+ if(int32(powerType) != GetMiscValue())
return;
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType);
- m_target->HandleStatModifier(unitMod, TOTAL_VALUE, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(unitMod, TOTAL_VALUE, float(m_amount), apply);
}
-void Aura::HandleAuraModIncreaseEnergyPercent(bool apply, bool /*Real*/)
+void AuraEffect::HandleAuraModIncreaseEnergyPercent(bool apply, bool /*Real*/, bool /*changeAmount*/)
{
Powers powerType = m_target->getPowerType();
- if(int32(powerType) != m_modifier.m_miscvalue)
+ if(int32(powerType) != GetMiscValue())
return;
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType);
- m_target->HandleStatModifier(unitMod, TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(unitMod, TOTAL_PCT, float(m_amount), apply);
}
-void Aura::HandleAuraModIncreaseHealthPercent(bool apply, bool /*Real*/)
+void AuraEffect::HandleAuraModIncreaseHealthPercent(bool apply, bool /*Real*/, bool /*changeAmount*/)
{
- m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(m_amount), apply);
+}
+
+void AuraEffect::HandleAuraIncreaseBaseHealthPercent(bool apply, bool /*Real*/, bool /*changeAmount*/)
+{
+ m_target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(m_amount), apply);
}
/********************************/
/*** FIGHT ***/
/********************************/
-void Aura::HandleAuraModParryPercent(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModParryPercent(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId()!=TYPEID_PLAYER)
return;
@@ -4488,28 +5047,28 @@ void Aura::HandleAuraModParryPercent(bool /*apply*/, bool Real)
((Player*)m_target)->UpdateParryPercentage();
}
-void Aura::HandleAuraModDodgePercent(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModDodgePercent(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId()!=TYPEID_PLAYER)
return;
((Player*)m_target)->UpdateDodgePercentage();
- //sLog.outError("BONUS DODGE CHANCE: + %f", float(m_modifier.m_amount));
+ //sLog.outError("BONUS DODGE CHANCE: + %f", float(m_amount));
}
-void Aura::HandleAuraModBlockPercent(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModBlockPercent(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId()!=TYPEID_PLAYER)
return;
((Player*)m_target)->UpdateBlockPercentage();
- //sLog.outError("BONUS BLOCK CHANCE: + %f", float(m_modifier.m_amount));
+ //sLog.outError("BONUS BLOCK CHANCE: + %f", float(m_amount));
}
-void Aura::HandleAuraModRegenInterrupt(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModRegenInterrupt(bool /*apply*/, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
if(m_target->GetTypeId()!=TYPEID_PLAYER)
@@ -4518,13 +5077,13 @@ void Aura::HandleAuraModRegenInterrupt(bool /*apply*/, bool Real)
((Player*)m_target)->UpdateManaRegen();
}
-void Aura::HandleAuraModCritPercent(bool apply, bool Real)
+void AuraEffect::HandleAuraModCritPercent(bool apply, bool Real, bool changeAmount)
{
if(m_target->GetTypeId()!=TYPEID_PLAYER)
return;
// apply item specific bonuses for already equipped weapon
- if(Real)
+ if(Real || changeAmount)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
@@ -4533,13 +5092,13 @@ void Aura::HandleAuraModCritPercent(bool apply, bool Real)
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
- // m_modifier.m_miscvalue comparison with item generated damage types
+ // GetMiscValue() comparison with item generated damage types
if (GetSpellProto()->EquippedItemClass == -1)
{
- ((Player*)m_target)->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetModifierValue()), apply);
- ((Player*)m_target)->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetModifierValue()), apply);
- ((Player*)m_target)->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetModifierValue()), apply);
+ ((Player*)m_target)->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (m_amount), apply);
+ ((Player*)m_target)->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (m_amount), apply);
+ ((Player*)m_target)->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (m_amount), apply);
}
else
{
@@ -4547,21 +5106,36 @@ void Aura::HandleAuraModCritPercent(bool apply, bool Real)
}
}
-void Aura::HandleModHitChance(bool apply, bool Real)
+void AuraEffect::HandleModHitChance(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->m_modMeleeHitChance += apply ? GetModifierValue() : -GetModifierValue();
- m_target->m_modRangedHitChance += apply ? GetModifierValue() : -GetModifierValue();
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)m_target)->UpdateMeleeHitChances();
+ ((Player*)m_target)->UpdateRangedHitChances();
+ }
+ else
+ {
+ m_target->m_modMeleeHitChance += apply ? m_amount : (-m_amount);
+ m_target->m_modRangedHitChance += apply ? m_amount : (-m_amount);
+ }
}
-void Aura::HandleModSpellHitChance(bool apply, bool Real)
+void AuraEffect::HandleModSpellHitChance(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->m_modSpellHitChance += apply ? GetModifierValue(): -GetModifierValue();
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)m_target)->UpdateSpellHitChances();
+ }
+ else
+ {
+ m_target->m_modSpellHitChance += apply ? m_amount: (-m_amount);
+ }
}
-void Aura::HandleModSpellCritChance(bool apply, bool Real)
+void AuraEffect::HandleModSpellCritChance(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
if(m_target->GetTypeId() == TYPEID_PLAYER)
@@ -4570,21 +5144,21 @@ void Aura::HandleModSpellCritChance(bool apply, bool Real)
}
else
{
- m_target->m_baseSpellCritChance += apply ? GetModifierValue():-GetModifierValue();
+ m_target->m_baseSpellCritChance += apply ? m_amount:-m_amount;
}
}
-void Aura::HandleModSpellCritChanceShool(bool /*apply*/, bool Real)
+void AuraEffect::HandleModSpellCritChanceShool(bool /*apply*/, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
for(int school = SPELL_SCHOOL_NORMAL; school < MAX_SPELL_SCHOOL; ++school)
- if (m_modifier.m_miscvalue & (1<<school))
+ if (GetMiscValue() & (1<<school))
((Player*)m_target)->UpdateSpellCritChance(school);
}
@@ -4592,157 +5166,137 @@ void Aura::HandleModSpellCritChanceShool(bool /*apply*/, bool Real)
/*** ATTACK SPEED ***/
/********************************/
-void Aura::HandleModCastingSpeed(bool apply, bool Real)
+void AuraEffect::HandleModCastingSpeed(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->ApplyCastTimePercentMod(GetModifierValue(),apply);
+ m_target->ApplyCastTimePercentMod(m_amount,apply);
}
-void Aura::HandleModMeleeRangedSpeedPct(bool apply, bool Real)
+void AuraEffect::HandleModMeleeRangedSpeedPct(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->ApplyAttackTimePercentMod(BASE_ATTACK,GetModifierValue(),apply);
- m_target->ApplyAttackTimePercentMod(OFF_ATTACK,GetModifierValue(),apply);
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, GetModifierValue(), apply);
+ m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(OFF_ATTACK,m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_amount, apply);
}
-void Aura::HandleModCombatSpeedPct(bool apply, bool Real)
+void AuraEffect::HandleModCombatSpeedPct(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->ApplyCastTimePercentMod(GetModifierValue(),apply);
- m_target->ApplyAttackTimePercentMod(BASE_ATTACK,GetModifierValue(),apply);
- m_target->ApplyAttackTimePercentMod(OFF_ATTACK,GetModifierValue(),apply);
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, GetModifierValue(), apply);
+ m_target->ApplyCastTimePercentMod(m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(OFF_ATTACK,m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_amount, apply);
}
-void Aura::HandleModAttackSpeed(bool apply, bool Real)
+void AuraEffect::HandleModAttackSpeed(bool apply, bool Real, bool /*changeAmount*/)
{
if(!m_target->isAlive() )
return;
- m_target->ApplyAttackTimePercentMod(BASE_ATTACK,GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_amount,apply);
}
-void Aura::HandleHaste(bool apply, bool Real)
+void AuraEffect::HandleHaste(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->ApplyAttackTimePercentMod(BASE_ATTACK, GetModifierValue(),apply);
- m_target->ApplyAttackTimePercentMod(OFF_ATTACK, GetModifierValue(),apply);
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(BASE_ATTACK, m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(OFF_ATTACK, m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,m_amount,apply);
}
-void Aura::HandleAuraModRangedHaste(bool apply, bool Real)
+void AuraEffect::HandleAuraModRangedHaste(bool apply, bool Real, bool /*changeAmount*/)
{
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, GetModifierValue(), apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_amount, apply);
}
-void Aura::HandleRangedAmmoHaste(bool apply, bool Real)
+void AuraEffect::HandleRangedAmmoHaste(bool apply, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,GetModifierValue(), apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,m_amount, apply);
}
/********************************/
/*** ATTACK POWER ***/
/********************************/
-void Aura::HandleAuraModAttackPower(bool apply, bool Real)
-{
- m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetModifierValue()), apply);
- if(apply)
- switch(m_spellProto->Id){
- // Warrior & Druid Demoshout should remove stealth
- case 1160:
- case 6190:
- case 11554:
- case 11555:
- case 11556:
- case 25202:
- case 25203:
- case 47437: //WotLK spell
- case 99:
- case 1735:
- case 9490:
- case 9747:
- case 9898:
- case 26998:
- case 48559: //WotLK spell
- case 48560: //WotLK spell
- m_target->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- break;
- }
-}
-
-void Aura::HandleAuraModRangedAttackPower(bool apply, bool Real)
+void AuraEffect::HandleAuraModAttackPower(bool apply, bool Real, bool /*changeAmount*/)
+{
+ m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(m_amount), apply);
+}
+
+void AuraEffect::HandleAuraModRangedAttackPower(bool apply, bool Real, bool /*changeAmount*/)
{
if((m_target->getClassMask() & CLASSMASK_WAND_USERS)!=0)
return;
- m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(m_amount), apply);
}
-void Aura::HandleAuraModAttackPowerPercent(bool apply, bool Real)
+void AuraEffect::HandleAuraModAttackPowerPercent(bool apply, bool Real, bool /*changeAmount*/)
{
//UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1
- m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(m_amount), apply);
}
-void Aura::HandleAuraModRangedAttackPowerPercent(bool apply, bool Real)
+void AuraEffect::HandleAuraModRangedAttackPowerPercent(bool apply, bool Real, bool /*changeAmount*/)
{
if((m_target->getClassMask() & CLASSMASK_WAND_USERS)!=0)
return;
//UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1
- m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(m_amount), apply);
}
-void Aura::HandleAuraModRangedAttackPowerOfStatPercent(bool apply, bool Real)
+void AuraEffect::HandleAuraModRangedAttackPowerOfStatPercent(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
- if(m_target->GetTypeId() == TYPEID_PLAYER && (m_target->getClassMask() & CLASSMASK_WAND_USERS)!=0)
- return;
+ // Recalculate bonus
+ if(m_target->GetTypeId() == TYPEID_PLAYER && !(m_target->getClassMask() & CLASSMASK_WAND_USERS))
+ ((Player*)m_target)->UpdateAttackPowerAndDamage(true);
+}
- if(m_modifier.m_miscvalue != STAT_INTELLECT)
- {
- // support required adding UpdateAttackPowerAndDamage calls at stat update
- sLog.outError("Aura SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT (212) need support non-intellect stats!");
+void AuraEffect::HandleAuraModAttackPowerOfStatPercent(bool apply, bool Real, bool changeAmount)
+{
+ // spells required only Real aura add/remove
+ if(!Real && !changeAmount)
return;
- }
// Recalculate bonus
- ((Player*)m_target)->UpdateAttackPowerAndDamage(true);
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)m_target)->UpdateAttackPowerAndDamage(false);
}
/********************************/
/*** DAMAGE BONUS ***/
/********************************/
-void Aura::HandleModDamageDone(bool apply, bool Real)
+void AuraEffect::HandleModDamageDone(bool apply, bool Real, bool changeAmount)
{
// apply item specific bonuses for already equipped weapon
- if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
+ if((Real || changeAmount) && m_target->GetTypeId()==TYPEID_PLAYER)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
((Player*)m_target)->_ApplyWeaponDependentAuraDamageMod(pItem,WeaponAttackType(i),this,apply);
}
- // m_modifier.m_miscvalue is bitmask of spell schools
+ // GetMiscValue() is bitmask of spell schools
// 1 ( 0-bit ) - normal school damage (SPELL_SCHOOL_MASK_NORMAL)
// 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands
// 127 - full bitmask any damages
//
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
- // m_modifier.m_miscvalue comparison with item generated damage types
+ // GetMiscValue() comparison with item generated damage types
- if((m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) != 0)
+ if((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0)
{
// apply generic physical damage bonuses including wand case
if (GetSpellProto()->EquippedItemClass == -1 || m_target->GetTypeId() != TYPEID_PLAYER)
{
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetModifierValue()), apply);
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetModifierValue()), apply);
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(m_amount), apply);
}
else
{
@@ -4751,15 +5305,15 @@ void Aura::HandleModDamageDone(bool apply, bool Real)
if(m_target->GetTypeId() == TYPEID_PLAYER)
{
- if(m_positive)
- m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS,GetModifierValue(),apply);
+ if(GetParentAura()->IsPositive())
+ m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS,m_amount,apply);
else
- m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG,GetModifierValue(),apply);
+ m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG,m_amount,apply);
}
}
// Skip non magic case for speedup
- if((m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_MAGIC) == 0)
+ if((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0)
return;
if( GetSpellProto()->EquippedItemClass != -1 || GetSpellProto()->EquippedItemInventoryTypeMask != 0 )
@@ -4775,57 +5329,57 @@ void Aura::HandleModDamageDone(bool apply, bool Real)
// This information for client side use only
if(m_target->GetTypeId() == TYPEID_PLAYER)
{
- if(m_positive)
+ if(GetParentAura()->IsPositive())
{
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
{
- if((m_modifier.m_miscvalue & (1<<i)) != 0)
- m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i,GetModifierValue(),apply);
+ if((GetMiscValue() & (1<<i)) != 0)
+ m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i,m_amount,apply);
}
}
else
{
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
{
- if((m_modifier.m_miscvalue & (1<<i)) != 0)
- m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i,GetModifierValue(),apply);
+ if((GetMiscValue() & (1<<i)) != 0)
+ m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i,m_amount,apply);
}
}
- Pet* pet = m_target->GetPet();
+ Pet* pet = ((Player*)m_target)->GetPet();
if(pet)
pet->UpdateAttackPowerAndDamage();
}
}
-void Aura::HandleModDamagePercentDone(bool apply, bool Real)
+void AuraEffect::HandleModDamagePercentDone(bool apply, bool Real, bool changeAmount)
{
- sLog.outDebug("AURA MOD DAMAGE type:%u negative:%u", m_modifier.m_miscvalue, m_positive ? 0 : 1);
+ sLog.outDebug("AURA MOD DAMAGE type:%u negative:%u", GetMiscValue(), GetParentAura()->IsPositive() ? 0 : 1);
// apply item specific bonuses for already equipped weapon
- if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
+ if((Real || changeAmount) && m_target->GetTypeId()==TYPEID_PLAYER)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
((Player*)m_target)->_ApplyWeaponDependentAuraDamageMod(pItem,WeaponAttackType(i),this,apply);
}
- // m_modifier.m_miscvalue is bitmask of spell schools
+ // GetMiscValue() is bitmask of spell schools
// 1 ( 0-bit ) - normal school damage (SPELL_SCHOOL_MASK_NORMAL)
// 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wand
// 127 - full bitmask any damages
//
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
- // m_modifier.m_miscvalue comparison with item generated damage types
+ // GetMiscValue() comparison with item generated damage types
- if((m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) != 0)
+ if((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0)
{
// apply generic physical damage bonuses including wand case
if (GetSpellProto()->EquippedItemClass == -1 || m_target->GetTypeId() != TYPEID_PLAYER)
{
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetModifierValue()), apply);
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetModifierValue()), apply);
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(m_amount), apply);
}
else
{
@@ -4833,11 +5387,11 @@ void Aura::HandleModDamagePercentDone(bool apply, bool Real)
}
// For show in client
if(m_target->GetTypeId() == TYPEID_PLAYER)
- m_target->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT,m_modifier.m_amount/100.0f,apply);
+ m_target->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT,m_amount/100.0f,apply);
}
// Skip non magic case for speedup
- if((m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_MAGIC) == 0)
+ if((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0)
return;
if( GetSpellProto()->EquippedItemClass != -1 || GetSpellProto()->EquippedItemInventoryTypeMask != 0 )
@@ -4853,190 +5407,88 @@ void Aura::HandleModDamagePercentDone(bool apply, bool Real)
// Send info to client
if(m_target->GetTypeId() == TYPEID_PLAYER)
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
- m_target->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT+i,m_modifier.m_amount/100.0f,apply);
+ m_target->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT+i,m_amount/100.0f,apply);
}
-void Aura::HandleModOffhandDamagePercent(bool apply, bool Real)
+void AuraEffect::HandleModOffhandDamagePercent(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
sLog.outDebug("AURA MOD OFFHAND DAMAGE");
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(m_amount), apply);
}
/********************************/
/*** POWER COST ***/
/********************************/
-void Aura::HandleModPowerCostPCT(bool apply, bool Real)
+void AuraEffect::HandleModPowerCostPCT(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
- float amount = GetModifierValue() /100.0f;
+ float amount = m_amount /100.0f;
for(int i = 0; i < MAX_SPELL_SCHOOL; ++i)
- if(m_modifier.m_miscvalue & (1<<i))
+ if(GetMiscValue() & (1<<i))
m_target->ApplyModSignedFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+i,amount,apply);
}
-void Aura::HandleModPowerCost(bool apply, bool Real)
+void AuraEffect::HandleModPowerCost(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
for(int i = 0; i < MAX_SPELL_SCHOOL; ++i)
- if(m_modifier.m_miscvalue & (1<<i))
- m_target->ApplyModInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i,GetModifierValue(),apply);
+ if(GetMiscValue() & (1<<i))
+ m_target->ApplyModInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i,m_amount,apply);
+}
+
+void AuraEffect::HandleNoReagentUseAura(bool Apply, bool Real, bool /*changeAmount*/)
+{
+ // spells required only Real aura add/remove
+ if(!Real)
+ return;
+ if(m_target->GetTypeId() != TYPEID_PLAYER)
+ return;
+ flag96 mask;
+ Unit::AuraEffectList const& noReagent = m_target->GetAurasByType(SPELL_AURA_NO_REAGENT_USE);
+ for(Unit::AuraEffectList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i)
+ mask |= (*i)->m_spellProto->EffectSpellClassMask[(*i)->m_effIndex];
+
+ m_target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1 , mask[0]);
+ m_target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+1, mask[1]);
+ m_target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+2, mask[2]);
}
/*********************************************************/
/*** OTHERS ***/
/*********************************************************/
-void Aura::HandleShapeshiftBoosts(bool apply)
+void AuraEffect::HandleAuraAllowOnlyAbility(bool apply, bool Real, bool /*changeAmount*/)
{
- uint32 spellId = 0;
- uint32 spellId2 = 0;
- uint32 HotWSpellId = 0;
-
- switch(GetModifier()->m_miscvalue)
- {
- case FORM_CAT:
- spellId = 3025;
- HotWSpellId = 24900;
- break;
- case FORM_TREE:
- spellId = 5420;
- break;
- case FORM_TRAVEL:
- spellId = 5419;
- break;
- case FORM_AQUA:
- spellId = 5421;
- break;
- case FORM_BEAR:
- spellId = 1178;
- spellId2 = 21178;
- HotWSpellId = 24899;
- break;
- case FORM_DIREBEAR:
- spellId = 9635;
- spellId2 = 21178;
- HotWSpellId = 24899;
- break;
- case FORM_BATTLESTANCE:
- spellId = 21156;
- break;
- case FORM_DEFENSIVESTANCE:
- spellId = 7376;
- break;
- case FORM_BERSERKERSTANCE:
- spellId = 7381;
- break;
- case FORM_MOONKIN:
- spellId = 24905;
- // aura from effect trigger spell
- spellId2 = 24907;
- break;
- case FORM_FLIGHT:
- spellId = 33948;
- break;
- case FORM_FLIGHT_EPIC:
- spellId = 40122;
- spellId2 = 40121;
- break;
- case FORM_SPIRITOFREDEMPTION:
- spellId = 27792;
- spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation.
- break;
- case FORM_GHOSTWOLF:
- case FORM_AMBIENT:
- case FORM_GHOUL:
- case FORM_SHADOW:
- case FORM_STEALTH:
- case FORM_CREATURECAT:
- case FORM_CREATUREBEAR:
- spellId = 0;
- break;
- }
-
- uint32 form = GetModifier()->m_miscvalue-1;
-
- if(apply)
- {
- if (spellId) m_target->CastSpell(m_target, spellId, true, NULL, this );
- if (spellId2) m_target->CastSpell(m_target, spellId2, true, NULL, this);
+ if(!Real)
+ return;
- if(m_target->GetTypeId() == TYPEID_PLAYER)
- {
- const PlayerSpellMap& sp_list = ((Player *)m_target)->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
- {
- if(itr->second->state == PLAYERSPELL_REMOVED) continue;
- if(itr->first==spellId || itr->first==spellId2) continue;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
- if (!spellInfo || !(spellInfo->Attributes & ((1<<6) | (1<<7)))) continue;
- if (spellInfo->Stances & (1<<form))
- m_target->CastSpell(m_target, itr->first, true, NULL, this);
- }
- //LotP
- if (((Player*)m_target)->HasSpell(17007))
- {
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(24932);
- if (spellInfo && spellInfo->Stances & (1<<form))
- m_target->CastSpell(m_target, 24932, true, NULL, this);
- }
- // HotW
- if (HotWSpellId)
- {
- Unit::AuraList const& mModTotalStatPct = m_target->GetAurasByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
- for(Unit::AuraList::const_iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i)
- {
- if ((*i)->GetSpellProto()->SpellIconID == 240 && (*i)->GetModifier()->m_miscvalue == 3)
- {
- int32 HotWMod = (*i)->GetModifier()->m_amount;
- if(GetModifier()->m_miscvalue == FORM_CAT)
- HotWMod /= 2;
+ if(!apply && m_target->HasAuraType(SPELL_AURA_ALLOW_ONLY_ABILITY))
+ return;
- m_target->CastCustomSpell(m_target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this);
- break;
- }
- }
- }
- }
- }
- else
+ if(m_target->GetTypeId()==TYPEID_PLAYER)
{
- m_target->RemoveAurasDueToSpell(spellId);
- m_target->RemoveAurasDueToSpell(spellId2);
-
- Unit::AuraMap& tAuras = m_target->GetAuras();
- for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
- {
- if (itr->second->IsRemovedOnShapeLost())
- {
- m_target->RemoveAurasDueToSpell(itr->second->GetId());
- itr = tAuras.begin();
- }
- else
- {
- ++itr;
- }
- }
+ if (apply)
+ m_target->SetFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY);
+ else
+ m_target->RemoveFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY);
}
-
- /*double healthPercentage = (double)m_target->GetHealth() / (double)m_target->GetMaxHealth();
- m_target->SetHealth(uint32(ceil((double)m_target->GetMaxHealth() * healthPercentage)));*/
}
-void Aura::HandleAuraEmpathy(bool apply, bool Real)
+void AuraEffect::HandleAuraEmpathy(bool apply, bool Real, bool /*changeAmount*/)
{
- if(m_target->GetTypeId() != TYPEID_UNIT)
+ if(!Real || m_target->GetTypeId() != TYPEID_UNIT)
return;
CreatureInfo const * ci = objmgr.GetCreatureTemplate(m_target->GetEntry());
@@ -5044,43 +5496,43 @@ void Aura::HandleAuraEmpathy(bool apply, bool Real)
m_target->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply);
}
-void Aura::HandleAuraUntrackable(bool apply, bool Real)
+void AuraEffect::HandleAuraUntrackable(bool apply, bool Real, bool /*changeAmount*/)
{
+ if (!Real)
+ return;
if(apply)
- m_target->SetFlag(UNIT_FIELD_BYTES_1, PLAYER_STATE_FLAG_UNTRACKABLE);
+ m_target->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE);
else
- m_target->RemoveFlag(UNIT_FIELD_BYTES_1, PLAYER_STATE_FLAG_UNTRACKABLE);
+ m_target->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE);
}
-void Aura::HandleAuraModPacify(bool apply, bool Real)
+void AuraEffect::HandleAuraModPacify(bool apply, bool Real, bool /*changeAmount*/)
{
- if(m_target->GetTypeId() != TYPEID_PLAYER)
+ if(!Real || m_target->GetTypeId() != TYPEID_PLAYER)
return;
if(apply)
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
else
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
-
-
- if(m_spellProto->Id == 45839){
- if(apply){
- m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- }else{
- m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- }
- }
}
-void Aura::HandleAuraModPacifyAndSilence(bool apply, bool Real)
+void AuraEffect::HandleAuraModPacifyAndSilence(bool apply, bool Real, bool changeAmount)
{
- HandleAuraModPacify(apply,Real);
- HandleAuraModSilence(apply,Real);
+ if(m_spellProto->Id == 45839)
+ {
+ if(apply)
+ m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ else
+ m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ }
+ HandleAuraModPacify(apply,Real, changeAmount);
+ HandleAuraModSilence(apply,Real, changeAmount);
}
-void Aura::HandleAuraGhost(bool apply, bool Real)
+void AuraEffect::HandleAuraGhost(bool apply, bool Real, bool /*changeAmount*/)
{
- if(m_target->GetTypeId() != TYPEID_PLAYER)
+ if(!Real || m_target->GetTypeId() != TYPEID_PLAYER)
return;
if(apply)
@@ -5093,7 +5545,7 @@ void Aura::HandleAuraGhost(bool apply, bool Real)
}
}
-void Aura::HandleAuraAllowFlight(bool apply, bool Real)
+void AuraEffect::HandleAuraAllowFlight(bool apply, bool Real, bool /*changeAmount*/)
{
// all applied/removed only at real aura add/remove
if(!Real)
@@ -5102,29 +5554,57 @@ void Aura::HandleAuraAllowFlight(bool apply, bool Real)
// allow fly
WorldPacket data;
if(apply)
+ {
data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12);
+ if(m_target->GetTypeId() == TYPEID_UNIT)
+ {
+ m_target->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0x02);
+ m_target->AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
+ }
+ }
else
+ {
data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12);
+ if(m_target->GetTypeId() == TYPEID_UNIT)
+ {
+ m_target->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, 0x02);
+ m_target->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING2);
+ }
+ }
data.append(m_target->GetPackGUID());
data << uint32(0); // unk
m_target->SendMessageToSet(&data, true);
}
-void Aura::HandleModRating(bool apply, bool Real)
+void AuraEffect::HandleModRating(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
- if (m_modifier.m_miscvalue & (1 << rating))
- ((Player*)m_target)->ApplyRatingMod(CombatRating(rating), GetModifierValue(), apply);
+ if (GetMiscValue() & (1 << rating))
+ ((Player*)m_target)->ApplyRatingMod(CombatRating(rating), m_amount, apply);
+}
+
+void AuraEffect::HandleModRatingFromStat(bool apply, bool Real, bool changeAmount)
+{
+ // spells required only Real aura add/remove
+ if(!Real && !changeAmount)
+ return;
+
+ if(m_target->GetTypeId() != TYPEID_PLAYER)
+ return;
+ // Just recalculate ratings
+ for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ if (GetMiscValue() & (1 << rating))
+ ((Player*)m_target)->ApplyRatingMod(CombatRating(rating), 0, apply);
}
-void Aura::HandleForceMoveForward(bool apply, bool Real)
+void AuraEffect::HandleForceMoveForward(bool apply, bool Real, bool /*changeAmount*/)
{
if(!Real || m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -5134,7 +5614,7 @@ void Aura::HandleForceMoveForward(bool apply, bool Real)
m_target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE);
}
-void Aura::HandleAuraModExpertise(bool /*apply*/, bool Real)
+void AuraEffect::HandleAuraModExpertise(bool /*apply*/, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -5143,36 +5623,36 @@ void Aura::HandleAuraModExpertise(bool /*apply*/, bool Real)
((Player*)m_target)->UpdateExpertise(OFF_ATTACK);
}
-void Aura::HandleModTargetResistance(bool apply, bool Real)
+void AuraEffect::HandleModTargetResistance(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
// applied to damage as HandleNoImmediateEffect in Unit::CalcAbsorbResist and Unit::CalcArmorReducedDamage
// show armor penetration
- if (m_target->GetTypeId() == TYPEID_PLAYER && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
- m_target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE,GetModifierValue(), apply);
+ if (m_target->GetTypeId() == TYPEID_PLAYER && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
+ m_target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE,m_amount, apply);
// show as spell penetration only full spell penetration bonuses (all resistances except armor and holy
- if (m_target->GetTypeId() == TYPEID_PLAYER && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_SPELL)==SPELL_SCHOOL_MASK_SPELL)
- m_target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE,GetModifierValue(), apply);
+ if (m_target->GetTypeId() == TYPEID_PLAYER && (GetMiscValue() & SPELL_SCHOOL_MASK_SPELL)==SPELL_SCHOOL_MASK_SPELL)
+ m_target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE,m_amount, apply);
}
-void Aura::HandleShieldBlockValue(bool apply, bool Real)
+void AuraEffect::HandleShieldBlockValue(bool apply, bool Real, bool /*changeAmount*/)
{
BaseModType modType = FLAT_MOD;
- if(m_modifier.m_auraname == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT)
+ if(m_auraName == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT)
modType = PCT_MOD;
if(m_target->GetTypeId() == TYPEID_PLAYER)
- ((Player*)m_target)->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetModifierValue()), apply);
+ ((Player*)m_target)->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(m_amount), apply);
}
-void Aura::HandleAuraRetainComboPoints(bool apply, bool Real)
+void AuraEffect::HandleAuraRetainComboPoints(bool apply, bool Real, bool changeAmount)
{
// spells required only Real aura add/remove
- if(!Real)
+ if(!Real && !changeAmount)
return;
if(m_target->GetTypeId() != TYPEID_PLAYER)
@@ -5182,23 +5662,26 @@ void Aura::HandleAuraRetainComboPoints(bool apply, bool Real)
// combo points was added in SPELL_EFFECT_ADD_COMBO_POINTS handler
// remove only if aura expire by time (in case combo points amount change aura removed without combo points lost)
- if( !apply && m_duration==0 && target->GetComboTarget())
+ if( !apply && GetParentAura()->GetAuraDuration()==0 && target->GetComboTarget())
if(Unit* unit = ObjectAccessor::GetUnit(*m_target,target->GetComboTarget()))
- target->AddComboPoints(unit, -GetModifierValue());
+ target->AddComboPoints(unit, -m_amount);
}
-void Aura::HandleModUnattackable( bool Apply, bool Real )
+void AuraEffect::HandleModUnattackable( bool Apply, bool Real , bool /*changeAmount*/)
{
- if(Real && Apply)
+ if(!Real)
+ return;
+
+ if(Apply)
{
m_target->CombatStop();
- m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_UNATTACKABLE);
+ m_target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
}
- m_target->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE,Apply);
+ m_target->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, Apply);
}
-void Aura::HandleSpiritOfRedemption( bool apply, bool Real )
+void AuraEffect::HandleSpiritOfRedemption( bool apply, bool Real , bool /*changeAmount*/)
{
// spells required only Real aura add/remove
if(!Real)
@@ -5214,7 +5697,7 @@ void Aura::HandleSpiritOfRedemption( bool apply, bool Real )
// set stand state (expected in this form)
if(!m_target->IsStandState())
- m_target->SetStandState(PLAYER_STATE_NONE);
+ m_target->SetStandState(UNIT_STAND_STATE_STAND);
}
m_target->SetHealth(1);
@@ -5224,38 +5707,9 @@ void Aura::HandleSpiritOfRedemption( bool apply, bool Real )
m_target->setDeathState(JUST_DIED);
}
-void Aura::CleanupTriggeredSpells()
+void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount)
{
- uint32 tSpellId = m_spellProto->EffectTriggerSpell[GetEffIndex()];
- if(!tSpellId)
- return;
-
- SpellEntry const* tProto = sSpellStore.LookupEntry(tSpellId);
- if(!tProto)
- return;
-
- if(GetSpellDuration(tProto) != -1)
- return;
-
- // needed for spell 43680, maybe others
- // TODO: is there a spell flag, which can solve this in a more sophisticated way?
- if(m_spellProto->EffectApplyAuraName[GetEffIndex()] == SPELL_AURA_PERIODIC_TRIGGER_SPELL &&
- GetSpellDuration(m_spellProto) == m_spellProto->EffectAmplitude[GetEffIndex()])
- return;
- m_target->RemoveAurasDueToSpell(tSpellId);
-}
-
-void Aura::HandleAuraPowerBurn(bool apply, bool Real)
-{
- if (m_periodicTimer <= 0)
- m_periodicTimer += m_modifier.periodictime;
-
- m_isPeriodic = apply;
-}
-
-void Aura::HandleSchoolAbsorb(bool apply, bool Real)
-{
- if(!Real)
+ if(!Real && !changeAmount)
return;
// prevent double apply bonuses
@@ -5267,29 +5721,36 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real)
switch(m_spellProto->SpellFamilyName)
{
case SPELLFAMILY_PRIEST:
- if(m_spellProto->SpellFamilyFlags == 0x1) //PW:S
+ // PW: S
+ if(m_spellProto->SpellFamilyFlags.IsEqual(0x1, 0, 0x400))
{
- //+30% from +healing bonus
- DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.3f;
- break;
+ // +80.68% from sp bonus
+ DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.8068f;
}
break;
case SPELLFAMILY_MAGE:
- if(m_spellProto->SpellFamilyFlags == 0x80100 || m_spellProto->SpellFamilyFlags == 0x8 || m_spellProto->SpellFamilyFlags == 0x100000000LL)
+ // ice barrier
+ if(m_spellProto->SpellFamilyFlags.IsEqual(0, 0x1, 0x8))
+ {
+ // +80.67% from sp bonus
+ DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.8067f;
+ }
+ /*
+ TODO: find the correct spell power coefficient for frost ward and fire ward (if has)
+ // frost ward, fire ward
+ else if(m_spellProto->SpellFamilyFlags.IsEqual(0x100, 0, 0x8) || m_spellProto->SpellFamilyFlags.IsEqual(0x8, 0, 0x8))
{
- //frost ward, fire ward, ice barrier
//+10% from +spd bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.1f;
- break;
}
+ */
break;
case SPELLFAMILY_WARLOCK:
- if(m_spellProto->SpellFamilyFlags == 0x00)
+ // shadow ward
+ if(m_spellProto->SpellFamilyFlags.IsEqual(0, 0, 0x40))
{
- //shadow ward
- //+10% from +spd bonus
- DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.1f;
- break;
+ // +30% from sp bonus
+ DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.3f;
}
break;
default:
@@ -5298,17 +5759,17 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real)
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
- m_modifier.m_amount += (int32)DoneActualBenefit;
+ m_amount += (int32)DoneActualBenefit;
}
}
}
-void Aura::PeriodicTick()
+void AuraEffect::PeriodicTick()
{
if(!m_target->isAlive())
return;
- switch(m_modifier.m_auraname)
+ switch(GetAuraName())
{
case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
@@ -5317,16 +5778,17 @@ void Aura::PeriodicTick()
if(!pCaster)
return;
+ // Consecrate ticks can miss and will not show up in the combat log
if( GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_PERSISTENT_AREA_AURA &&
pCaster->SpellHitResult(m_target,GetSpellProto(),false)!=SPELL_MISS_NONE)
return;
// Check for immune (not use charges)
- if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
+ if(m_target->IsImmunedToDamage(GetSpellProto()))
return;
// some auras remove at specific health level or more
- if(m_modifier.m_auraname==SPELL_AURA_PERIODIC_DAMAGE)
+ if(m_auraName==SPELL_AURA_PERIODIC_DAMAGE)
{
switch(GetId())
{
@@ -5353,19 +5815,20 @@ void Aura::PeriodicTick()
}
case 41337:// aura of anger
{
- Unit::AuraList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for(Unit::AuraList::const_iterator i = mMod.begin(); i != mMod.end(); ++i)
+ Unit::AuraEffectList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
+ for(Unit::AuraEffectList::const_iterator i = mMod.begin(); i != mMod.end(); ++i)
{
if ((*i)->GetId() == 41337)
{
(*i)->ApplyModifier(false);
- (*i)->GetModifier()->m_amount += 5;
+ (*i)->SetAmount((*i)->GetAmount()+5);
(*i)->ApplyModifier(true);
break;
}
}
- m_modifier.m_amount = 100 * m_tickNumber;
- }break;
+ m_amount = 100 * m_tickNumber;
+ break;
+ }
default:
break;
}
@@ -5376,30 +5839,27 @@ void Aura::PeriodicTick()
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
// ignore non positive values (can be result apply spellmods to aura damage
- uint32 amount = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0;
+ //uint32 amount = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0;
+ uint32 pdamage = GetAmount() > 0 ? GetAmount() : 0;
- uint32 pdamage;
-
- if(m_modifier.m_auraname == SPELL_AURA_PERIODIC_DAMAGE)
+ if(GetAuraName() == SPELL_AURA_PERIODIC_DAMAGE)
{
- pdamage = pCaster->SpellDamageBonus(m_target,GetSpellProto(),amount,DOT);
+ pdamage = pCaster->SpellDamageBonus(m_target, GetSpellProto(), pdamage, DOT, GetParentAura()->GetStackAmount());
// Calculate armor mitigation if it is a physical spell
// But not for bleed mechanic spells
if ( GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL &&
GetEffectMechanic(GetSpellProto(), m_effIndex) != MECHANIC_BLEED)
{
- uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage);
+ uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage, GetSpellProto());
cleanDamage.damage += pdamage - pdamageReductedArmor;
pdamage = pdamageReductedArmor;
}
- //pdamage = pCaster->SpellDamageBonus(m_target,GetSpellProto(),pdamage,DOT);
-
// Curse of Agony damage-per-tick calculation
- if (GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 0x0000000000000400LL) && GetSpellProto()->SpellIconID==544)
+ if (GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags[0] & 0x400) && GetSpellProto()->SpellIconID==544)
{
- uint32 totalTick = m_maxduration / m_modifier.periodictime;
+ uint32 totalTick = GetParentAura()->GetAuraMaxDuration() / m_amplitude;
// 1..4 ticks, 1/2 from normal tick damage
if(m_tickNumber <= totalTick / 3)
pdamage = pdamage/2;
@@ -5410,27 +5870,28 @@ void Aura::PeriodicTick()
}
}
else
- pdamage = uint32(m_target->GetMaxHealth()*amount/100);
+ pdamage = uint32(m_target->GetMaxHealth()*pdamage/100);
//As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit
// Reduce dot damage from resilience for players
if (m_target->GetTypeId()==TYPEID_PLAYER)
pdamage-=((Player*)m_target)->GetDotDamageReduction(pdamage);
- pdamage *= GetStackAmount();
-
- pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist);
+ pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist, m_spellProto);
sLog.outDetail("PeriodicTick: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId(),absorb);
+ pCaster->DealDamageMods(m_target,pdamage,&absorb);
+
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
data.append(m_target->GetPackGUID());
data.appendPackGUID(GetCasterGUID());
data << uint32(GetId());
data << uint32(1);
- data << uint32(m_modifier.m_auraname);
+ data << uint32(m_auraName);
data << (uint32)pdamage;
+ data << uint32(0); // overkill
data << (uint32)GetSpellSchoolMask(GetSpellProto()); // will be mask in 2.4.x
data << (uint32)absorb;
data << (uint32)resist;
@@ -5452,6 +5913,7 @@ void Aura::PeriodicTick()
break;
}
case SPELL_AURA_PERIODIC_LEECH:
+ case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
{
Unit *pCaster = GetCaster();
if(!pCaster)
@@ -5464,88 +5926,32 @@ void Aura::PeriodicTick()
pCaster->SpellHitResult(m_target,GetSpellProto(),false)!=SPELL_MISS_NONE)
return;
- // Check for immune (not use charges)
- if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
+ // Check for immune
+ if(m_target->IsImmunedToDamage(GetSpellProto()))
return;
uint32 absorb=0;
uint32 resist=0;
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
- uint32 pdamage = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0;
- pdamage = pCaster->SpellDamageBonus(m_target,GetSpellProto(),pdamage,DOT);
+ //uint32 pdamage = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0;
+ uint32 pdamage = GetAmount() > 0 ? GetAmount() : 0;
+ pdamage = pCaster->SpellDamageBonus(m_target, GetSpellProto(), pdamage, DOT, GetParentAura()->GetStackAmount());
//Calculate armor mitigation if it is a physical spell
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)
{
- uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage);
+ uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage, GetSpellProto());
cleanDamage.damage += pdamage - pdamageReductedArmor;
pdamage = pdamageReductedArmor;
}
- //pdamage = pCaster->SpellDamageBonus(m_target,GetSpellProto(),pdamage,DOT);
-
- // talent Soul Siphon add bonus to Drain Life spells
- if( GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 0x8) )
- {
- // find talent max bonus percentage
- Unit::AuraList const& mClassScriptAuras = pCaster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator i = mClassScriptAuras.begin(); i != mClassScriptAuras.end(); ++i)
- {
- if ((*i)->GetModifier()->m_miscvalue == 4992 || (*i)->GetModifier()->m_miscvalue == 4993)
- {
- if((*i)->GetEffIndex()!=1)
- {
- sLog.outError("Expected spell %u structure change, need code update",(*i)->GetId());
- break;
- }
-
- // effect 1 m_amount
- int32 maxPercent = (*i)->GetModifier()->m_amount;
- // effect 0 m_amount
- int32 stepPercent = pCaster->CalculateSpellDamage((*i)->GetSpellProto(),0,(*i)->GetSpellProto()->EffectBasePoints[0],pCaster);
-
- // count affliction effects and calc additional damage in percentage
- int32 modPercent = 0;
- Unit::AuraMap const& victimAuras = m_target->GetAuras();
- for (Unit::AuraMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
- {
- Aura* aura = itr->second;
- if (aura->IsPositive())continue;
- SpellEntry const* m_spell = aura->GetSpellProto();
- if (m_spell->SpellFamilyName != SPELLFAMILY_WARLOCK)
- continue;
-
- SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(m_spell->Id);
- SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(m_spell->Id);
-
- for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
- {
- if(_spell_idx->second->skillId == SKILL_AFFLICTION)
- {
- modPercent += stepPercent;
- if (modPercent >= maxPercent)
- {
- modPercent = maxPercent;
- break;
- }
- }
- }
- }
- pdamage += (pdamage*modPercent/100);
- break;
- }
- }
- }
-
//As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit
// Reduce dot damage from resilience for players
if (m_target->GetTypeId()==TYPEID_PLAYER)
pdamage-=((Player*)m_target)->GetDotDamageReduction(pdamage);
- pdamage *= GetStackAmount();
-
- pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist);
+ pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist, m_spellProto);
if(m_target->GetHealth() < pdamage)
pdamage = uint32(m_target->GetHealth());
@@ -5555,10 +5961,10 @@ void Aura::PeriodicTick()
pCaster->SendSpellNonMeleeDamageLog(m_target, GetId(), pdamage, GetSpellSchoolMask(GetSpellProto()), absorb, resist, false, 0);
-
Unit* target = m_target; // aura can be deleted in DealDamage
SpellEntry const* spellProto = GetSpellProto();
float multiplier = spellProto->EffectMultipleValue[GetEffIndex()] > 0 ? spellProto->EffectMultipleValue[GetEffIndex()] : 1;
+ int32 stackAmount = GetParentAura()->GetStackAmount();
// Set trigger flag
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;
@@ -5579,16 +5985,13 @@ void Aura::PeriodicTick()
}
}
-
if(Player *modOwner = pCaster->GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
- uint32 heal = pCaster->SpellHealingBonus(spellProto, uint32(new_damage * multiplier), DOT, pCaster);
+ uint32 heal = uint32(pCaster->SpellHealingBonus(pCaster, spellProto, uint32(new_damage * multiplier), DOT, stackAmount));
- int32 gain = pCaster->ModifyHealth(heal);
+ int32 gain = pCaster->DealHeal(pCaster, heal, spellProto);
pCaster->getHostilRefManager().threatAssist(pCaster, gain * 0.5f, spellProto);
-
- pCaster->SendHealSpellLog(pCaster, spellProto->Id, heal);
break;
}
case SPELL_AURA_PERIODIC_HEAL:
@@ -5599,53 +6002,50 @@ void Aura::PeriodicTick()
return;
// heal for caster damage (must be alive)
- if(m_target != pCaster && GetSpellProto()->SpellVisual==163 && !pCaster->isAlive())
+ if(m_target != pCaster && GetSpellProto()->SpellVisual[0]==163 && !pCaster->isAlive())
return;
- // ignore non positive values (can be result apply spellmods to aura damage
- uint32 amount = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0;
+ if(GetParentAura()->GetAuraDuration() ==-1 && m_target->GetHealth()==m_target->GetMaxHealth())
+ return;
- uint32 pdamage;
+ // ignore non positive values (can be result apply spellmods to aura damage
+ //uint32 amount = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0;
+ int32 pdamage = GetAmount() > 0 ? GetAmount() : 0;
- if(m_modifier.m_auraname==SPELL_AURA_OBS_MOD_HEALTH)
- pdamage = uint32(m_target->GetMaxHealth() * amount/100);
+ if(m_auraName==SPELL_AURA_OBS_MOD_HEALTH)
+ pdamage = uint32(m_target->GetMaxHealth() * pdamage * GetParentAura()->GetStackAmount() / 100);
else
- pdamage = pCaster->SpellHealingBonus(GetSpellProto(), amount, DOT, m_target);
-
- pdamage *= GetStackAmount();
-
- //pdamage = pCaster->SpellHealingBonus(GetSpellProto(), pdamage, DOT, m_target);
+ pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetParentAura()->GetStackAmount());
sLog.outDetail("PeriodicTick: %u (TypeId: %u) heal of %u (TypeId: %u) for %u health inflicted by %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
+ int32 gain = m_target->ModifyHealth(pdamage);
+
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
data.append(m_target->GetPackGUID());
data.appendPackGUID(GetCasterGUID());
data << uint32(GetId());
data << uint32(1);
- data << uint32(m_modifier.m_auraname);
+ data << uint32(m_auraName);
data << (uint32)pdamage;
+ data << uint32(pdamage - gain); // wotlk
m_target->SendMessageToSet(&data,true);
- int32 gain = m_target->ModifyHealth(pdamage);
-
// add HoTs to amount healed in bgs
if( pCaster->GetTypeId() == TYPEID_PLAYER )
if( BattleGround *bg = ((Player*)pCaster)->GetBattleGround() )
bg->UpdatePlayerScore(((Player*)pCaster), SCORE_HEALING_DONE, gain);
- //Do check before because m_modifier.auraName can be invalidate by DealDamage.
- bool procSpell = (m_modifier.m_auraname == SPELL_AURA_PERIODIC_HEAL && m_target != pCaster);
-
m_target->getHostilRefManager().threatAssist(pCaster, float(gain) * 0.5f, GetSpellProto());
Unit* target = m_target; // aura can be deleted in DealDamage
SpellEntry const* spellProto = GetSpellProto();
- bool haveCastItem = GetCastItemGUID()!=0;
+ bool haveCastItem = GetParentAura()->GetCastItemGUID()!=0;
+ // Health Funnel
// heal for caster damage
- if(m_target!=pCaster && spellProto->SpellVisual==163)
+ if(m_target!=pCaster && spellProto->SpellVisual[0]==163)
{
uint32 dmg = spellProto->manaPerSecond;
if(pCaster->GetHealth() <= dmg && pCaster->GetTypeId()==TYPEID_PLAYER)
@@ -5665,10 +6065,13 @@ void Aura::PeriodicTick()
}
else
{
- pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), gain, GetSpellSchoolMask(GetSpellProto()), 0, 0, false, 0, false);
+ uint32 damage = gain;
+ uint32 absorb = 0;
+ pCaster->DealDamageMods(pCaster,damage,&absorb);
+ pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), damage, GetSpellSchoolMask(GetSpellProto()), absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
- pCaster->DealDamage(pCaster, gain, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true);
+ pCaster->DealDamage(pCaster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true);
}
}
@@ -5676,12 +6079,21 @@ void Aura::PeriodicTick()
uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;
uint32 procEx = PROC_EX_INTERNAL_HOT | PROC_EX_NORMAL_HIT;
// ignore item heals
- if(procSpell && !haveCastItem)
+ if(!haveCastItem)
pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, pdamage, BASE_ATTACK, spellProto);
break;
}
case SPELL_AURA_PERIODIC_MANA_LEECH:
{
+ if(GetMiscValue() < 0 || GetMiscValue() >= MAX_POWERS)
+ return;
+
+ Powers power = Powers(GetMiscValue());
+
+ // power type might have changed between aura applying and tick (druid's shapeshift)
+ if(m_target->getPowerType() != power)
+ return;
+
Unit *pCaster = GetCaster();
if(!pCaster)
return;
@@ -5694,24 +6106,26 @@ void Aura::PeriodicTick()
return;
// Check for immune (not use charges)
- if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
+ if(m_target->IsImmunedToDamage(GetSpellProto()))
return;
// ignore non positive values (can be result apply spellmods to aura damage
- uint32 pdamage = GetModifierValue() > 0 ? GetModifierValue() : 0;
+ uint32 pdamage = m_amount > 0 ? m_amount : 0;
+
+ // Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana)
+ // It's mana percent cost spells, m_amount is percent drain from target
+ if (m_spellProto->ManaCostPercentage)
+ {
+ // max value
+ uint32 maxmana = pCaster->GetMaxPower(power) * pdamage * 2 / 100;
+ pdamage = m_target->GetMaxPower(power) * pdamage / 100;
+ if(pdamage > maxmana)
+ pdamage = maxmana;
+ }
sLog.outDetail("PeriodicTick: %u (TypeId: %u) power leech of %u (TypeId: %u) for %u dmg inflicted by %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
- if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue > 4)
- break;
-
- Powers power = Powers(m_modifier.m_miscvalue);
-
- // power type might have changed between aura applying and tick (druid's shapeshift)
- if(m_target->getPowerType() != power)
- break;
-
int32 drain_amount = m_target->GetPower(power) > pdamage ? pdamage : m_target->GetPower(power);
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
@@ -5735,7 +6149,7 @@ void Aura::PeriodicTick()
data.appendPackGUID(GetCasterGUID());
data << uint32(GetId());
data << uint32(1);
- data << uint32(m_modifier.m_auraname);
+ data << uint32(m_auraName);
data << (uint32)power; // power type
data << (uint32)drain_amount;
data << (float)gain_multiplier;
@@ -5754,7 +6168,7 @@ void Aura::PeriodicTick()
{
m_target->CastSpell(m_target, 31463, true, 0, this);
// Remove aura
- SetAuraDuration(0);
+ GetParentAura()->SetAuraDuration(0);
}
// Mark of Kazzak
@@ -5767,67 +6181,78 @@ void Aura::PeriodicTick()
{
m_target->CastSpell(m_target, 32961, true, 0, this);
// Remove aura
- SetAuraDuration(0);
+ GetParentAura()->SetAuraDuration(0);
}
}
break;
}
- case SPELL_AURA_PERIODIC_ENERGIZE:
+ case SPELL_AURA_OBS_MOD_ENERGY:
{
- // ignore non positive values (can be result apply spellmods to aura damage
- uint32 pdamage = GetModifierValue() > 0 ? GetModifierValue() : 0;
+ if(GetMiscValue() < 0)
+ return;
- sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u",
- GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
+ Powers power;
+ if (GetMiscValue() == POWER_ALL)
+ power = m_target->getPowerType();
+ else
+ power = Powers(GetMiscValue());
- if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue > 4)
- break;
+ if(m_target->GetMaxPower(power) == 0)
+ return;
- Powers power = Powers(m_modifier.m_miscvalue);
+ if(GetParentAura()->GetAuraDuration() ==-1 && m_target->GetPower(power)==m_target->GetMaxPower(power))
+ return;
- if(m_target->GetMaxPower(power) == 0)
- break;
+ uint32 amount = m_amount * m_target->GetMaxPower(power) /100;
+ sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u",
+ GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), amount, GetId());
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
data.append(m_target->GetPackGUID());
data.appendPackGUID(GetCasterGUID());
data << uint32(GetId());
data << uint32(1);
- data << uint32(m_modifier.m_auraname);
- data << (uint32)power; // power type
- data << (uint32)pdamage;
+ data << uint32(m_auraName);
+ data << uint32(power); // power type
+ data << (uint32)amount;
m_target->SendMessageToSet(&data,true);
- int32 gain = m_target->ModifyPower(power,pdamage);
+ int32 gain = m_target->ModifyPower(power,amount);
if(Unit* pCaster = GetCaster())
m_target->getHostilRefManager().threatAssist(pCaster, float(gain) * 0.5f, GetSpellProto());
break;
}
- case SPELL_AURA_OBS_MOD_MANA:
+ case SPELL_AURA_PERIODIC_ENERGIZE:
{
// ignore non positive values (can be result apply spellmods to aura damage
- uint32 amount = GetModifierValue() > 0 ? GetModifierValue() : 0;
+ if(m_amount < 0 || GetMiscValue() >= MAX_POWERS)
+ return;
- uint32 pdamage = uint32(m_target->GetMaxPower(POWER_MANA) * amount/100);
+ Powers power = Powers(GetMiscValue());
- sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u mana inflicted by %u",
- GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
+ if(m_target->GetMaxPower(power) == 0)
+ return;
- if(m_target->GetMaxPower(POWER_MANA) == 0)
- break;
+ if(GetParentAura()->GetAuraDuration() ==-1 && m_target->GetPower(power)==m_target->GetMaxPower(power))
+ return;
+
+ uint32 amount = m_amount;
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
data.append(m_target->GetPackGUID());
data.appendPackGUID(GetCasterGUID());
data << uint32(GetId());
data << uint32(1);
- data << uint32(m_modifier.m_auraname);
- data << (uint32)0; // ?
- data << (uint32)pdamage;
+ data << uint32(m_auraName);
+ data << (uint32)power; // power type
+ data << (uint32)amount;
m_target->SendMessageToSet(&data,true);
- int32 gain = m_target->ModifyPower(POWER_MANA, pdamage);
+ sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u",
+ GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), amount, GetId());
+
+ int32 gain = m_target->ModifyPower(power,amount);
if(Unit* pCaster = GetCaster())
m_target->getHostilRefManager().threatAssist(pCaster, float(gain) * 0.5f, GetSpellProto());
@@ -5840,12 +6265,12 @@ void Aura::PeriodicTick()
return;
// Check for immune (not use charges)
- if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
+ if(m_target->IsImmunedToDamage(GetSpellProto()))
return;
- int32 pdamage = GetModifierValue() > 0 ? GetModifierValue() : 0;
+ int32 pdamage = m_amount > 0 ? m_amount : 0;
- Powers powerType = Powers(m_modifier.m_miscvalue);
+ Powers powerType = Powers(GetMiscValue());
if(!m_target->isAlive() || m_target->getPowerType() != powerType)
return;
@@ -5863,6 +6288,9 @@ void Aura::PeriodicTick()
SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask);
//no SpellDamageBonus for burn mana
pCaster->CalculateSpellDamageTaken(&damageInfo, gain, spellProto);
+
+ pCaster->DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
+
pCaster->SendSpellNonMeleeDamageLog(&damageInfo);
// Set trigger flag
@@ -5877,127 +6305,150 @@ void Aura::PeriodicTick()
pCaster->DealSpellDamage(&damageInfo, true);
break;
}
+ case SPELL_AURA_MOD_REGEN:
+ {
+ int32 gain = m_target->ModifyHealth(m_amount);
+ if (Unit *caster = GetCaster())
+ m_target->getHostilRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellProto());
+ break;
+ }
+ case SPELL_AURA_MOD_POWER_REGEN:
+ {
+ Powers pt = m_target->getPowerType();
+ if(int32(pt) != GetMiscValue())
+ return;
+
+ if ( GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED )
+ {
+ // eating anim
+ m_target->HandleEmoteCommand(EMOTE_ONESHOT_EAT);
+ }
+ else if( GetId() == 20577 )
+ {
+ // cannibalize anim
+ m_target->HandleEmoteCommand(EMOTE_STATE_CANNIBALIZE);
+ }
+ // Butchery
+ else if (m_spellProto->SpellFamilyName==SPELLFAMILY_DEATHKNIGHT
+ && m_spellProto->SpellIconID==2664)
+ {
+ if (m_target->isInCombat())
+ m_target->ModifyPower(pt,m_amount);
+ }
+
+ // Anger Management
+ // amount = 1+ 16 = 17 = 3,4*5 = 10,2*5/3
+ // so 17 is rounded amount for 5 sec tick grow ~ 1 range grow in 3 sec
+ if(pt == POWER_RAGE)
+ m_target->ModifyPower(pt, m_amount*3/5);
+ break;
+ }
+ case SPELL_AURA_DUMMY:
+ {
+ // Haunting Spirits
+ if (GetId() == 7057)
+ {
+ m_target->CastSpell((Unit*)NULL , m_amount , true);
+ m_amplitude = irand (0 , 60 ) + 30;
+ m_amplitude *= IN_MILISECONDS;
+ break;
+ }
+ break;
+ }
// Here tick dummy auras
case SPELL_AURA_PERIODIC_DUMMY:
{
PeriodicDummyTick();
break;
}
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
+ {
+ TriggerSpell();
+ break;
+ }
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
+ {
+ TriggerSpellWithValue();
+ break;
+ }
default:
break;
}
}
-void Aura::PeriodicDummyTick()
+void AuraEffect::PeriodicDummyTick()
{
+ Unit *caster = GetCaster();
SpellEntry const* spell = GetSpellProto();
- switch (spell->Id)
- {
- // Drink
- case 430:
- case 431:
- case 432:
- case 1133:
- case 1135:
- case 1137:
- case 10250:
- case 22734:
- case 27089:
- case 34291:
- case 43706:
- case 46755:
+ switch (spell->SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ switch (spell->Id)
{
- if (m_target->GetTypeId() != TYPEID_PLAYER)
- return;
- // Search SPELL_AURA_MOD_POWER_REGEN aura for this spell and add bonus
- Unit::AuraList const& aura = m_target->GetAurasByType(SPELL_AURA_MOD_POWER_REGEN);
- for(Unit::AuraList::const_iterator i = aura.begin(); i != aura.end(); ++i)
+ // Drink
+ case 430:
+ case 431:
+ case 432:
+ case 1133:
+ case 1135:
+ case 1137:
+ case 10250:
+ case 22734:
+ case 27089:
+ case 34291:
+ case 43706:
+ case 46755:
+ case 49472: // Drink Coffee
+ case 61830:
{
- if ((*i)->GetId() == GetId())
+ if (m_target->GetTypeId() != TYPEID_PLAYER)
+ return;
+ // Search SPELL_AURA_MOD_POWER_REGEN aura for this spell and add bonus
+ Unit::AuraEffectList const& aura = m_target->GetAurasByType(SPELL_AURA_MOD_POWER_REGEN);
+ for(Unit::AuraEffectList::const_iterator i = aura.begin(); i != aura.end(); ++i)
{
- // Get tick number
- int32 tick = (m_maxduration - m_duration) / m_modifier.periodictime;
- // Default case (not on arenas)
- if (tick == 0)
+ if ((*i)->GetId() == GetId())
{
- (*i)->GetModifier()->m_amount = m_modifier.m_amount;
+ (*i)->SetAmount(m_amount);
((Player*)m_target)->UpdateManaRegen();
// Disable continue
m_isPeriodic = false;
- }
- return;
- //**********************************************
- // Code commended since arena patch not added
- // This feature uses only in arenas
- //**********************************************
- // Here need increase mana regen per tick (6 second rule)
- // on 0 tick - 0 (handled in 2 second)
- // on 1 tick - 166% (handled in 4 second)
- // on 2 tick - 133% (handled in 6 second)
- // Not need update after 3 tick
- /*
- if (tick > 3)
return;
- // Apply bonus for 0 - 3 tick
- switch (tick)
- {
- case 0: // 0%
- (*i)->GetModifier()->m_amount = m_modifier.m_amount = 0;
- break;
- case 1: // 166%
- (*i)->GetModifier()->m_amount = m_modifier.m_amount * 5 / 3;
- break;
- case 2: // 133%
- (*i)->GetModifier()->m_amount = m_modifier.m_amount * 4 / 3;
- break;
- default: // 100% - normal regen
- (*i)->GetModifier()->m_amount = m_modifier.m_amount;
- break;
}
- ((Player*)m_target)->UpdateManaRegen();
- return;*/
}
+ return;
+ }
+ // Forsaken Skills
+ case 7054:
+ {
+ // Possibly need cast one of them (but
+ // 7038 Forsaken Skill: Swords
+ // 7039 Forsaken Skill: Axes
+ // 7040 Forsaken Skill: Daggers
+ // 7041 Forsaken Skill: Maces
+ // 7042 Forsaken Skill: Staves
+ // 7043 Forsaken Skill: Bows
+ // 7044 Forsaken Skill: Guns
+ // 7045 Forsaken Skill: 2H Axes
+ // 7046 Forsaken Skill: 2H Maces
+ // 7047 Forsaken Skill: 2H Swords
+ // 7048 Forsaken Skill: Defense
+ // 7049 Forsaken Skill: Fire
+ // 7050 Forsaken Skill: Frost
+ // 7051 Forsaken Skill: Holy
+ // 7053 Forsaken Skill: Shadow
+ return;
}
- return;
- }
// // Panda
// case 19230: break;
-// // Master of Subtlety
-// case 31666: break;
// // Gossip NPC Periodic - Talk
// case 33208: break;
// // Gossip NPC Periodic - Despawn
// case 33209: break;
-// // Force of Nature
-// case 33831: break;
- // Aspect of the Viper
- case 34074:
- {
- if (m_target->GetTypeId() != TYPEID_PLAYER)
- return;
- // Should be manauser
- if (m_target->getPowerType()!=POWER_MANA)
- return;
- Unit *caster = GetCaster();
- if (!caster)
- return;
- // Regen amount is max (100% from spell) on 21% or less mana and min on 92.5% or greater mana (20% from spell)
- int mana = m_target->GetPower(POWER_MANA);
- int max_mana = m_target->GetMaxPower(POWER_MANA);
- int32 base_regen = caster->CalculateSpellDamage(m_spellProto, m_effIndex, m_currentBasePoints, m_target);
- float regen_pct = 1.20f - 1.1f * mana / max_mana;
- if (regen_pct > 1.0f) regen_pct = 1.0f;
- else if (regen_pct < 0.2f) regen_pct = 0.2f;
- m_modifier.m_amount = int32 (base_regen * regen_pct);
- ((Player*)m_target)->UpdateManaRegen();
- return;
- }
// // Steal Weapon
// case 36207: break;
// // Simon Game START timer, (DND)
// case 39993: break;
-// // Harpooner's Mark
-// case 40084: break;
// // Knockdown Fel Cannon: break; The Aggro Burst
// case 40119: break;
// // Old Mount Spell
@@ -6010,6 +6461,8 @@ void Aura::PeriodicDummyTick()
// case 40846: break;
// // Copy Weapon
// case 41054: break;
+// // Dementia
+// case 41404: break;
// // Ethereal Ring Visual, Lightning Aura
// case 41477: break;
// // Ethereal Ring Visual, Lightning Aura (Fork)
@@ -6058,6 +6511,8 @@ void Aura::PeriodicDummyTick()
// case 43310: break;
// // Headless Horseman - Maniacal Laugh, Maniacal, Delayed 17
// case 43884: break;
+// // Wretched!
+// case 43963: break;
// // Headless Horseman - Maniacal Laugh, Maniacal, other, Delayed 17
// case 44000: break;
// // Energy Feedback
@@ -6124,25 +6579,202 @@ void Aura::PeriodicDummyTick()
// case 47407: break;
// // Mole Machine Port Schedule
// case 47489: break;
+// case 47941: break; // Crystal Spike
+// case 48200: break; // Healer Aura
+// case 48630: break; // Summon Gauntlet Mobs Periodic
+// case 49313: break; // Proximity Mine Area Aura
// // Mole Machine Portal Schedule
// case 49466: break;
-// // Drink Coffee
-// case 49472: break;
+// case 49555: break; // Corpse Explode
+// case 49592: break; // Temporal Rift
+// case 49957: break; // Cutting Laser
+// case 50085: break; // Slow Fall
// // Listening to Music
// case 50493: break;
// // Love Rocket Barrage
// case 50530: break;
+ // Tenacity
+ case 58549:
+ case 59911:
+ GetParentAura()->RefreshAura();
+ break;
+// Exist more after, need add later
+ default:
+ break;
+ }
+ break;
+ case SPELLFAMILY_MAGE:
+ {
+ // Mirror Image
+// if (spell->Id == 55342)
+// return;
+ break;
+ }
+ case SPELLFAMILY_WARRIOR:
+ {
+ // Armored to the Teeth
+ if (spell->SpellIconID == 3516)
+ {
+ // Increases your attack power by $s1 for every $s2 armor value you have.
+ // Calculate AP bonus (from 1 efect of this spell)
+ int32 apBonus = m_amount * m_target->GetArmor() / m_target->CalculateSpellDamage(spell, 1, spell->EffectBasePoints[1], m_target);
+ m_target->CastCustomSpell(m_target, 61217, &apBonus, &apBonus, 0, true, 0, this);
+ return;
+ }
+ break;
+ }
+ case SPELLFAMILY_DRUID:
+ {
+ switch (spell->Id)
+ {
+ // Frenzied Regeneration
+ case 22842:
+ {
+ // Converts up to 10 rage per second into health for $d. Each point of rage is converted into ${$m2/10}.1% of max health.
+ // Should be manauser
+ if (m_target->getPowerType()!=POWER_RAGE)
+ return;
+ uint32 rage = m_target->GetPower(POWER_RAGE);
+ // Nothing todo
+ if (rage == 0)
+ return;
+ int32 mod = (rage < 100) ? rage : 100;
+ int32 points = m_target->CalculateSpellDamage(spell, 1, spell->EffectBasePoints[1], m_target);
+ int32 regen = m_target->GetMaxHealth() * (mod * points / 10) / 1000;
+ m_target->CastCustomSpell(m_target, 22845, &regen, 0, 0, true, 0, this);
+ m_target->SetPower(POWER_RAGE, rage-mod);
+ return;
+ }
+ // Force of Nature
+ case 33831:
+ return;
+ default:
+ break;
+ }
+ break;
+ }
+ case SPELLFAMILY_ROGUE:
+ {
+ switch (spell->Id)
+ {
+ // Killing Spree
+// case 51690: break;
+ // Overkill
+ case 58428:
+ if (!m_target->HasAuraType(SPELL_AURA_MOD_STEALTH))
+ m_target->RemoveAurasDueToSpell(58427);
+ break;
+ // Master of Subtlety
+ case 31666:
+ if (!m_target->HasAuraType(SPELL_AURA_MOD_STEALTH))
+ m_target->RemoveAurasDueToSpell(31665);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case SPELLFAMILY_HUNTER:
+ {
+ // Explosive Shot
+ if (spell->SpellFamilyFlags[1] & 0x80000000)
+ {
+ if(caster)
+ caster->CastCustomSpell(53352, SPELLVALUE_BASE_POINT0, m_amount, m_target, true, NULL, this);
+ return;
+ }
+ switch (spell->Id)
+ {
+ // Harpooner's Mark
+ // case 40084:
+ // return;
+ // Feeding Frenzy Rank 1
+ case 53511:
+ if ( m_target->GetHealth() * 100 < m_target->GetMaxHealth() * 35 )
+ m_target->CastSpell(m_target, 60096, true, 0, this);
+ return;
+ // Feeding Frenzy Rank 2
+ case 53512:
+ if ( m_target->GetHealth() * 100 < m_target->GetMaxHealth() * 35 )
+ m_target->CastSpell(m_target, 60097, true, 0, this);
+ return;
+ default:
+ break;
+ }
+ break;
+ }
+ case SPELLFAMILY_SHAMAN:
+ {
+ // Astral Shift
+ if (spell->Id == 52179)
+ {
+ // Periodic need for remove visual on stun/fear/silence lost
+ if (!(m_target->GetUInt32Value(UNIT_FIELD_FLAGS)&(UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED)))
+ m_target->RemoveAurasDueToSpell(52179);
+ return;
+ }
+ break;
+ }
+ case SPELLFAMILY_DEATHKNIGHT:
+ {
+ // Death and Decay
+ if (spell->SpellFamilyFlags[0] & 0x20)
+ {
+ if (caster)
+ caster->CastCustomSpell(m_target, 52212, &m_amount, NULL, NULL, true, 0, this);
+ return;
+ }
+ // Raise Dead
+// if (spell->SpellFamilyFlags & 0x0000000000001000LL)
+// return;
+ // Chains of Ice
+ if (spell->SpellFamilyFlags[1] & 0x00004000)
+ {
+ // Get 0 effect aura
+ AuraEffect *slow = GetParentAura()->GetPartAura(0);
+ if (slow)
+ {
+ slow->ApplyModifier(false, true);
+ slow->SetAmount(slow->GetAmount() + GetAmount());
+ if (slow->GetAmount() > 0) slow->SetAmount(0);
+ slow->ApplyModifier(true, true);
+ }
+ return;
+ }
+ // Summon Gargoyle
+// if (spell->SpellFamilyFlags & 0x0000008000000000LL)
+// return;
+ // Death Rune Mastery
+// if (spell->SpellFamilyFlags & 0x0000000000004000LL)
+// return;
+ // Bladed Armor
+ if (spell->SpellIconID == 2653)
+ {
+ // Increases your attack power by $s1 for every $s2 armor value you have.
+ // Calculate AP bonus (from 1 efect of this spell)
+ int32 apBonus = m_amount * m_target->GetArmor() / m_target->CalculateSpellDamage(spell, 1, spell->EffectBasePoints[1], m_target);
+ m_target->CastCustomSpell(m_target, 61217, &apBonus, &apBonus, 0, true, 0, this);
+ return;
+ }
+ // Reaping
+// if (spell->SpellIconID == 22)
+// return;
+ // Blood of the North
+// if (spell->SpellIconID == 30412)
+// return;
+ break;
+ }
default:
break;
}
}
-void Aura::HandlePreventFleeing(bool apply, bool Real)
+void AuraEffect::HandlePreventFleeing(bool apply, bool Real, bool /*changeAmount*/)
{
if(!Real)
return;
- Unit::AuraList const& fearAuras = m_target->GetAurasByType(SPELL_AURA_MOD_FEAR);
+ Unit::AuraEffectList const& fearAuras = m_target->GetAurasByType(SPELL_AURA_MOD_FEAR);
if( !fearAuras.empty() )
{
m_target->SetControlled(!apply, UNIT_STAT_FLEEING);
@@ -6153,9 +6785,9 @@ void Aura::HandlePreventFleeing(bool apply, bool Real)
}
}
-void Aura::HandleManaShield(bool apply, bool Real)
+void AuraEffect::HandleManaShield(bool apply, bool Real, bool changeAmount)
{
- if(!Real)
+ if(!Real && !changeAmount)
return;
// prevent double apply bonuses
@@ -6167,7 +6799,7 @@ void Aura::HandleManaShield(bool apply, bool Real)
switch(m_spellProto->SpellFamilyName)
{
case SPELLFAMILY_MAGE:
- if(m_spellProto->SpellFamilyFlags & 0x8000)
+ if(m_spellProto->SpellFamilyFlags[0] & 0x8000)
{
// Mana Shield
// +50% from +spd bonus
@@ -6181,12 +6813,12 @@ void Aura::HandleManaShield(bool apply, bool Real)
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
- m_modifier.m_amount += (int32)DoneActualBenefit;
+ m_amount += (int32)DoneActualBenefit;
}
}
}
-void Aura::HandleArenaPreparation(bool apply, bool Real)
+void AuraEffect::HandleArenaPreparation(bool apply, bool Real, bool /*changeAmount*/)
{
if(!Real)
return;
@@ -6197,21 +6829,229 @@ void Aura::HandleArenaPreparation(bool apply, bool Real)
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION);
}
-void Aura::UnregisterSingleCastAura()
+/**
+ * Such auras are applied from a caster(=player) to a vehicle.
+ * This has been verified using spell #49256
+ */
+void AuraEffect::HandleAuraControlVehicle(bool apply, bool Real, bool /*changeAmount*/)
{
- if (IsSingleTarget())
+ if(!Real)
+ return;
+
+ if(m_target->GetTypeId() != TYPEID_UNIT || !((Creature*)m_target)->isVehicle())
+ return;
+
+ Unit *caster = GetSource();
+ if(!caster || caster == m_target)
+ return;
+
+ Vehicle *vehicle = dynamic_cast<Vehicle*>(m_target);
+
+ if (apply)
{
- Unit* caster = NULL;
- caster = GetCaster();
- if(caster)
+ //if(caster->GetTypeId() == TYPEID_PLAYER)
+ // if(Pet *pet = ((Player*)caster)->GetPet())
+ // pet->Remove(PET_SAVE_AS_CURRENT);
+ caster->EnterVehicle(vehicle, 0);
+ }
+ else
+ {
+ // some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them
+ caster->RemoveAurasDueToSpell(GetId());
+
+ caster->ExitVehicle();
+ }
+}
+
+void AuraEffect::HandleAuraConvertRune(bool apply, bool Real, bool /*changeAmount*/)
+{
+ if(!Real)
+ return;
+
+ if(m_target->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player *plr = (Player*)m_target;
+
+ if(plr->getClass() != CLASS_DEATH_KNIGHT)
+ return;
+
+ // how to determine what rune need to be converted?
+ for(uint32 i = 0; i < MAX_RUNES; ++i)
+ {
+ if(apply)
{
- caster->GetSingleCastAuras().remove(this);
+ if(!plr->GetRuneCooldown(i))
+ {
+ plr->ConvertRune(i, GetSpellProto()->EffectMiscValueB[m_effIndex]);
+ break;
+ }
}
else
{
- sLog.outError("Couldn't find the caster of the single target aura, may crash later!");
- assert(false);
+ if(plr->GetCurrentRune(i) == GetSpellProto()->EffectMiscValueB[m_effIndex])
+ {
+ plr->ConvertRune(i, plr->GetBaseRune(i));
+ break;
+ }
}
- m_isSingleTargetAura = false;
}
}
+
+// Control Auras
+
+void AuraEffect::HandleAuraModStun(bool apply, bool Real, bool /*changeAmount*/)
+{
+ if(!Real)
+ return;
+
+ m_target->SetControlled(apply, UNIT_STAT_STUNNED);
+}
+
+void AuraEffect::HandleAuraModRoot(bool apply, bool Real, bool /*changeAmount*/)
+{
+ if(!Real)
+ return;
+
+ m_target->SetControlled(apply, UNIT_STAT_ROOT);
+}
+
+// Charm Auras
+
+void AuraEffect::HandleModPossess(bool apply, bool Real, bool /*changeAmount*/)
+{
+ if(!Real)
+ return;
+
+ Unit* caster = GetCaster();
+ if(caster && caster->GetTypeId() == TYPEID_UNIT)
+ {
+ HandleModCharm(apply, Real, false);
+ return;
+ }
+
+ if(apply)
+ {
+ if(m_target->getLevel() > m_amount)
+ return;
+
+ m_target->SetCharmedOrPossessedBy(caster, true);
+ }
+ else
+ m_target->RemoveCharmedOrPossessedBy(caster);
+}
+
+void AuraEffect::HandleModPossessPet(bool apply, bool Real, bool /*changeAmount*/)
+{
+ if(!Real)
+ return;
+
+ Unit* caster = GetCaster();
+ if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if(apply)
+ {
+ if(caster->GetGuardianPet() != m_target)
+ return;
+
+ m_target->SetCharmedOrPossessedBy(caster, true);
+ }
+ else
+ {
+ m_target->RemoveCharmedOrPossessedBy(caster);
+
+ // Reinitialize the pet bar and make the pet come back to the owner
+ ((Player*)caster)->PetSpellInitialize();
+ if(!m_target->getVictim())
+ {
+ m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ m_target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
+ }
+ }
+}
+
+void AuraEffect::HandleModCharm(bool apply, bool Real, bool /*changeAmount*/)
+{
+ if(!Real)
+ return;
+
+ Unit* caster = GetCaster();
+
+ if(apply)
+ {
+ if(int32(m_target->getLevel()) > m_amount)
+ return;
+
+ m_target->SetCharmedOrPossessedBy(caster, false);
+ }
+ else
+ m_target->RemoveCharmedOrPossessedBy(caster);
+}
+
+void AuraEffect::HandlePhase(bool apply, bool Real, bool /*changeAmount*/)
+{
+ if(!Real)
+ return;
+
+ // always non stackable
+ if(apply)
+ {
+ m_target->RemoveAurasByType(SPELL_AURA_PHASE, NULL, GetParentAura());
+ }
+
+ // no-phase is also phase state so same code for apply and remove
+
+ // phase auras normally not expected at BG but anyway better check
+ if(m_target->GetTypeId()==TYPEID_PLAYER)
+ {
+ // drop flag at invisible in bg
+ if(((Player*)m_target)->InBattleGround())
+ if(BattleGround *bg = ((Player*)m_target)->GetBattleGround())
+ bg->EventPlayerDroppedFlag((Player*)m_target);
+
+ // GM-mode have mask 0xFFFFFFFF
+ if(!((Player*)m_target)->isGameMaster())
+ m_target->SetPhaseMask(apply ? GetMiscValue() : PHASEMASK_NORMAL,false);
+
+ ((Player*)m_target)->GetSession()->SendSetPhaseShift(apply ? GetMiscValue() : PHASEMASK_NORMAL);
+
+ if(GetEffIndex()==0)
+ {
+ SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
+ if(saBounds.first != saBounds.second)
+ {
+ uint32 zone, area;
+ m_target->GetZoneAndAreaId(zone,area);
+
+ for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
+ {
+ // some auras remove at aura remove
+ if(!itr->second->IsFitToRequirements((Player*)m_target,zone,area))
+ m_target->RemoveAurasDueToSpell(itr->second->spellId);
+ // some auras applied at aura apply
+ else if(itr->second->autocast)
+ {
+ if( !m_target->HasAura(itr->second->spellId) )
+ m_target->CastSpell(m_target,itr->second->spellId,true);
+ }
+ }
+ }
+ }
+ }
+ else
+ m_target->SetPhaseMask(apply ? GetMiscValue() : PHASEMASK_NORMAL,false);
+
+ // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases)
+ if(m_target->GetVisibility()!=VISIBILITY_OFF)
+ m_target->SetVisibility(m_target->GetVisibility());
+}
+
+void AuraEffect::HandleAuraSafeFall( bool Apply, bool Real , bool /*changeAmount*/)
+{
+ // implemented in WorldSession::HandleMovementOpcodes
+
+ // only special case
+ if(Apply && Real && GetId()==32474 && m_target->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_target)->ActivateTaxiPathTo(506,GetId());
+}
diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h
index 245669456e9..20d27e915c1 100644
--- a/src/game/SpellAuras.h
+++ b/src/game/SpellAuras.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,23 +22,6 @@
#include "SpellAuraDefines.h"
-struct DamageManaShield
-{
- uint32 m_spellId;
- uint32 m_modType;
- int32 m_schoolType;
- uint32 m_totalAbsorb;
- uint32 m_currAbsorb;
-};
-
-struct Modifier
-{
- AuraType m_auraname;
- int32 m_amount;
- int32 m_miscvalue;
- uint32 periodictime;
-};
-
class Unit;
struct SpellEntry;
struct SpellModifier;
@@ -46,8 +29,9 @@ struct ProcTriggerSpell;
// forward decl
class Aura;
+class AuraEffect;
-typedef void(Aura::*pAuraHandler)(bool Apply, bool Real);
+typedef void(AuraEffect::*pAuraHandler)(bool Apply, bool Real, bool changeAmount);
// Real == true at aura add/remove
// Real == false at aura mod unapply/reapply; when adding/removing dependent aura/item/stat mods
//
@@ -60,326 +44,377 @@ typedef void(Aura::*pAuraHandler)(bool Apply, bool Real);
// Other case choice: each code line moved under if(Real) check is Trinity speedup,
// each setting object update field code line moved under if(Real) check is significant Trinity speedup, and less server->client data sends
// each packet sending code moved under if(Real) check is _large_ Trinity speedup, and lot less server->client data sends
+//
+// changeAmount == true at changing existing aura amount - called wit real == false
+// if aura has amount dependant effect handler has to allow proceeding it
+// example: change speed aura, modifier aura
class TRINITY_DLL_SPEC Aura
{
- friend Aura* CreateAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem);
-
+ friend void Player::SendAurasForTarget(Unit *target);
public:
- //aura handlers
- void HandleNULL(bool, bool)
- {
- // NOT IMPLEMENTED
- }
- void HandleUnused(bool, bool)
- {
- // NOT USED BY ANY SPELL OR USELESS
- }
- void HandleNoImmediateEffect(bool, bool)
- {
- // aura not have immediate effect at add/remove and handled by ID in other code place
- }
- void HandleBindSight(bool Apply, bool Real);
- void HandleModPossess(bool Apply, bool Real);
- void HandlePeriodicDamage(bool Apply, bool Real);
- void HandleAuraDummy(bool Apply, bool Real);
- void HandleAuraPeriodicDummy(bool apply, bool Real);
- void HandleModConfuse(bool Apply, bool Real);
- void HandleModCharm(bool Apply, bool Real);
- void HandleModFear(bool Apply, bool Real);
- void HandlePeriodicHeal(bool Apply, bool Real);
- void HandleModAttackSpeed(bool Apply, bool Real);
- void HandleModMeleeRangedSpeedPct(bool apply, bool Real);
- void HandleModCombatSpeedPct(bool apply, bool Real);
- void HandleModThreat(bool Apply, bool Real);
- void HandleModTaunt(bool Apply, bool Real);
- void HandleFeignDeath(bool Apply, bool Real);
- void HandleAuraModDisarm(bool Apply, bool Real);
- void HandleAuraModStalked(bool Apply, bool Real);
- void HandleAuraWaterWalk(bool Apply, bool Real);
- void HandleAuraFeatherFall(bool Apply, bool Real);
- void HandleAuraHover(bool Apply, bool Real);
- void HandleAddModifier(bool Apply, bool Real);
- void HandleAuraModStun(bool Apply, bool Real);
- void HandleModDamageDone(bool Apply, bool Real);
- void HandleAuraUntrackable(bool Apply, bool Real);
- void HandleAuraEmpathy(bool Apply, bool Real);
- void HandleModOffhandDamagePercent(bool apply, bool Real);
- void HandleAuraModRangedAttackPower(bool Apply, bool Real);
- void HandleAuraModIncreaseEnergyPercent(bool Apply, bool Real);
- void HandleAuraModIncreaseHealthPercent(bool Apply, bool Real);
- void HandleAuraModRegenInterrupt(bool Apply, bool Real);
- void HandleHaste(bool Apply, bool Real);
- void HandlePeriodicTriggerSpell(bool Apply, bool Real);
- void HandlePeriodicEnergize(bool Apply, bool Real);
- void HandleAuraModResistanceExclusive(bool Apply, bool Real);
- void HandleModStealth(bool Apply, bool Real);
- void HandleInvisibility(bool Apply, bool Real);
- void HandleInvisibilityDetect(bool Apply, bool Real);
- void HandleAuraModTotalHealthPercentRegen(bool Apply, bool Real);
- void HandleAuraModTotalManaPercentRegen(bool Apply, bool Real);
- void HandleAuraModResistance(bool Apply, bool Real);
- void HandleAuraModRoot(bool Apply, bool Real);
- void HandleAuraModSilence(bool Apply, bool Real);
- void HandleAuraModStat(bool Apply, bool Real);
- void HandleAuraModIncreaseSpeed(bool Apply, bool Real);
- void HandleAuraModIncreaseMountedSpeed(bool Apply, bool Real);
- void HandleAuraModIncreaseFlightSpeed(bool Apply, bool Real);
- void HandleAuraModDecreaseSpeed(bool Apply, bool Real);
- void HandleAuraModUseNormalSpeed(bool Apply, bool Real);
- void HandleAuraModIncreaseHealth(bool Apply, bool Real);
- void HandleAuraModIncreaseEnergy(bool Apply, bool Real);
- void HandleAuraModShapeshift(bool Apply, bool Real);
- void HandleAuraModEffectImmunity(bool Apply, bool Real);
- void HandleAuraModStateImmunity(bool Apply, bool Real);
- void HandleAuraModSchoolImmunity(bool Apply, bool Real);
- void HandleAuraModDmgImmunity(bool Apply, bool Real);
- void HandleAuraModDispelImmunity(bool Apply, bool Real);
- void HandleAuraProcTriggerSpell(bool Apply, bool Real);
- void HandleAuraTrackCreatures(bool Apply, bool Real);
- void HandleAuraTrackResources(bool Apply, bool Real);
- void HandleAuraModParryPercent(bool Apply, bool Real);
- void HandleAuraModDodgePercent(bool Apply, bool Real);
- void HandleAuraModBlockPercent(bool Apply, bool Real);
- void HandleAuraModCritPercent(bool Apply, bool Real);
- void HandlePeriodicLeech(bool Apply, bool Real);
- void HandleModHitChance(bool Apply, bool Real);
- void HandleModSpellHitChance(bool Apply, bool Real);
- void HandleAuraModScale(bool Apply, bool Real);
- void HandlePeriodicManaLeech(bool Apply, bool Real);
- void HandleModCastingSpeed(bool Apply, bool Real);
- void HandleAuraMounted(bool Apply, bool Real);
- void HandleWaterBreathing(bool Apply, bool Real);
- void HandleModBaseResistance(bool Apply, bool Real);
- void HandleModRegen(bool Apply, bool Real);
- void HandleModPowerRegen(bool Apply, bool Real);
- void HandleModPowerRegenPCT(bool Apply, bool Real);
- void HandleChannelDeathItem(bool Apply, bool Real);
- void HandlePeriodicDamagePCT(bool Apply, bool Real);
- void HandleAuraModAttackPower(bool Apply, bool Real);
- void HandleAuraTransform(bool Apply, bool Real);
- void HandleModSpellCritChance(bool Apply, bool Real);
- void HandleAuraModIncreaseSwimSpeed(bool Apply, bool Real);
- void HandleModPowerCostPCT(bool Apply, bool Real);
- void HandleModPowerCost(bool Apply, bool Real);
- void HandleFarSight(bool Apply, bool Real);
- void HandleModPossessPet(bool Apply, bool Real);
- void HandleModMechanicImmunity(bool Apply, bool Real);
- void HandleAuraModSkill(bool Apply, bool Real);
- void HandleModDamagePercentDone(bool Apply, bool Real);
- void HandleModPercentStat(bool Apply, bool Real);
- void HandleModResistancePercent(bool Apply, bool Real);
- void HandleAuraModBaseResistancePCT(bool Apply, bool Real);
- void HandleModShieldBlockPCT(bool Apply, bool Real);
- void HandleAuraTrackStealthed(bool Apply, bool Real);
- void HandleModShieldBlock(bool Apply, bool Real);
- void HandleForceReaction(bool Apply, bool Real);
- void HandleAuraModRangedHaste(bool Apply, bool Real);
- void HandleRangedAmmoHaste(bool Apply, bool Real);
- void HandleModHealingDone(bool Apply, bool Real);
- void HandleModTotalPercentStat(bool Apply, bool Real);
- void HandleAuraModTotalThreat(bool Apply, bool Real);
- void HandleModUnattackable(bool Apply, bool Real);
- void HandleAuraModPacify(bool Apply, bool Real);
- void HandleAuraGhost(bool Apply, bool Real);
- void HandleAuraAllowFlight(bool Apply, bool Real);
- void HandleModRating(bool apply, bool Real);
- void HandleModTargetResistance(bool apply, bool Real);
- void HandleAuraModAttackPowerPercent(bool apply, bool Real);
- void HandleAuraModRangedAttackPowerPercent(bool apply, bool Real);
- void HandleAuraModRangedAttackPowerOfStatPercent(bool apply, bool Real);
- void HandleSpiritOfRedemption(bool apply, bool Real);
- void HandleModManaRegen(bool apply, bool Real);
- void HandleComprehendLanguage(bool apply, bool Real);
- void HandleShieldBlockValue(bool apply, bool Real);
- void HandleModSpellCritChanceShool(bool apply, bool Real);
- void HandleAuraRetainComboPoints(bool apply, bool Real);
- void HandleModSpellDamagePercentFromStat(bool apply, bool Real);
- void HandleModSpellHealingPercentFromStat(bool apply, bool Real);
- void HandleAuraModDispelResist(bool apply, bool Real);
- void HandleModSpellDamagePercentFromAttackPower(bool apply, bool Real);
- void HandleModSpellHealingPercentFromAttackPower(bool apply, bool Real);
- void HandleAuraModPacifyAndSilence(bool Apply, bool Real);
- void HandleAuraModIncreaseMaxHealth(bool apply, bool Real);
- void HandleAuraModExpertise(bool apply, bool Real);
- void HandleForceMoveForward(bool apply, bool Real);
- void HandleAuraModResistenceOfStatPercent(bool apply, bool Real);
- void HandleAuraPowerBurn(bool apply, bool Real);
- void HandleSchoolAbsorb(bool apply, bool Real);
- void HandlePreventFleeing(bool apply, bool Real);
- void HandleManaShield(bool apply, bool Real);
- void HandleArenaPreparation(bool apply, bool Real);
-
virtual ~Aura();
-
- void SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue);
- Modifier* GetModifier() {return &m_modifier;}
- int32 GetModifierValuePerStack() {return m_modifier.m_amount;}
- int32 GetModifierValue() {return m_modifier.m_amount * m_stackAmount;}
- int32 GetMiscValue() {return m_spellProto->EffectMiscValue[m_effIndex];}
- int32 GetMiscBValue() {return m_spellProto->EffectMiscValueB[m_effIndex];}
+ explicit Aura(SpellEntry const* spellproto, uint32 effMask, int32 *currentBasePoints, Unit *target, WorldObject *source = NULL, Unit *caster = NULL, Item *castItem = NULL);
SpellEntry const* GetSpellProto() const { return m_spellProto; }
uint32 GetId() const{ return m_spellProto->Id; }
uint64 GetCastItemGUID() const { return m_castItemGuid; }
- uint32 GetEffIndex() const{ return m_effIndex; }
- int32 GetBasePoints() const { return m_currentBasePoints; }
-
- int32 GetAuraMaxDuration() const { return m_maxduration; }
- void SetAuraMaxDuration(int32 duration) { m_maxduration = duration; }
- int32 GetAuraDuration() const { return m_duration; }
- void SetAuraDuration(int32 duration)
- {
- m_duration = duration;
- if (duration<0)
- m_permanent=true;
- else
- m_permanent=false;
- }
- time_t GetAuraApplyTime() { return m_applyTime; }
- void UpdateAuraDuration();
- void SendAuraDurationForCaster(Player* caster);
- void UpdateSlotCounterAndDuration();
- uint32 GetTickNumber() const { return m_tickNumber; }
uint64 const& GetCasterGUID() const { return m_caster_guid; }
Unit* GetCaster() const;
Unit* GetTarget() const { return m_target; }
- void SetTarget(Unit* target) { m_target = target; }
- void SetLoadedState(uint64 caster_guid,int32 damage,int32 maxduration,int32 duration,int32 charges)
- {
- m_caster_guid = caster_guid;
- m_modifier.m_amount = damage;
- m_maxduration = maxduration;
- m_duration = duration;
- m_procCharges = charges;
- }
+ time_t GetAuraApplyTime() const { return m_applyTime; }
+
+ int32 GetAuraMaxDuration() const { return m_maxduration; }
+ void SetAuraMaxDuration(int32 duration) { m_maxduration = duration; }
+ int32 GetAuraDuration() const { return m_duration; }
+ void SetAuraDuration(int32 duration, bool withMods = false);
+ void RefreshAura() { SetAuraDuration(m_maxduration); }
+ bool IsExpired() const { return !GetAuraDuration() && !(IsPermanent() || IsPassive()); }
+ void SendAuraUpdate();
uint8 GetAuraSlot() const { return m_auraSlot; }
void SetAuraSlot(uint8 slot) { m_auraSlot = slot; }
- void UpdateAuraCharges()
- {
- uint8 slot = GetAuraSlot();
+ uint8 GetAuraCharges() const { return m_procCharges; }
+ void SetAuraCharges(uint8 charges);
+ void DropAuraCharge();
+ void SetProcDamage(uint32 val) { m_procDamage = val; }
+ uint32 GetProcDamage() const { return m_procDamage; }
+
+ int8 GetStackAmount() const {return m_stackAmount;}
+ void SetStackAmount(uint8 num, bool applied = true);
+ bool modStackAmount(int32 num); // return true if last charge dropped
+ uint32 GetAuraStateMask(){return m_auraStateMask;}
+ void SetAuraState(uint8 num){m_auraStateMask |= 1<<(num-1);} //modifies auras' aura state (not unit!)
- // only aura in slot with charges and without stack limitation
- if (slot < MAX_AURAS && m_procCharges >= 1 && GetSpellProto()->StackAmount==0)
- SetAuraApplication(slot, m_procCharges - 1);
- }
+ void SetRemoveMode(AuraRemoveMode mode) { m_removeMode = mode; }
+ uint8 GetRemoveMode() const {return m_removeMode;}
+
+ inline uint8 GetEffectMask() const {return m_auraFlags & 7;}
+ AuraEffect * GetPartAura (uint8 effIndex) const {assert (effIndex < MAX_SPELL_EFFECTS); return m_partAuras[effIndex];}
+ bool SetPartAura(AuraEffect* aurEff, uint8 effIndex);
- bool IsPositive() { return m_positive; }
+ bool IsPositive() const { return m_positive; }
void SetNegative() { m_positive = false; }
void SetPositive() { m_positive = true; }
-
bool IsPermanent() const { return m_permanent; }
- bool IsAreaAura() const { return m_isAreaAura; }
- bool IsPeriodic() const { return m_isPeriodic; }
- bool IsTrigger() const { return m_isTrigger; }
+ void SetPermanent(bool val) { m_permanent = val; }
+
bool IsPassive() const { return m_isPassive; }
- bool IsPersistent() const { return m_isPersistent; }
bool IsDeathPersistent() const { return m_isDeathPersist; }
bool IsRemovedOnShapeLost() const { return m_isRemovedOnShapeLost; }
- bool IsInUse() const { return m_in_use;}
- void CleanupTriggeredSpells();
+ bool IsUpdated() const { return m_updated; }
+ bool IsRemoved() const { return m_isRemoved; }
+ void SetUpdated(bool val) { m_updated = val; }
- virtual void Update(uint32 diff);
- void ApplyModifier(bool apply, bool Real = false);
+ bool IsPersistent() const;
+ bool IsAreaAura() const;
+ bool IsAuraType(AuraType type) const;
+ void SetLoadedState(uint64 caster_guid,int32 maxduration,int32 duration,int32 charges, uint8 stackamount, int32 * amount);
+ bool HasEffect(uint8 effIndex) const {return bool (m_partAuras[effIndex]);}
+ inline void HandleEffects(bool apply)
+ {
+ for (uint8 i = 0; i<MAX_SPELL_EFFECTS;++i)
+ if (m_partAuras[i])
+ m_target->HandleAuraEffect(m_partAuras[i], apply);
+ }
+ void ApplyAllModifiers(bool apply, bool Real=false);
+
+ void Update(uint32 diff);
void _AddAura();
void _RemoveAura();
- void TriggerSpell();
+ // Allow Apply Aura Handler to modify and access m_AuraDRGroup
+ void setDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; }
+ DiminishingGroup getDiminishGroup() const { return m_AuraDRGroup; }
- bool IsUpdated() { return m_updated; }
- void SetUpdated(bool val) { m_updated = val; }
- void SetRemoveMode(AuraRemoveMode mode) { m_removeMode = mode; }
+ // Single cast aura helpers
+ void UnregisterSingleCastAura();
+ bool IsSingleTarget() const {return m_isSingleTargetAura;}
+ void SetIsSingleTarget(bool val) { m_isSingleTargetAura = val;}
+
+ private:
+ SpellEntry const *m_spellProto;
+ Unit * const m_target;
+ uint64 m_caster_guid;
+ uint64 m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
+ time_t m_applyTime;
- int32 m_procCharges;
- void SetAuraProcCharges(int32 charges) { m_procCharges = charges; }
+ int32 m_maxduration; // Max aura duration
+ int32 m_duration; // Current time
+ int32 m_timeCla; // Timer for power per sec calcultion
- Unit* GetTriggerTarget() const;
+ AuraRemoveMode m_removeMode:8; // Store info for know remove aura reason
+ DiminishingGroup m_AuraDRGroup:8; // Diminishing
+
+ uint8 m_auraSlot; // Aura slot on unit (for show in client)
+ uint8 m_auraFlags; // Aura info flag (for send data to client)
+ uint8 m_auraLevel; // Aura level (store caster level for correct show level dep amount)
+ uint8 m_procCharges; // Aura charges (0 for infinite)
+ uint8 m_stackAmount; // Aura stack amount
+ uint32 m_auraStateMask;
+ AuraEffect * m_partAuras[3];
+
+ uint32 m_procDamage; // used in aura proc code
+
+ bool m_isDeathPersist:1;
+ bool m_isRemovedOnShapeLost:1;
+ bool m_isPassive:1;
+ bool m_positive:1;
+ bool m_permanent:1;
+ bool m_isRemoved:1;
+ bool m_updated:1; // Prevent remove aura by stack if set
+ bool m_isSingleTargetAura:1; // true if it's a single target spell and registered at caster - can change at spell steal for example
+
+ bool IsVisible() const;
+};
+
+class TRINITY_DLL_SPEC AuraEffect
+{
+ public:
+ friend AuraEffect* CreateAuraEffect(Aura * parentAura, uint32 effIndex, int32 *currentBasePoints, Unit * caster, Item * castItem, WorldObject *source);
+ friend void Aura::SetStackAmount(uint8 stackAmount, bool applied);
+ //aura handlers
+ void HandleNULL(bool, bool, bool)
+ {
+ // NOT IMPLEMENTED
+ }
+ void HandleUnused(bool, bool, bool)
+ {
+ // NOT USED BY ANY SPELL OR USELESS
+ }
+ void HandleNoImmediateEffect(bool, bool, bool)
+ {
+ // aura not have immediate effect at add/remove and handled by ID in other code place
+ }
+ void HandleBindSight(bool Apply, bool Real, bool changeAmount);
+ void HandleModPossess(bool Apply, bool Real, bool changeAmount);
+ void HandlePeriodicDamage(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraDummy(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraPeriodicDummy(bool apply, bool Real, bool changeAmount);
+ void HandleModConfuse(bool Apply, bool Real, bool changeAmount);
+ void HandleModCharm(bool Apply, bool Real, bool changeAmount);
+ void HandleModFear(bool Apply, bool Real, bool changeAmount);
+ void HandlePeriodicHeal(bool Apply, bool Real, bool changeAmount);
+ void HandleModAttackSpeed(bool Apply, bool Real, bool changeAmount);
+ void HandleModMeleeRangedSpeedPct(bool apply, bool Real, bool changeAmount);
+ void HandleModCombatSpeedPct(bool apply, bool Real, bool changeAmount);
+ void HandleModThreat(bool Apply, bool Real, bool changeAmount);
+ void HandleModTaunt(bool Apply, bool Real, bool changeAmount);
+ void HandleFeignDeath(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModDisarm(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModStalked(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraWaterWalk(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraFeatherFall(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraHover(bool Apply, bool Real, bool changeAmount);
+ void HandleAddModifier(bool Apply, bool Real, bool changeAmount);
+ void HandleAddTargetTrigger(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModStun(bool Apply, bool Real, bool changeAmount);
+ void HandleModDamageDone(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraUntrackable(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraEmpathy(bool Apply, bool Real, bool changeAmount);
+ void HandleModOffhandDamagePercent(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModRangedAttackPower(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseEnergyPercent(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseHealthPercent(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModRegenInterrupt(bool Apply, bool Real, bool changeAmount);
+ void HandleHaste(bool Apply, bool Real, bool changeAmount);
+ void HandlePeriodicTriggerSpell(bool Apply, bool Real, bool changeAmount);
+ void HandlePeriodicTriggerSpellWithValue(bool apply, bool Real, bool changeAmount);
+ void HandlePeriodicEnergize(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModResistanceExclusive(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraSafeFall(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModPetTalentsPoints(bool Apply, bool Real, bool changeAmount);
+ void HandleModStealth(bool Apply, bool Real, bool changeAmount);
+ void HandleInvisibility(bool Apply, bool Real, bool changeAmount);
+ void HandleInvisibilityDetect(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModTotalHealthPercentRegen(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModTotalEnergyPercentRegen(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModResistance(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModRoot(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModSilence(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModStat(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseSpeed(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseMountedSpeed(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseFlightSpeed(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModDecreaseSpeed(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModUseNormalSpeed(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseHealth(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseEnergy(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModShapeshift(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModEffectImmunity(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModStateImmunity(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModSchoolImmunity(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModDmgImmunity(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModDispelImmunity(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraProcTriggerSpell(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraTrackCreatures(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraTrackResources(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModParryPercent(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModDodgePercent(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModBlockPercent(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModCritPercent(bool Apply, bool Real, bool changeAmount);
+ void HandlePeriodicLeech(bool Apply, bool Real, bool changeAmount);
+ void HandleModHitChance(bool Apply, bool Real, bool changeAmount);
+ void HandleModSpellHitChance(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModScale(bool Apply, bool Real, bool changeAmount);
+ void HandlePeriodicManaLeech(bool Apply, bool Real, bool changeAmount);
+ void HandlePeriodicHealthFunnel(bool apply, bool Real, bool changeAmount);
+ void HandleModCastingSpeed(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraMounted(bool Apply, bool Real, bool changeAmount);
+ void HandleWaterBreathing(bool Apply, bool Real, bool changeAmount);
+ void HandleModBaseResistance(bool Apply, bool Real, bool changeAmount);
+ void HandleModRegen(bool Apply, bool Real, bool changeAmount);
+ void HandleModPowerRegen(bool Apply, bool Real, bool changeAmount);
+ void HandleModPowerRegenPCT(bool Apply, bool Real, bool changeAmount);
+ void HandleChannelDeathItem(bool Apply, bool Real, bool changeAmount);
+ void HandlePeriodicDamagePCT(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModAttackPower(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraTransform(bool Apply, bool Real, bool changeAmount);
+ void HandleModSpellCritChance(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseSwimSpeed(bool Apply, bool Real, bool changeAmount);
+ void HandleModPowerCostPCT(bool Apply, bool Real, bool changeAmount);
+ void HandleModPowerCost(bool Apply, bool Real, bool changeAmount);
+ void HandleFarSight(bool Apply, bool Real, bool changeAmount);
+ void HandleModPossessPet(bool Apply, bool Real, bool changeAmount);
+ void HandleModMechanicImmunity(bool Apply, bool Real, bool changeAmount);
+ void HandleModStateImmunityMask(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModSkill(bool Apply, bool Real, bool changeAmount);
+ void HandleModDamagePercentDone(bool Apply, bool Real, bool changeAmount);
+ void HandleModPercentStat(bool Apply, bool Real, bool changeAmount);
+ void HandleModResistancePercent(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModBaseResistancePCT(bool Apply, bool Real, bool changeAmount);
+ void HandleModShieldBlockPCT(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraTrackStealthed(bool Apply, bool Real, bool changeAmount);
+ void HandleModShieldBlock(bool Apply, bool Real, bool changeAmount);
+ void HandleForceReaction(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModRangedHaste(bool Apply, bool Real, bool changeAmount);
+ void HandleRangedAmmoHaste(bool Apply, bool Real, bool changeAmount);
+ void HandleModHealingDone(bool Apply, bool Real, bool changeAmount);
+ void HandleModTotalPercentStat(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModTotalThreat(bool Apply, bool Real, bool changeAmount);
+ void HandleModUnattackable(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModPacify(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraGhost(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraAllowFlight(bool Apply, bool Real, bool changeAmount);
+ void HandleModRating(bool apply, bool Real, bool changeAmount);
+ void HandleModRatingFromStat(bool apply, bool Real, bool changeAmount);
+ void HandleModTargetResistance(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModAttackPowerPercent(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModRangedAttackPowerPercent(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModRangedAttackPowerOfStatPercent(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModAttackPowerOfStatPercent(bool apply, bool Real, bool changeAmount);
+ void HandleSpiritOfRedemption(bool apply, bool Real, bool changeAmount);
+ void HandleModManaRegen(bool apply, bool Real, bool changeAmount);
+ void HandleComprehendLanguage(bool apply, bool Real, bool changeAmount);
+ void HandleShieldBlockValue(bool apply, bool Real, bool changeAmount);
+ void HandleModSpellCritChanceShool(bool apply, bool Real, bool changeAmount);
+ void HandleAuraRetainComboPoints(bool apply, bool Real, bool changeAmount);
+ void HandleModSpellDamagePercentFromStat(bool apply, bool Real, bool changeAmount);
+ void HandleModSpellHealingPercentFromStat(bool apply, bool Real, bool changeAmount);
+ void HandleAuraControlVehicle(bool apply, bool Real, bool changeAmount);
+ void HandleModSpellDamagePercentFromAttackPower(bool apply, bool Real, bool changeAmount);
+ void HandleModSpellHealingPercentFromAttackPower(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModPacifyAndSilence(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraModIncreaseMaxHealth(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModExpertise(bool apply, bool Real, bool changeAmount);
+ void HandleForceMoveForward(bool apply, bool Real, bool changeAmount);
+ void HandleAuraModResistenceOfStatPercent(bool apply, bool Real, bool changeAmount);
+ void HandleAuraPowerBurn(bool apply, bool Real, bool changeAmount);
+ void HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount);
+ void HandlePreventFleeing(bool apply, bool Real, bool changeAmount);
+ void HandleManaShield(bool apply, bool Real, bool changeAmount);
+ void HandleArenaPreparation(bool apply, bool Real, bool changeAmount);
+ void HandleAuraConvertRune(bool apply, bool Real, bool changeAmount);
+ void HandleAuraIncreaseBaseHealthPercent(bool Apply, bool Real, bool changeAmount);
+ void HandleNoReagentUseAura(bool Apply, bool Real, bool changeAmount);
+ void HandlePhase(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraAllowOnlyAbility(bool apply, bool Real, bool changeAmount);
// add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras
void HandleShapeshiftBoosts(bool apply);
- // Allow Apply Aura Handler to modify and access m_AuraDRGroup
- void setDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; }
- DiminishingGroup getDiminishGroup() const { return m_AuraDRGroup; }
+ Unit * GetCaster() const { return m_parentAura->GetCaster(); }
+ uint64 GetCasterGUID() const{ return m_parentAura->GetCasterGUID(); }
+ Unit* GetSource() const; // { return m_parentAura->GetSource(); }
+ Aura * GetParentAura() const { return m_parentAura; }
+
+ SpellEntry const* GetSpellProto() const { return m_spellProto; }
+ uint32 GetId() const { return m_spellProto->Id; }
+ uint32 GetEffIndex() const { return m_effIndex; }
+ int32 GetBasePoints() const { return m_currentBasePoints; }
+ int32 GetAuraAmplitude(){return m_amplitude;}
+ virtual void Update(uint32 diff);
+
+ uint32 GetTickNumber() const { return m_tickNumber; }
+ bool IsAreaAura() const { return m_isAreaAura; }
+ bool IsPeriodic() const { return m_isPeriodic; }
+ bool IsPersistent() const { return m_isPersistent; }
+ bool isAffectedOnSpell(SpellEntry const *spell) const;
+
+ void ApplyModifier(bool apply, bool Real = false, bool changeAmount=false);
+ void RecalculateAmount(bool applied = true);
+ void HandleAuraEffect(bool apply);
+ void ApplyAllModifiers(bool apply, bool Real);
+ Unit* GetTriggerTarget() const;
+ void TriggerSpell();
+ void TriggerSpellWithValue();
void PeriodicTick();
void PeriodicDummyTick();
- int32 GetStackAmount() {return m_stackAmount;}
- void SetStackAmount(int32 amount) {m_stackAmount=amount;}
+ int32 GetMiscBValue() const {return m_spellProto->EffectMiscValueB[m_effIndex];}
+ int32 GetMiscValue() const {return m_spellProto->EffectMiscValue[m_effIndex];}
+ uint32 GetAuraName() const {return m_auraName;}
+ int32 GetAmount() const {return m_amount;}
+ void SetAmount(int32 amount) { m_amount = amount; }
+ void CleanupTriggeredSpells();
- // Single cast aura helpers
- void UnregisterSingleCastAura();
- bool IsSingleTarget() const {return m_isSingleTargetAura;}
- void SetIsSingleTarget(bool val) { m_isSingleTargetAura = val;}
protected:
- Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL);
+ explicit AuraEffect(Aura * parentAura, uint8 effIndex, int32 *currentBasePoints , Unit *caster, Item *castItem, WorldObject *source);
+ Aura * const m_parentAura;
+ Unit * const m_target;
+ uint64 m_sourceGUID; // Spell::m_caster/trap? for normal aura, totem/paladin for areaaura, dynobj for persistent aura
- Modifier m_modifier;
- SpellModifier *m_spellmod;
- uint32 m_effIndex;
SpellEntry const *m_spellProto;
- int32 m_currentBasePoints; // cache SpellEntry::EffectBasePoints and use for set custom base points
- uint64 m_caster_guid;
- Unit* m_target;
- int32 m_maxduration;
- int32 m_duration;
uint32 m_tickNumber;
- int32 m_timeCla;
- uint64 m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
- time_t m_applyTime;
- AuraRemoveMode m_removeMode;
+ uint8 m_effIndex;
+ AuraType m_auraName;
+ int32 m_currentBasePoints;
+ int32 m_amount;
+
+ SpellModifier *m_spellmod;
- uint8 m_auraSlot;
+ int32 m_periodicTimer; // Timer for periodic auras
+ int32 m_amplitude;
- bool m_positive:1;
- bool m_permanent:1;
bool m_isPeriodic:1;
- bool m_isTrigger:1;
bool m_isAreaAura:1;
- bool m_isPassive:1;
bool m_isPersistent:1;
- bool m_isDeathPersist:1;
- bool m_isRemovedOnShapeLost:1;
- bool m_updated:1;
- bool m_in_use:1; // true while in Aura::ApplyModifier call
- bool m_isSingleTargetAura:1; // true if it's a single target spell and registered at caster - can change at spell steal for example
-
- int32 m_periodicTimer;
- uint32 m_PeriodicEventId;
- DiminishingGroup m_AuraDRGroup;
-
- int32 m_stackAmount;
- private:
- void SetAura(uint32 slot, bool remove) { m_target->SetUInt32Value(UNIT_FIELD_AURA + slot, remove ? 0 : GetId()); }
- void SetAuraFlag(uint32 slot, bool add);
- void SetAuraLevel(uint32 slot, uint32 level);
- void SetAuraApplication(uint32 slot, int8 count);
};
-class TRINITY_DLL_SPEC AreaAura : public Aura
+class TRINITY_DLL_SPEC AreaAuraEffect : public AuraEffect
{
public:
- AreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL);
- ~AreaAura();
+ AreaAuraEffect(Aura * parentAura, uint32 effIndex, int32 * currentBasePoints, Unit * caster=NULL, Item * castItem=NULL, Unit * source = NULL);
+ ~AreaAuraEffect();
void Update(uint32 diff);
private:
float m_radius;
+ int32 m_removeTime;
AreaAuraType m_areaAuraType;
};
-class TRINITY_DLL_SPEC PersistentAreaAura : public Aura
+class TRINITY_DLL_SPEC PersistentAreaAuraEffect : public AuraEffect
{
public:
- PersistentAreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL);
- ~PersistentAreaAura();
+ PersistentAreaAuraEffect(Aura * parentAura, uint32 eff, int32 *currentBasePoints, Unit *caster = NULL, Item* castItem = NULL, DynamicObject * source = NULL);
+ ~PersistentAreaAuraEffect();
void Update(uint32 diff);
};
-Aura* CreateAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL);
-#endif
+AuraEffect* CreateAuraEffect(Aura * parentAura, uint32 effIndex, int32 *currentBasePoints, Unit *caster, Item *castItem = NULL, WorldObject *source = NULL);
+#endif
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 86c2235cdb5..12008b94ddb 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,10 +19,8 @@
*/
#include "Common.h"
-#include "SharedDefines.h"
#include "Database/DatabaseEnv.h"
#include "WorldPacket.h"
-#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
#include "UpdateMask.h"
@@ -32,7 +30,6 @@
#include "Player.h"
#include "SkillExtraItems.h"
#include "Unit.h"
-#include "CreatureAI.h"
#include "Spell.h"
#include "DynamicObject.h"
#include "SpellAuras.h"
@@ -47,6 +44,7 @@
#include "Creature.h"
#include "Totem.h"
#include "CreatureAI.h"
+#include "BattleGroundMgr.h"
#include "BattleGround.h"
#include "BattleGroundEY.h"
#include "BattleGroundWS.h"
@@ -60,6 +58,9 @@
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
+#include "SkillDiscovery.h"
+#include "Formulas.h"
+#include "Vehicle.h"
pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
{
@@ -104,8 +105,8 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
&Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
&Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
- &Spell::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD
- &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN
+ &Spell::EffectJump, // 41 SPELL_EFFECT_JUMP
+ &Spell::EffectJump, // 42 SPELL_EFFECT_JUMP2
&Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
&Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
&Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
@@ -128,16 +129,16 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
&Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
&Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
- &Spell::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused
- &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused
+ &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
+ &Spell::EffectUnused, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID)
&Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
&Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
&Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
&Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
&Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
&Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
- &Spell::EffectSummonPossessed, // 73 SPELL_EFFECT_SUMMON_POSSESSED
- &Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM
+ &Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
+ &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
&Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
&Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
&Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
@@ -150,17 +151,17 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
&Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
&Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
- &Spell::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1
- &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2
- &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3
- &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4
+ &Spell::EffectWMODamage, // 87 SPELL_EFFECT_WMO_DAMAGE
+ &Spell::EffectWMORepair, // 88 SPELL_EFFECT_WMO_REPAIR
+ &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE
+ &Spell::EffectKillCredit, // 90 SPELL_EFFECT_KILL_CREDIT
&Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
&Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
&Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
&Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
&Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
- &Spell::EffectUnused, // 96 SPELL_EFFECT_CHARGE
- &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER
+ &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
+ &Spell::EffectUnused, // 97 SPELL_EFFECT_97
&Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
&Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
&Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
@@ -175,7 +176,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
&Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
&Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
- &Spell::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON
+ &Spell::EffectUnused, //112 SPELL_EFFECT_112
&Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
&Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
&Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
@@ -195,21 +196,21 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
&Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT
&Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
- &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value
+ &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
&Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
&Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
&Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
&Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
&Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
- &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
- &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused
+ &Spell::EffectJump2, //138 SPELL_EFFECT_138 Leap
+ &Spell::EffectUnused, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID)
&Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
&Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
&Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
&Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
&Spell::EffectKnockBack, //144 SPELL_EFFECT_KNOCK_BACK_2 Spectral Blast
&Spell::EffectPlayerPull, //145 SPELL_EFFECT_145 Black Hole Effect
- &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused
+ &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
&Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
&Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
&Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
@@ -217,6 +218,12 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
&Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
&Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
+ &Spell::EffectNULL, //154 unused
+ &Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
+ &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
+ &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create/learn item/spell for profession
+ &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
+ &Spell::EffectRenamePet //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
};
void Spell::EffectNULL(uint32 /*i*/)
@@ -279,8 +286,7 @@ void Spell::EffectInstaKill(uint32 /*i*/)
if(m_caster==unitTarget) // prevent interrupt message
finish();
- uint32 health = unitTarget->GetHealth();
- m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
}
void Spell::EffectEnvirinmentalDMG(uint32 i)
@@ -291,13 +297,13 @@ void Spell::EffectEnvirinmentalDMG(uint32 i)
// Note: this hack with damage replace required until GO casting not implemented
// environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
// currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
- damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
+ damage = m_spellInfo->CalculateSimpleValue(i);
- m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
+ m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, m_spellInfo);
m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
if(m_caster->GetTypeId() == TYPEID_PLAYER)
- ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
+ ((Player*)m_caster)->EnvironmentalDamage(DAMAGE_FIRE,damage);
}
void Spell::EffectSchoolDMG(uint32 effect_idx)
@@ -331,14 +337,48 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
switch(m_spellInfo->Id) // better way to check unknown
{
- case 35354: //Hand of Death
- {
- if(unitTarget && unitTarget->HasAura(38528,0)) //Protection of Elune
+ // Positive/Negative Charge
+ case 28062:
+ case 28085:
+ case 39090:
+ case 39093:
+ if(!m_triggeredByAuraSpell)
+ break;
+ if(unitTarget == m_caster)
{
- damage = 0;
+ uint8 count = 0;
+ for(std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
+ if(ihit->targetGUID != m_caster->GetGUID())
+ if(Player *target = ObjectAccessor::FindPlayer(ihit->targetGUID))
+ if(target->HasAura(m_triggeredByAuraSpell->Id))
+ ++count;
+ if(count)
+ {
+ uint32 spellId;
+ switch(m_spellInfo->Id)
+ {
+ case 28062: spellId = 29659; break;
+ case 28085: spellId = 29660; break;
+ case 39090: spellId = 39089; break;
+ case 39093: spellId = 39092; break;
+ }
+ Aura *aur = m_caster->GetAura(spellId);
+ if(!aur)
+ {
+ m_caster->CastSpell(m_caster, spellId, true);
+ aur = m_caster->GetAura(spellId);
+ }
+ if(aur)
+ aur->SetStackAmount(count);
+ }
}
+ else if(unitTarget->HasAura(m_triggeredByAuraSpell->Id))
+ damage = 0;
+ break;
+ // Consumption
+ case 28865:
+ damage = (m_caster->GetMap()->IsHeroic() ? 4250 : 2750);
break;
- }
// percent from health with min
case 25599: // Thundercrash
{
@@ -347,6 +387,13 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
damage = 200;
break;
}
+ // Intercept (warrior spell trigger)
+ case 20253:
+ case 61491:
+ {
+ damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f);
+ break;
+ }
// arcane charge. must only affect demons (also undead?)
case 45072:
{
@@ -362,7 +409,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
if(unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
- float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0]));
+ float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0]));
if(!radius) return;
float distance = m_caster->GetDistance2d(unitTarget);
damage = (distance > radius ) ? 0 : (int32)(m_spellInfo->EffectBasePoints[0]*((radius - distance)/radius));
@@ -376,121 +423,111 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
break;
}
- case SPELLFAMILY_MAGE:
- {
- // Arcane Blast
- if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
- {
- m_caster->CastSpell(m_caster,36032,true);
- }
- break;
- }
case SPELLFAMILY_WARRIOR:
{
// Bloodthirst
- if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
+ if(m_spellInfo->SpellFamilyFlags[1] & 0x400)
{
damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
}
// Shield Slam
- else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->Category==1209)
damage += int32(m_caster->GetShieldBlockValue());
// Victory Rush
- else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x100)
{
damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
}
+ // Revenge ${$m1+$AP*0.207} to ${$M1+$AP*0.207}
+ else if(m_spellInfo->SpellFamilyFlags[0] & 0x400)
+ damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.207f);
+ // Heroic Throw ${$m1+$AP*.50}
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x00000001)
+ damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
+ // Shockwave ${$m3/100*$AP}
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x00008000)
+ {
+ int32 pct = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
+ if (pct > 0)
+ damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
+ break;
+ }
+ // Thunder Clap
+ else if(m_spellInfo->SpellFamilyFlags[0] & 0x80)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 12 / 100);
+ break;
+ }
break;
}
case SPELLFAMILY_WARLOCK:
{
// Incinerate Rank 1 & 2
- if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
+ if((m_spellInfo->SpellFamilyFlags[1] & 0x000040) && m_spellInfo->SpellIconID==2128)
{
// Incinerate does more dmg (dmg*0.25) if the target is Immolated.
- if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
- damage += int32(damage*0.25);
+ if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE, m_spellInfo, m_caster))
+ damage += int32(damage*0.25f);
}
-
// Conflagrate - consumes immolate
if (m_spellInfo->TargetAuraState == AURA_STATE_IMMOLATE)
{
+ // Glyph of Conflagrate
+ if (m_caster->HasAura(56235))
+ break;
// for caster applied auras only
- Unit::AuraList const &mPeriodic = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
- for(Unit::AuraList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
+ Unit::AuraEffectList const &mPeriodic = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ for(Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
{
- if( (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && ((*i)->GetSpellProto()->SpellFamilyFlags & 4) &&
+ if( (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && ((*i)->GetSpellProto()->SpellFamilyFlags[0] & 4 || (*i)->GetSpellProto()->SpellFamilyFlags[2] & 2) &&
(*i)->GetCasterGUID()==m_caster->GetGUID() )
{
- unitTarget->RemoveAurasByCasterSpell((*i)->GetId(), m_caster->GetGUID());
+ unitTarget->RemoveAurasDueToSpell((*i)->GetId(), m_caster->GetGUID());
break;
}
}
}
break;
}
+ case SPELLFAMILY_PRIEST:
+ {
+ // Shadow Word: Death - deals damage equal to damage done to caster
+ if ((m_spellInfo->SpellFamilyFlags[1] & 0x2 ))
+ m_caster->CastCustomSpell(m_caster, 32409, &damage, 0, 0, true);
+ break;
+ }
case SPELLFAMILY_DRUID:
{
// Ferocious Bite
- if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587)
+ if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[0] & 0x000800000) && m_spellInfo->SpellVisual[0]==6587)
{
- // converts each extra point of energy into ($f1+$AP/630) additional damage
- float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx];
+ // converts each extra point of energy into ($f1+$AP/410) additional damage
+ float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
+ float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
+ damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
m_caster->SetPower(POWER_ENERGY,0);
}
// Rake
- else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
+ else if(m_spellInfo->SpellFamilyFlags[0] & 0x1000)
{
damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
}
// Swipe
- else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x00100000)
{
damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
}
- // Starfire
- else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
- {
- Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
- {
- // Starfire Bonus (caster)
- switch((*i)->GetModifier()->m_miscvalue)
- {
- case 5481: // Nordrassil Regalia - bonus
- {
- Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
- for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
- {
- // Moonfire or Insect Swarm (target debuff from any casters)
- if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
- {
- int32 mod = (*i)->GetModifier()->m_amount;
- damage += damage*mod/100;
- break;
- }
- }
- break;
- }
- case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
- {
- damage += (*i)->GetModifier()->m_amount;
- break;
- }
- }
- }
- }
//Mangle Bonus for the initial damage of Lacerate and Rake
- if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
- (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
+ if((m_spellInfo->SpellFamilyFlags.IsEqual(0x1000,0,0) && m_spellInfo->SpellIconID==494) ||
+ (m_spellInfo->SpellFamilyFlags.IsEqual(0,0x100,0) && m_spellInfo->SpellIconID==2246))
{
- Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
- if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
+ Unit::AuraEffectList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
+ if((*i)->GetSpellProto()->SpellFamilyFlags[1] & 0x00000440 && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
{
- damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
+ damage = int32(damage*(100.0f+(*i)->GetAmount())/100.0f);
break;
}
}
@@ -499,78 +536,97 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
case SPELLFAMILY_ROGUE:
{
// Envenom
- if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
+ if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[1] & 0x8))
{
// consume from stack dozes not more that have combo-points
if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
{
- // count consumed deadly poison doses at target
- uint32 doses = 0;
-
- // remove consumed poison doses
- Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
- for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
- {
- // Deadly poison (only attacker applied)
- if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
- (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
+ Aura *poison = 0;
+ // Lookup for Deadly poison (only attacker applied)
+ Unit::AuraEffectList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
+ if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
+ (*itr)->GetSpellProto()->SpellFamilyFlags[0] & 0x10000 &&
+ (*itr)->GetCasterGUID()==m_caster->GetGUID() )
{
- --combo;
- ++doses;
-
- unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
-
- itr = auras.begin();
+ poison = (*itr)->GetParentAura();
+ break;
}
- else
- ++itr;
+ // count consumed deadly poison doses at target
+ if (poison)
+ {
+ uint32 spellId = poison->GetId();
+ uint32 doses = poison->GetStackAmount();
+ if (doses > combo)
+ doses = combo;
+ for (int i=0; i< doses; i++)
+ unitTarget->RemoveAuraFromStack(spellId);
+ damage *= doses;
+ damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
}
-
- damage *= doses;
- damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
-
// Eviscerate and Envenom Bonus Damage (item set effect)
if(m_caster->GetDummyAura(37169))
damage += ((Player*)m_caster)->GetComboPoints()*40;
}
}
// Eviscerate
- else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
+ else if((m_spellInfo->SpellFamilyFlags[0] & 0x00020000) && m_caster->GetTypeId()==TYPEID_PLAYER)
{
if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
{
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f);
+ 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->GetDummyAura(37169))
damage += combo*40;
}
}
+ // Gouge
+ else if(m_spellInfo->SpellFamilyFlags[0] & 0x8)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.21f);
+ }
+ // Instant Poison
+ else if(m_spellInfo->SpellFamilyFlags[0] & 0x2000)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
+ }
+ // Wound Poison
+ else if(m_spellInfo->SpellFamilyFlags[0] & 0x10000000)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
+ }
break;
}
case SPELLFAMILY_HUNTER:
{
// Mongoose Bite
- if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342)
+ if((m_spellInfo->SpellFamilyFlags[0] & 0x2) && m_spellInfo->SpellVisual[0]==342)
{
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2);
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
+ }
+ // Counterattack
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x00080000)
+ {
+ damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
}
// Arcane Shot
- else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
+ else if((m_spellInfo->SpellFamilyFlags[0] & 0x00000800) && m_spellInfo->maxLevel > 0)
{
- damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15);
+ damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
}
// Steady Shot
- else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x1)
{
int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
- damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
+ damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
bool found = false;
// check dazed affect
- Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
- for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
+ Unit::AuraEffectList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
+ for(Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
{
if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
{
@@ -583,28 +639,39 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
if(found)
damage += m_spellInfo->EffectBasePoints[1];
}
- //Explosive Trap Effect
- else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
+ // Explosive Trap Effect
+ else if(m_spellInfo->SpellFamilyFlags[0] & 0x00000004)
{
- damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1);
+ damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
}
break;
}
case SPELLFAMILY_PALADIN:
{
- //Judgement of Vengeance
- if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
- {
- uint32 stacks = 0;
- Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
- for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
- if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
- ++stacks;
- if(!stacks)
- //No damage if the target isn't affected by this
- damage = -1;
- else
- damage *= stacks;
+ // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP)
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x4000)
+ {
+ float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
+ damage += int32(ap * 0.07f);
+ }
+ // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP)
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x00000080)
+ {
+ float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
+ damage += int32(ap * 0.15f);
+ }
+ // Hammer of the Righteous
+ else if(m_spellInfo->SpellFamilyFlags[1]&0x00040000)
+ {
+ // Add main hand dps * effect[2] amount
+ float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
+ int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
+ damage += count * int32(average * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
+ }
+ // Shield of Righteousness
+ else if(m_spellInfo->SpellFamilyFlags[1]&0x00100000)
+ {
+ damage+=int32(m_caster->GetShieldBlockValue());
}
break;
}
@@ -664,9 +731,9 @@ void Spell::EffectDummy(uint32 i)
if (!creatureTarget || !pGameObj) return;
- if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 181574, creatureTarget->GetMap(),
+ if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 181574, creatureTarget->GetMap(), creatureTarget->GetPhaseMask(),
creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
- creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY))
{
delete pGameObj;
return;
@@ -772,12 +839,6 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
return;
}
- case 12975: //Last Stand
- {
- int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
- m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
- return;
- }
case 13120: // net-o-matic
{
if(!unitTarget)
@@ -814,30 +875,6 @@ void Spell::EffectDummy(uint32 i)
}
return;
}
- case 14185: // Preparation Rogue
- {
- if(m_caster->GetTypeId()!=TYPEID_PLAYER)
- return;
-
- //immediately finishes the cooldown on certain Rogue abilities
- const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
- {
- uint32 classspell = itr->first;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
-
- if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL))
- {
- ((Player*)m_caster)->RemoveSpellCooldown(classspell);
-
- WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
- data << uint32(classspell);
- data << uint64(m_caster->GetGUID());
- ((Player*)m_caster)->GetSession()->SendPacket(&data);
- }
- }
- return;
- }
case 15998: // Capture Worg Pup
case 29435: // Capture Female Kaliri Hatchling
{
@@ -902,19 +939,20 @@ void Spell::EffectDummy(uint32 i)
if(creatureTarget->isPet())
return;
+ GameObject* Crystal_Prison = m_caster->SummonGameObject(179644, creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), creatureTarget->GetOrientation(), 0, 0, 0, 0, creatureTarget->GetRespawnTime()-time(NULL));
+ sLog.outDebug("SummonGameObject at SpellEfects.cpp EffectDummy for Spell 23019");
+
creatureTarget->setDeathState(JUST_DIED);
creatureTarget->RemoveCorpse();
creatureTarget->SetHealth(0); // just for nice GM-mode view
- GameObject* Crystal_Prison = m_caster->SummonGameObject(179644, creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), creatureTarget->GetOrientation(), 0, 0, 0, 0, creatureTarget->GetRespawnTime()-time(NULL));
- sLog.outDebug("SummonGameObject at SpellEfects.cpp EffectDummy for Spell 23019\n");
WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
data << uint64(Crystal_Prison->GetGUID());
m_caster->SendMessageToSet(&data,true);
return;
}
- case 23074: // Arc. Dragonling
+ case 23074: // Arcanite Dragonling
if (!m_CastItem) return;
m_caster->CastSpell(m_caster,19804,true,m_CastItem);
return;
@@ -962,7 +1000,7 @@ void Spell::EffectDummy(uint32 i)
float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
float speed = m_caster->GetSpeedRate(MOVE_RUN);
- m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+ m_caster->RemoveAurasByType(SPELL_AURA_MOUNTED);
//5 different spells used depending on mounted speed and if mount can fly or not
if (flyspeed >= 4.1f)
@@ -982,21 +1020,20 @@ void Spell::EffectDummy(uint32 i)
// return; -- implemented at client side
case 28006: // Arcane Cloaking
{
- if( unitTarget->GetTypeId() == TYPEID_PLAYER )
+ if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER )
m_caster->CastSpell(unitTarget,29294,true);
return;
}
- case 28730: // Arcane Torrent (Mana)
- {
- Aura * dummy = m_caster->GetDummyAura(28734);
- if (dummy)
- {
- int32 bp = damage * dummy->GetStackAmount();
- m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
- m_caster->RemoveAurasDueToSpell(28734);
- }
- return;
- }
+ // Polarity Shift
+ case 28089:
+ if(unitTarget)
+ unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 28059 : 28084, true, NULL, NULL, m_caster->GetGUID());
+ break;
+ // Polarity Shift
+ case 39096:
+ if(unitTarget)
+ unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 39088 : 39091, true, NULL, NULL, m_caster->GetGUID());
+ break;
case 29200: // Purify Helboar Meat
{
if( m_caster->GetTypeId() != TYPEID_PLAYER )
@@ -1026,6 +1063,13 @@ void Spell::EffectDummy(uint32 i)
else // backfire 20%
m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
return;
+ case 55004: //Nitro Boosts
+ if(!m_CastItem) return;
+ if(roll_chance_i(95)) //success
+ m_caster->CastSpell(m_caster, 54861, true, m_CastItem);
+ else //backfire 5%
+ m_caster->CastSpell(m_caster, 46014, true, m_CastItem);
+ return;
case 33060: // Make a Wish
{
if(m_caster->GetTypeId()!=TYPEID_PLAYER)
@@ -1126,36 +1170,6 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(m_caster,42337,true,NULL);
return;
}
- case 37573: //Temporal Phase Modulator
- {
- if(!unitTarget)
- return;
-
- TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
- if(!tempSummon)
- return;
-
- uint32 health = tempSummon->GetHealth();
- const uint32 entry_list[6] = {21821, 21820, 21817};
-
- float x = tempSummon->GetPositionX();
- float y = tempSummon->GetPositionY();
- float z = tempSummon->GetPositionZ();
- float o = tempSummon->GetOrientation();
-
- tempSummon->UnSummon();
-
- Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
- if (!pCreature)
- return;
-
- pCreature->SetHealth(health);
-
- if(pCreature->IsAIEnabled)
- pCreature->AI()->AttackStart(m_caster);
-
- return;
- }
case 34665: //Administer Antidote
{
if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
@@ -1164,7 +1178,7 @@ void Spell::EffectDummy(uint32 i)
if(!unitTarget)
return;
- TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
+ TempSummon* tempSummon = dynamic_cast<TempSummon*>(unitTarget);
if(!tempSummon)
return;
@@ -1181,7 +1195,7 @@ void Spell::EffectDummy(uint32 i)
return;
pCreature->SetHealth(health);
- ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
+ ((Player*)m_caster)->RewardPlayerAndGroupAtEvent(16992,pCreature);
if (pCreature->IsAIEnabled)
pCreature->AI()->AttackStart(m_caster);
@@ -1231,7 +1245,52 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(m_caster, 30452, true, NULL);
return;
- }
+ }
+ case 51592: // Pickup Primordial Hatchling
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
+ return;
+
+ Creature* creatureTarget = (Creature*)unitTarget;
+
+ creatureTarget->setDeathState(JUST_DIED);
+ creatureTarget->RemoveCorpse();
+ creatureTarget->SetHealth(0); // just for nice GM-mode view
+ return;
+
+ }
+ case 52308:
+ {
+ switch(i)
+ {
+ case 0:
+ {
+ uint32 spellID = m_spellInfo->CalculateSimpleValue(0);
+ uint32 reqAuraID = m_spellInfo->CalculateSimpleValue(1);
+
+ if (m_caster->HasAuraEffect(reqAuraID,0))
+ m_caster->CastSpell(m_caster,spellID,true,NULL);
+ return;
+ }
+ case 1:
+ return; // additional data for dummy[0]
+ }
+ return;
+ }
+ case 52759: // Ancestral Awakening
+ if (!unitTarget)
+ return;
+ m_caster->CastCustomSpell(unitTarget, 52752, &damage, NULL, NULL, true);
+ return;
+ case 53341:
+ case 53343:
+ {
+ m_caster->CastSpell(m_caster,54586,true);
+ return;
+ }
+ case 58418: // Portal to Orgrimmar
+ case 58420: // Portal to Stormwind
+ return; // implemented in EffectScript[0]
}
//All IconID Check in there
@@ -1281,12 +1340,7 @@ void Spell::EffectDummy(uint32 i)
(GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
{
- ((Player*)m_caster)->RemoveSpellCooldown(classspell);
-
- WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
- data << uint32(classspell);
- data << uint64(m_caster->GetGUID());
- ((Player*)m_caster)->GetSession()->SendPacket(&data);
+ ((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
}
}
return;
@@ -1305,65 +1359,140 @@ void Spell::EffectDummy(uint32 i)
break;
case SPELLFAMILY_WARRIOR:
// Charge
- if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867)
+ if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
{
int32 chargeBasePoints0 = damage;
m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
return;
}
+ //Slam
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x200000 && m_spellInfo->SpellIconID == 559)
+ {
+ int32 bp0 = damage;
+ m_caster->CastCustomSpell(unitTarget, 50783, &bp0, NULL, NULL, true, 0);
+ return;
+ }
// Execute
- if(m_spellInfo->SpellFamilyFlags & 0x20000000)
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x20000000)
{
if(!unitTarget)
return;
+ uint32 rage=0;
+ // Glyph of Execution bonus
+ if (AuraEffect *aura = m_caster->GetDummyAura(58367))
+ rage+=aura->GetAmount();
+
spell_id = 20647;
- bp = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]);
- m_caster->SetPower(POWER_RAGE,0);
+ // Sudden death cost modifier
+ if (Aura * aur = m_caster->GetAura(52437))
+ {
+ rage += m_powerCost;
+ m_caster->ModifyPower(POWER_RAGE,- m_powerCost);
+ if (m_caster->GetPower(POWER_RAGE)<100)
+ m_caster->SetPower(POWER_RAGE,100);
+ m_caster->RemoveAura(aur);
+ }
+ else
+ {
+ rage += m_caster->GetPower(POWER_RAGE);
+ m_caster->SetPower(POWER_RAGE,0);
+ }
+
+ bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
+ m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
break;
}
- if(m_spellInfo->Id==21977) //Warrior's Wrath
+ // Slam
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x200000)
{
if(!unitTarget)
return;
-
- m_caster->CastSpell(unitTarget,21887,true); // spell mod
+ m_damage+=m_caster->CalculateDamage(m_attackType, false);
+ m_damage+=damage;
return;
}
+ // Concussion Blow
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x4000000)
+ {
+ m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
+ return;
+ }
+ switch(m_spellInfo->Id)
+ {
+ // Warrior's Wrath
+ case 21977:
+ {
+ if(!unitTarget)
+ return;
+ m_caster->CastSpell(unitTarget,21887,true); // spell mod
+ return;
+ }
+ // Last Stand
+ case 12975:
+ {
+ int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
+ m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
+ return;
+ }
+ // Bloodthirst
+ case 23881:
+ {
+ m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL);
+ return;
+ }
+ }
break;
case SPELLFAMILY_WARLOCK:
- //Life Tap (only it have this with dummy effect)
- if (m_spellInfo->SpellFamilyFlags == 0x40000)
+ // Life Tap
+ if (m_spellInfo->SpellFamilyFlags[0] & 0x40000)
{
- float cost = damage;
-
- if(Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this);
-
- int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE);
-
- if(int32(m_caster->GetHealth()) > dmg)
+ // In 303 exist spirit depend
+ uint32 spirit = uint32(m_caster->GetStat(STAT_SPIRIT));
+ switch (m_spellInfo->Id)
+ {
+ case 1454: damage+=spirit; break;
+ case 1455: damage+=spirit*15/10; break;
+ case 1456: damage+=spirit*2; break;
+ case 11687: damage+=spirit*25/10; break;
+ case 11688:
+ case 11689:
+ case 27222:
+ case 57946: damage+=spirit*3; break;
+ default:
+ sLog.outError("Spell::EffectDummy: %u Life Tap need set spirit multipler", m_spellInfo->Id);
+ return;
+ }
+// Think its not need (also need remove Life Tap from SpellDamageBonus or add new value)
+// damage = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(damage > 0 ? damage : 0), SPELL_DIRECT_DAMAGE);
+ if(unitTarget && (int32(unitTarget->GetHealth()) > damage))
{
// Shouldn't Appear in Combat Log
- m_caster->ModifyHealth(-dmg);
-
- int32 mana = dmg;
+ unitTarget->ModifyHealth(-damage);
- Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
+ int32 mana = damage;
+ // Improved Life Tap mod
+ Unit::AuraEffectList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
{
- // only Imp. Life Tap have this in combination with dummy aura
if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
- mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
+ mana = ((*itr)->GetAmount() + 100)* mana / 100;
}
-
- m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL);
+ m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
// Mana Feed
- int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster);
- manaFeedVal = manaFeedVal * mana / 100;
+ int32 manaFeedVal = 0;
+ Unit::AuraEffectList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
+ for(Unit::AuraEffectList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
+ {
+ if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
+ manaFeedVal+= (*itr)->GetAmount();
+ }
if(manaFeedVal > 0)
- m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL);
+ {
+ manaFeedVal = manaFeedVal * mana / 100;
+ m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
+ }
}
else
SendCastResult(SPELL_FAILED_FIZZLE);
@@ -1371,52 +1500,54 @@ void Spell::EffectDummy(uint32 i)
}
break;
case SPELLFAMILY_PRIEST:
- switch(m_spellInfo->Id )
+ // Penance
+ if (m_spellInfo->SpellFamilyFlags[1] & 0x00800000)
{
- case 28598: // Touch of Weakness triggered spell
+ if (!unitTarget || !unitTarget->isAlive())
+ return;
+
+ int hurt = 0;
+ int heal = 0;
+ switch(m_spellInfo->Id)
{
- if(!unitTarget || !m_triggeredByAuraSpell)
+ case 47540: hurt = 47758; heal = 47757; break;
+ case 53005: hurt = 53001; heal = 52986; break;
+ case 53006: hurt = 53002; heal = 52987; break;
+ case 53007: hurt = 53003; heal = 52988; break;
+ default:
+ sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id);
return;
-
- uint32 spellid = 0;
- switch(m_triggeredByAuraSpell->Id)
- {
- case 2652: spellid = 2943; break; // Rank 1
- case 19261: spellid = 19249; break; // Rank 2
- case 19262: spellid = 19251; break; // Rank 3
- case 19264: spellid = 19252; break; // Rank 4
- case 19265: spellid = 19253; break; // Rank 5
- case 19266: spellid = 19254; break; // Rank 6
- case 25461: spellid = 25460; break; // Rank 7
- default:
- sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandled spell %u",m_triggeredByAuraSpell->Id);
- return;
- }
- m_caster->CastSpell(unitTarget, spellid, true, NULL);
- return;
}
+ if (m_caster->IsFriendlyTo(unitTarget))
+ m_caster->CastSpell(unitTarget, heal, true, 0);
+ else
+ m_caster->CastSpell(unitTarget, hurt, true, 0);
+ return;
}
break;
case SPELLFAMILY_DRUID:
- switch(m_spellInfo->Id )
+ // Starfall
+ if (m_spellInfo->SpellFamilyFlags[2] & 0x100)
{
- case 5420: // Tree of Life passive
+ //Shapeshifting into an animal form or mounting cancels the effect.
+ if(m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted())
{
- // Tree of Life area effect
- int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
- m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
+ if(m_triggeredByAuraSpell)
+ m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id);
return;
}
+
+ //Any effect which causes you to lose control of your character will supress the starfall effect.
+ if(m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED))
+ return;
+
+ m_caster->CastSpell(unitTarget, damage, true);
+ return;
}
break;
case SPELLFAMILY_ROGUE:
switch(m_spellInfo->Id )
{
- case 31231: // Cheat Death
- {
- m_caster->CastSpell(m_caster,45182,true);
- return;
- }
case 5938: // Shiv
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
@@ -1452,36 +1583,31 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(unitTarget, 5940, true);
return;
}
- }
- break;
- case SPELLFAMILY_HUNTER:
- // Kill command
- if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
- {
- if(m_caster->getClass()!=CLASS_HUNTER)
- return;
+ case 14185: // Preparation Rogue
+ {
+ if(m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
- // clear hunter crit aura state
- m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
+ //immediately finishes the cooldown on certain Rogue abilities
+ const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
+ for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ {
+ uint32 classspell = itr->first;
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
- // additional damage from pet to pet target
- Pet* pet = m_caster->GetPet();
- if(!pet || !pet->getVictim())
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags[1] & 0x00000240 || spellInfo->SpellFamilyFlags[0] & 0x00000860))
+ ((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
+ }
return;
-
- uint32 spell_id = 0;
- switch (m_spellInfo->Id)
+ }
+ case 31231: // Cheat Death
{
- case 34026: spell_id = 34027; break; // rank 1
- default:
- sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
+ m_caster->CastSpell(m_caster,45182,true);
return;
}
-
- pet->CastSpell(pet->getVictim(), spell_id, true);
- return;
}
-
+ break;
+ case SPELLFAMILY_HUNTER:
switch(m_spellInfo->Id)
{
case 23989: //Readiness talent
@@ -1497,14 +1623,7 @@ void Spell::EffectDummy(uint32 i)
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
- {
- ((Player*)m_caster)->RemoveSpellCooldown(classspell);
-
- WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
- data << uint32(classspell);
- data << uint64(m_caster->GetGUID());
- ((Player*)m_caster)->GetSession()->SendPacket(&data);
- }
+ ((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
}
return;
}
@@ -1524,6 +1643,13 @@ void Spell::EffectDummy(uint32 i)
case SPELLFAMILY_PALADIN:
switch(m_spellInfo->SpellIconID)
{
+ // Divine Storm
+ if (m_spellInfo->SpellFamilyFlags[1] & 0x20000)
+ {
+ int32 damage=m_currentBasePoints[0] * damage /100;
+ m_caster->CastCustomSpell(unitTarget, 54172, &damage , 0, 0, true);
+ return;
+ }
case 156: // Holy Shock
{
if(!unitTarget)
@@ -1539,6 +1665,8 @@ void Spell::EffectDummy(uint32 i)
case 20930: hurt = 25902; heal = 25903; break;
case 27174: hurt = 27176; heal = 27175; break;
case 33072: hurt = 33073; heal = 33074; break;
+ case 48824: hurt = 48822; heal = 48820; break;
+ case 48825: hurt = 48823; heal = 48821; break;
default:
sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
return;
@@ -1551,32 +1679,31 @@ void Spell::EffectDummy(uint32 i)
return;
}
- case 561: // Judgement of command
+ }
+
+ switch(m_spellInfo->Id)
+ {
+ case 20425: // Judgement of command
{
if(!unitTarget)
return;
- uint32 spell_id = m_spellInfo->EffectBasePoints[i]+1;//m_currentBasePoints[i]+1;
- SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
+ SpellEntry const* spell_proto = sSpellStore.LookupEntry(damage);
if(!spell_proto)
return;
- if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
+ if(unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
{
- // decreased damage (/2) for non-stunned target.
+ // always critical for stunned target
SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_DAMAGE;
- mod->value = -50;
- mod->type = SPELLMOD_PCT;
+ mod->op = SPELLMOD_CRITICAL_CHANCE;
+ mod->value = 100;
+ mod->type = SPELLMOD_FLAT;
mod->spellId = m_spellInfo->Id;
- mod->effectId = i;
- mod->lastAffected = NULL;
- mod->mask = 0x0000020000000000LL;
- mod->charges = 0;
+ mod->mask[1] = 0x00000200;
((Player*)m_caster)->AddSpellMod(mod, true);
m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
- // mod deleted
((Player*)m_caster)->AddSpellMod(mod, false);
}
else
@@ -1584,10 +1711,6 @@ void Spell::EffectDummy(uint32 i)
return;
}
- }
-
- switch(m_spellInfo->Id)
- {
case 31789: // Righteous Defense (step 1)
{
// 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
@@ -1595,17 +1718,8 @@ void Spell::EffectDummy(uint32 i)
// non-standard cast requirement check
if (!unitTarget || unitTarget->getAttackers().empty())
{
- // clear cooldown at fail
if(m_caster->GetTypeId()==TYPEID_PLAYER)
- {
- ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
-
- WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
- data << uint32(m_spellInfo->Id);
- data << uint64(m_caster->GetGUID());
- ((Player*)m_caster)->GetSession()->SendPacket(&data);
- }
-
+ ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true);
SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
return;
}
@@ -1654,8 +1768,10 @@ void Spell::EffectDummy(uint32 i)
break;
case SPELLFAMILY_SHAMAN:
//Shaman Rockbiter Weapon
- if (m_spellInfo->SpellFamilyFlags == 0x400000)
+ if (m_spellInfo->SpellFamilyFlags.IsEqual(0x400000))
{
+ // TODO: use expect spell for enchant (if exist talent)
+ // In 3.0.3 no mods present for rockbiter
uint32 spell_id = 0;
switch(m_spellInfo->Id)
{
@@ -1663,11 +1779,6 @@ void Spell::EffectDummy(uint32 i)
case 8018: spell_id = 36750; break; // Rank 2
case 8019: spell_id = 36755; break; // Rank 3
case 10399: spell_id = 36759; break; // Rank 4
- case 16314: spell_id = 36763; break; // Rank 5
- case 16315: spell_id = 36766; break; // Rank 6
- case 16316: spell_id = 36771; break; // Rank 7
- case 25479: spell_id = 36775; break; // Rank 8
- case 25485: spell_id = 36499; break; // Rank 9
default:
sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
return;
@@ -1677,16 +1788,16 @@ void Spell::EffectDummy(uint32 i)
if(!spellInfo)
{
- sLog.outError("WORLD: unknown spell id %i\n", spell_id);
+ sLog.outError("WORLD: unknown spell id %i", spell_id);
return;
}
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
+ for(int j = BASE_ATTACK; j <= OFF_ATTACK; ++j)
{
- if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
+ if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(j)))
{
if(item->IsFitToSpellRequirements(m_spellInfo))
{
@@ -1705,18 +1816,89 @@ void Spell::EffectDummy(uint32 i)
}
return;
}
-
- if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
+ // Cleansing Totem
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x04000000 && m_spellInfo->SpellIconID==1673)
+ {
+ m_caster->CastSpell(unitTarget, 52025, true, 0, 0, m_originalCasterGUID);
+ return;
+ }
+ // Healing Stream Totem
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x2000)
+ {
+ m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
+ return;
+ }
+ // Mana Spring Totem
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x4000)
+ {
+ if(unitTarget->getPowerType()!=POWER_MANA)
+ return;
+ m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
+ return;
+ }
+ if(m_spellInfo->Id == 39610) // Mana Tide Totem effect
{
if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
return;
-
+ // Glyph of Mana Tide
+ Unit *owner = m_caster->GetOwner();
+ if (owner)
+ if (AuraEffect *dummy = owner->GetDummyAura(55441))
+ damage+=dummy->GetAmount();
// Regenerate 6% of Total Mana Every 3 secs
int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
return;
}
+ // Lava Lash
+ if (m_spellInfo->SpellFamilyFlags[2] & 0x00000004)
+ {
+ if (m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
+ Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ if (item)
+ {
+ if (m_caster->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000))
+ {
+ m_damage += m_damage * damage / 100;
+ }
+ }
+ return;
+ }
+ break;
+ case SPELLFAMILY_DEATHKNIGHT:
+ // Death strike dummy aura apply
+ // Used to proc healing later
+ if (m_spellInfo->SpellFamilyFlags[0] & 0x00000010)
+ {
+ spell_id=45469;
+ m_caster->CastSpell(m_caster,spell_id,true);
+ return;
+ }
+ // Death Coil
+ else if(m_spellInfo->SpellFamilyFlags[0] & 0x002000)
+ {
+ if(m_caster->IsFriendlyTo(unitTarget))
+ {
+ if(unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
+ return;
+ int32 bp = damage * 1.5f;
+ m_caster->CastCustomSpell(unitTarget,47633,&bp,NULL,NULL,true);
+ }
+ else
+ {
+ int32 bp = damage;
+ m_caster->CastCustomSpell(unitTarget,47632,&bp,NULL,NULL,true);
+ }
+ return;
+ }
+ // Death Grip
+ else if(m_spellInfo->Id == 49560)
+ {
+ unitTarget->CastSpell(m_caster, damage, true);
+ return;
+ }
break;
}
@@ -1744,6 +1926,15 @@ void Spell::EffectDummy(uint32 i)
m_caster->AddPetAura(petSpell);
return;
}
+
+ // Script based implementation. Must be used only for not good for implementation in core spell effects
+ // So called only for not proccessed cases
+ if(gameObjTarget)
+ Script->EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget);
+ else if(unitTarget && unitTarget->GetTypeId()==TYPEID_UNIT)
+ Script->EffectDummyCreature(m_caster, m_spellInfo->Id, i, (Creature*)unitTarget);
+ else if(itemTarget)
+ Script->EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget);
}
void Spell::EffectTriggerSpellWithValue(uint32 i)
@@ -1755,7 +1946,7 @@ void Spell::EffectTriggerSpellWithValue(uint32 i)
if(!spellInfo)
{
- sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
+ sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
return;
}
@@ -1781,8 +1972,8 @@ void Spell::EffectTriggerRitualOfSummoning(uint32 i)
targets.setUnitTarget( unitTarget);
spell->prepare(&targets);
- m_caster->SetCurrentCastedSpell(spell);
- spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
+ //m_caster->SetCurrentCastedSpell(spell);
+ //spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
}
@@ -1815,16 +2006,15 @@ void Spell::EffectTriggerSpell(uint32 i)
// Vanish
case 18461:
{
- m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
- m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
- m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
+ m_caster->RemoveMovementImpairingAuras();
+ m_caster->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
// if this spell is given to NPC it must handle rest by it's own AI
if ( m_caster->GetTypeId() != TYPEID_PLAYER )
return;
// get highest rank of the Stealth spell
- bool found = false;
+ uint32 spellId = 0;
SpellEntry const *spellInfo;
const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
@@ -1837,24 +2027,36 @@ void Spell::EffectTriggerSpell(uint32 i)
if (!spellInfo)
continue;
- if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_STEALTH)
{
- found=true;
+ spellId = spellInfo->Id;
break;
}
}
// no Stealth spell found
- if (!found)
+ if (!spellId)
return;
// reset cooldown on it if needed
- if(((Player*)m_caster)->HasSpellCooldown(spellInfo->Id))
- ((Player*)m_caster)->RemoveSpellCooldown(spellInfo->Id);
+ if(((Player*)m_caster)->HasSpellCooldown(spellId))
+ ((Player*)m_caster)->RemoveSpellCooldown(spellId);
+ // Push stealth to list because it must be handled after combat remove
m_TriggerSpells.push_back(spellInfo);
return;
}
+ // Demonic Empowerment -- succubus
+ case 54437:
+ {
+ unitTarget->RemoveMovementImpairingAuras();
+ unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
+ unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STUN);
+
+ // Cast Lesser Invisibility
+ triggered_spell_id = 7870;
+ break;
+ }
// just skip
case 23770: // Sayge's Dark Fortune of *
// not exist, common cooldown can be implemented in scripts if need.
@@ -1866,7 +2068,7 @@ void Spell::EffectTriggerSpell(uint32 i)
if (!spell)
return;
- for (int i=0; i < spell->StackAmount; ++i)
+ for (int j=0; j < spell->StackAmount; ++j)
m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
return;
}
@@ -1877,7 +2079,7 @@ void Spell::EffectTriggerSpell(uint32 i)
if (!spell)
return;
- for (int i=0; i < spell->StackAmount; ++i)
+ for (int j=0; j < spell->StackAmount; ++j)
m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
return;
}
@@ -1892,7 +2094,7 @@ void Spell::EffectTriggerSpell(uint32 i)
{
uint32 dispelMask = GetDispellMask(DISPEL_ALL);
Unit::AuraMap& Auras = m_caster->GetAuras();
- for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
+ for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end();)
{
// remove all harmful spells on you...
SpellEntry const* spell = iter->second->GetSpellProto();
@@ -1901,16 +2103,17 @@ void Spell::EffectTriggerSpell(uint32 i)
// ignore positive and passive auras
&& !iter->second->IsPositive() && !iter->second->IsPassive())
{
- m_caster->RemoveAurasDueToSpell(spell->Id);
- iter = Auras.begin();
+ m_caster->RemoveAura(iter);
}
+ else
+ iter++;
}
return;
}
// Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
case 41967:
{
- if (Unit *pet = m_caster->GetPet())
+ if (Unit *pet = m_caster->GetGuardianPet())
pet->CastSpell(pet, 28305, true);
return;
}
@@ -1925,44 +2128,13 @@ void Spell::EffectTriggerSpell(uint32 i)
return;
}
- // some triggered spells require specific equipment
- if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
- {
- // main hand weapon required
- if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
- {
- Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
-
- // skip spell if no weapon in slot or broken
- if(!item || item->IsBroken() )
- return;
-
- // skip spell if weapon not fit to triggered spell
- if(!item->IsFitToSpellRequirements(spellInfo))
- return;
- }
-
- // offhand hand weapon required
- if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
- {
- Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
-
- // skip spell if no weapon in slot or broken
- if(!item || item->IsBroken() )
- return;
-
- // skip spell if weapon not fit to triggered spell
- if(!item->IsFitToSpellRequirements(spellInfo))
- return;
- }
- }
-
// some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
bool instant = false;
for(uint32 j = i+1; j < 3; ++j)
{
if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER
- && (m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL))
+ && (m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL
+ || m_spellInfo->Effect[j]==SPELL_EFFECT_SANCTUARY))
{
instant = true;
break;
@@ -1995,12 +2167,65 @@ void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
if (m_CastItem)
DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
- Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
+ m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo->Id, true, m_CastItem, 0, m_originalCasterGUID);
+}
- SpellCastTargets targets;
- targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
- spell->m_CastItem = m_CastItem;
- spell->prepare(&targets, NULL);
+void Spell::EffectJump(uint32 i)
+{
+ if(m_caster->isInFlight())
+ return;
+
+ // Init dest coordinates
+ float x,y,z,o;
+ if(m_targets.HasDst())
+ {
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+
+ if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_TARGET_BACK)
+ {
+ // explicit cast data from client or server-side cast
+ // some spell at client send caster
+ Unit* pTarget = NULL;
+ if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=m_caster)
+ pTarget = m_targets.getUnitTarget();
+ else if(m_caster->getVictim())
+ pTarget = m_caster->getVictim();
+ else if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
+
+ o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation();
+ }
+ else
+ o = m_caster->GetOrientation();
+ }
+ else if(m_targets.getUnitTarget())
+ {
+ m_targets.getUnitTarget()->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
+ o = m_caster->GetOrientation();
+ }
+ else if(m_targets.getGOTarget())
+ {
+ m_targets.getGOTarget()->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
+ o = m_caster->GetOrientation();
+ }
+ else
+ {
+ sLog.outError( "Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id );
+ return;
+ }
+
+ //m_caster->NearTeleportTo(x,y,z,o,true);
+ float speedZ;
+ if(m_spellInfo->EffectMiscValue[i])
+ speedZ = float(m_spellInfo->EffectMiscValue[i])/10;
+ else if(m_spellInfo->EffectMiscValueB[i])
+ speedZ = float(m_spellInfo->EffectMiscValueB[i])/10;
+ else
+ speedZ = 10.0f;
+ float speedXY = m_caster->GetExactDistance2d(x, y) * 10.0f / speedZ;
+ m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ);
}
void Spell::EffectTeleportUnits(uint32 i)
@@ -2014,6 +2239,7 @@ void Spell::EffectTeleportUnits(uint32 i)
sLog.outError( "Spell::EffectTeleportUnits - does not have destination for spell ID %u\n", m_spellInfo->Id );
return;
}
+
// Init dest coordinates
int32 mapid = m_targets.m_mapId;
if(mapid < 0) mapid = (int32)unitTarget->GetMapId();
@@ -2022,16 +2248,11 @@ void Spell::EffectTeleportUnits(uint32 i)
float z = m_targets.m_destZ;
float orientation = m_targets.getUnitTarget() ? m_targets.getUnitTarget()->GetOrientation() : unitTarget->GetOrientation();
sLog.outDebug("Spell::EffectTeleportUnits - teleport unit to %u %f %f %f\n", mapid, x, y, z);
- // Teleport
- if(unitTarget->GetTypeId() == TYPEID_PLAYER)
- ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
- else
- {
- MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
- WorldPacket data;
- unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
- unitTarget->SendMessageToSet(&data, false);
- }
+
+ if(mapid == unitTarget->GetMapId())
+ unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster);
+ else if(unitTarget->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, unitTarget==m_caster ? TELE_TO_SPELL : 0);
// post effects for TARGET_DST_DB
switch ( m_spellInfo->Id )
@@ -2132,84 +2353,16 @@ void Spell::EffectTeleportUnits(uint32 i)
void Spell::EffectApplyAura(uint32 i)
{
- if(!unitTarget)
- return;
-
- SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
- for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
- if(itr->type == m_spellInfo->EffectApplyAuraName[i])
- return;
-
- // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
- if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
- (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
- return;
-
- Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
- if(!caster)
- return;
-
- sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
-
- Aura* Aur = CreateAura(m_spellInfo, i, &damage, unitTarget, caster, m_CastItem);
-
- // Now Reduce spell duration using data received at spell hit
- int32 duration = Aur->GetAuraMaxDuration();
- unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,caster,m_diminishLevel);
- Aur->setDiminishGroup(m_diminishGroup);
-
- // if Aura removed and deleted, do not continue.
- if(duration== 0 && !(Aur->IsPermanent()))
- {
- delete Aur;
- return;
- }
-
- if(duration != Aur->GetAuraMaxDuration())
- {
- Aur->SetAuraMaxDuration(duration);
- Aur->SetAuraDuration(duration);
- }
-
- bool added = unitTarget->AddAura(Aur);
-
- // Aura not added and deleted in AddAura call;
- if (!added)
- return;
-
- // found crash at character loading, broken pointer to Aur...
- // Aur was deleted in AddAura()...
- if(!Aur)
- return;
-
- // TODO Make a way so it works for every related spell!
- if(unitTarget->GetTypeId()==TYPEID_PLAYER ||( unitTarget->GetTypeId()==TYPEID_UNIT && ((Creature*)unitTarget)->isPet() ) ) // Negative buff should only be applied on players
- {
- uint32 spellId = 0;
- if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
- spellId = 6788; // Weakened Soul
- else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
- spellId = 25771; // Forbearance
- else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
- spellId = 41425; // Hypothermia
- else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
- spellId = 11196; // Recently Bandaged
- else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
- spellId = 23230; // Blood Fury - Healing Reduction
-
- SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
- if (AdditionalSpellInfo)
- {
- // applied at target by target
- Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, NULL, unitTarget,unitTarget, 0);
- unitTarget->AddAura(AdditionalAura);
- sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
- }
- }
+ if (m_spellAura)
+ if (AuraEffect * AurEff = m_spellAura->GetPartAura(i))
+ unitTarget->HandleAuraEffect(AurEff, true);
+}
- // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
- if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
- m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
+void Spell::EffectApplyAreaAura(uint32 i)
+{
+ if (m_spellAura)
+ if (AuraEffect * AurEff = m_spellAura->GetPartAura(i))
+ unitTarget->HandleAuraEffect(AurEff, true);
}
void Spell::EffectUnlearnSpecialization( uint32 i )
@@ -2259,7 +2412,8 @@ void Spell::EffectPowerDrain(uint32 i)
unitTarget->ModifyPower(drain_power,-new_damage);
- if(drain_power == POWER_MANA)
+ // Don`t restore from self drain
+ if(drain_power == POWER_MANA && m_caster != unitTarget)
{
float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
if(manaMultiplier==0)
@@ -2278,60 +2432,9 @@ void Spell::EffectPowerDrain(uint32 i)
void Spell::EffectSendEvent(uint32 EffectIndex)
{
- if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
- {
- BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
- if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
- {
- switch(m_spellInfo->Id)
- {
- case 23333: // Pickup Horde Flag
- /*do not uncomment .
- if(bg->GetTypeID()==BATTLEGROUND_WS)
- bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
- sLog.outDebug("Send Event Horde Flag Picked Up");
- break;
- /* not used :
- case 23334: // Drop Horde Flag
- if(bg->GetTypeID()==BATTLEGROUND_WS)
- bg->EventPlayerDroppedFlag((Player*)m_caster);
- sLog.outDebug("Drop Horde Flag");
- break;
- */
- case 23335: // Pickup Alliance Flag
- /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion
- if(bg->GetTypeID()==BATTLEGROUND_WS)
- bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
- sLog.outDebug("Send Event Alliance Flag Picked Up");
- break;
- /* not used :
- case 23336: // Drop Alliance Flag
- if(bg->GetTypeID()==BATTLEGROUND_WS)
- bg->EventPlayerDroppedFlag((Player*)m_caster);
- sLog.outDebug("Drop Alliance Flag");
- break;
- case 23385: // Alliance Flag Returns
- if(bg->GetTypeID()==BATTLEGROUND_WS)
- bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
- sLog.outDebug("Alliance Flag Returned");
- break;
- case 23386: // Horde Flag Returns
- if(bg->GetTypeID()==BATTLEGROUND_WS)
- bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
- sLog.outDebug("Horde Flag Returned");
- break;*/
- case 34976:
- /*
- if(bg->GetTypeID()==BATTLEGROUND_EY)
- bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
- */
- break;
- default:
- sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
- break;
- }
- }
- }
+ /*
+ we do not handle a flag dropping or clicking on flag in battleground by sendevent system
+ */
sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
}
@@ -2352,10 +2455,20 @@ void Spell::EffectPowerBurn(uint32 i)
if(damage < 0)
return;
+ Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
+
+ // burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn)
+ if(m_spellInfo->ManaCostPercentage)
+ {
+ uint32 maxdamage = m_caster->GetMaxPower(powertype) * damage * 2 / 100;
+ damage = unitTarget->GetMaxPower(powertype) * damage / 100;
+ if(damage > maxdamage) damage = maxdamage;
+ }
+
int32 curPower = int32(unitTarget->GetPower(powertype));
- // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
uint32 power = damage;
+ // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
@@ -2397,27 +2510,27 @@ void Spell::SpellDamageHeal(uint32 /*i*/)
{
// Amount of heal - depends from stacked Holy Energy
int damageAmount = 0;
- Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
+ Unit::AuraEffectList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
if((*i)->GetId() == 45062)
- damageAmount+=(*i)->GetModifierValue();
+ damageAmount+=(*i)->GetAmount();
if (damageAmount)
m_caster->RemoveAurasDueToSpell(45062);
addhealth += damageAmount;
}
// Swiftmend - consumes Regrowth or Rejuvenation
- else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
+ else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND, m_spellInfo, m_caster))
{
- Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
+ Unit::AuraEffectList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
// find most short by duration
- Aura *targetAura = NULL;
- for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
+ AuraEffect *targetAura = NULL;
+ for(Unit::AuraEffectList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
{
if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
- && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
+ && ((*i)->GetSpellProto()->SpellFamilyFlags.IsEqual(0x40) || (*i)->GetSpellProto()->SpellFamilyFlags.IsEqual(0x10)) )
{
- if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
+ if(!targetAura || (*i)->GetParentAura()->GetAuraDuration() < targetAura->GetParentAura()->GetAuraDuration())
targetAura = *i;
}
}
@@ -2428,29 +2541,43 @@ void Spell::SpellDamageHeal(uint32 /*i*/)
return;
}
- int32 tickheal = targetAura->GetModifierValuePerStack();
+ int32 tickheal = targetAura->GetAmount();
if(Unit* auraCaster = targetAura->GetCaster())
- tickheal = auraCaster->SpellHealingBonus(targetAura->GetSpellProto(), tickheal, DOT, unitTarget);
+ tickheal = auraCaster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), tickheal, DOT);
//int32 tickheal = targetAura->GetSpellProto()->EffectBasePoints[idx] + 1;
//It is said that talent bonus should not be included
- //int32 tickheal = targetAura->GetModifierValue();
+
int32 tickcount = 0;
if(targetAura->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID)
{
- switch(targetAura->GetSpellProto()->SpellFamilyFlags)//TODO: proper spellfamily for 3.0.x
+ switch(targetAura->GetSpellProto()->SpellFamilyFlags[0])
{
case 0x10: tickcount = 4; break; // Rejuvenation
case 0x40: tickcount = 6; break; // Regrowth
}
}
addhealth += tickheal * tickcount;
- unitTarget->RemoveAurasByCasterSpell(targetAura->GetId(), targetAura->GetCasterGUID());
+
+ // Glyph of Swiftmend
+ if(!caster->GetDummyAura(54824))
+ unitTarget->RemoveAura(targetAura->GetId(), targetAura->GetCasterGUID());
//addhealth += tickheal * tickcount;
//addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
}
+ // Riptide - increase healing done by Chain Heal
+ else if (m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x100)
+ {
+ addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
+ if (AuraEffect * aurEff = unitTarget->GetAura(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, m_originalCasterGUID))
+ {
+ addhealth *= 1.25f;
+ // consume aura
+ unitTarget->RemoveAura(aurEff->GetParentAura());
+ }
+ }
else
- addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
+ addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
m_damage -= addhealth;
}
@@ -2468,14 +2595,11 @@ void Spell::EffectHealPct( uint32 /*i*/ )
return;
uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
- caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
+ if(Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, addhealth, this);
- int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
+ int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo);
unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
-
- if(caster->GetTypeId()==TYPEID_PLAYER)
- if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
- bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
}
}
@@ -2491,9 +2615,8 @@ void Spell::EffectHealMechanical( uint32 /*i*/ )
if (!caster)
return;
- uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
- caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
- unitTarget->ModifyHealth( int32(damage) );
+ uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL);
+ caster->DealHeal(unitTarget, addhealth, m_spellInfo);
}
}
@@ -2516,18 +2639,14 @@ void Spell::EffectHealthLeech(uint32 i)
int32 new_damage = int32(damage*multiplier);
uint32 curHealth = unitTarget->GetHealth();
- new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
+ new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage );
if(curHealth < new_damage)
new_damage = curHealth;
if(m_caster->isAlive())
{
- new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
-
- m_caster->ModifyHealth(new_damage);
-
- if(m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
+ new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
+ m_caster->DealHeal(m_caster, uint32(new_damage), m_spellInfo);
}
// m_healthLeech+=tmpvalue;
// m_damage+=new_damage;
@@ -2575,8 +2694,8 @@ void Spell::DoCreateItem(uint32 i, uint32 itemtype)
if (num_to_add < 1)
num_to_add = 1;
- if (num_to_add > pProto->Stackable)
- num_to_add = pProto->Stackable;
+ if (num_to_add > pProto->GetMaxStackSize())
+ num_to_add = pProto->GetMaxStackSize();
// init items_count to 1, since 1 item will be created regardless of specialization
int items_count=1;
@@ -2634,7 +2753,7 @@ void Spell::DoCreateItem(uint32 i, uint32 itemtype)
// we succeeded in creating at least one item, so a levelup is possible
player->UpdateCraftSkill(m_spellInfo->Id);
- }
+ }
}
void Spell::EffectCreateItem(uint32 i)
@@ -2642,9 +2761,37 @@ void Spell::EffectCreateItem(uint32 i)
DoCreateItem(i,m_spellInfo->EffectItemType[i]);
}
+void Spell::EffectCreateItem2(uint32 i)
+{
+ if(m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
+ Player* player = (Player*)m_caster;
+
+ uint32 item_id = m_spellInfo->EffectItemType[i];
+ if(item_id)
+ DoCreateItem(i,item_id);
+
+ // special case: fake item replaced by generate using spell_loot_template
+ if(IsLootCraftingSpell(m_spellInfo))
+ {
+ if(item_id)
+ {
+ if(!player->HasItemCount(item_id,1))
+ return;
+
+ // remove reagent
+ uint32 count = 1;
+ player->DestroyItemCount (item_id,count,true);
+ }
+
+ // create some random items
+ player->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
+ }
+}
+
void Spell::EffectPersistentAA(uint32 i)
{
- float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
if(Player* modOwner = m_originalCaster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
@@ -2672,6 +2819,8 @@ void Spell::EffectEnergize(uint32 i)
if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
return;
+ Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
+
// Some level depends spells
int multiplier = 0;
int level_diff = 0;
@@ -2699,11 +2848,18 @@ void Spell::EffectEnergize(uint32 i)
if (level_diff > 0)
damage -= multiplier * level_diff;
+ //Judgement of wisdom energize effect
+ if(m_spellInfo->Id == 20268)
+ {
+ if(unitTarget->GetTypeId() == TYPEID_PLAYER)
+ {
+ damage = unitTarget->GetCreateMana() * damage / 100;
+ }
+ }
+
if(damage < 0)
return;
- Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
-
if(unitTarget->GetMaxPower(power) == 0)
return;
@@ -2771,7 +2927,7 @@ void Spell::EffectEnergisePct(uint32 i)
uint32 gain = damage * maxPower / 100;
unitTarget->ModifyPower(power, gain);
- m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
+ m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, gain, power);
}
void Spell::SendLoot(uint64 guid, LootType loottype)
@@ -2850,6 +3006,8 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
// Don't return, let loots been taken
+ default:
+ break;
}
}
@@ -2857,7 +3015,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
player->SendLoot(guid, loottype);
}
-void Spell::EffectOpenLock(uint32 /*i*/)
+void Spell::EffectOpenLock(uint32 effIndex)
{
if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
{
@@ -2867,7 +3025,6 @@ void Spell::EffectOpenLock(uint32 /*i*/)
Player* player = (Player*)m_caster;
- LootType loottype = LOOT_CORPSE;
uint32 lockId = 0;
uint64 guid = 0;
@@ -2879,7 +3036,7 @@ void Spell::EffectOpenLock(uint32 /*i*/)
if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
{
- //isAllowUseBattleGroundObject() already called in CanCast()
+ //CanUseBattleGroundObject() already called in CheckCast()
// in battleground check
if(BattleGround *bg = player->GetBattleGround())
{
@@ -2891,7 +3048,7 @@ void Spell::EffectOpenLock(uint32 /*i*/)
}
else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
{
- //isAllowUseBattleGroundObject() already called in CanCast()
+ //CanUseBattleGroundObject() already called in CheckCast()
// in battleground check
if(BattleGround *bg = player->GetBattleGround())
{
@@ -2918,93 +3075,39 @@ void Spell::EffectOpenLock(uint32 /*i*/)
return;
}
- if(!lockId) // possible case for GO and maybe for items.
- {
- SendLoot(guid, loottype);
- return;
- }
-
- // Get LockInfo
- LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
+ SkillType skillId = SKILL_NONE;
+ int32 reqSkillValue = 0;
+ int32 skillValue;
- if (!lockInfo)
+ SpellCastResult res = CanOpenLock(effIndex,lockId,skillId,reqSkillValue,skillValue);
+ if(res != SPELL_CAST_OK)
{
- sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
- (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
- SendCastResult(SPELL_FAILED_BAD_TARGETS);
+ SendCastResult(res);
return;
}
- // check key
- for(int i = 0; i < 5; ++i)
- {
- // type==1 This means lockInfo->key[i] is an item
- if(lockInfo->keytype[i]==LOCK_KEY_ITEM && lockInfo->key[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[i])
- {
- SendLoot(guid, loottype);
- return;
- }
- }
-
- uint32 SkillId = 0;
- // Check and skill-up skill
- if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
- SkillId = m_spellInfo->EffectMiscValue[1];
- // pickpocketing spells
- else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
- SkillId = SKILL_LOCKPICKING;
-
- // skill bonus provided by casting spell (mostly item spells)
- uint32 spellSkillBonus = uint32(damage/*m_currentBasePoints[0]+1*/);
-
- uint32 reqSkillValue = lockInfo->requiredminingskill;
-
- if(lockInfo->requiredlockskill) // required pick lock skill applying
- {
- if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
- {
- SendCastResult(SPELL_FAILED_FIZZLE);
- return;
- }
-
- reqSkillValue = lockInfo->requiredlockskill;
- }
- else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
- {
- SendCastResult(SPELL_FAILED_BAD_TARGETS);
- return;
- }
+ SendLoot(guid, LOOT_SKINNING);
- if ( SkillId )
+ // not allow use skill grow at item base open
+ if(!m_CastItem && skillId != SKILL_NONE)
{
- loottype = LOOT_SKINNING;
- if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
- {
- SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
- return;
- }
-
// update skill if really known
- uint32 SkillValue = player->GetPureSkillValue(SkillId);
- if(SkillValue) // non only item base skill
+ if(uint32 pureSkillValue = player->GetPureSkillValue(skillId))
{
if(gameObjTarget)
{
// Allow one skill-up until respawned
if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
- player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
+ player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue) )
gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
}
else if(itemTarget)
{
// Do one skill-up
- uint32 SkillValue = player->GetPureSkillValue(SkillId);
- player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
+ player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
}
}
}
-
- SendLoot(guid, loottype);
}
void Spell::EffectSummonChangeItem(uint32 i)
@@ -3032,10 +3135,10 @@ void Spell::EffectSummonChangeItem(uint32 i)
if( !pNewItem )
return;
- for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
+ for(uint8 j= PERM_ENCHANTMENT_SLOT; j<=TEMP_ENCHANTMENT_SLOT; ++j)
{
- if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
- pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
+ if(m_CastItem->GetEnchantmentId(EnchantmentSlot(j)))
+ pNewItem->SetEnchantment(EnchantmentSlot(j), m_CastItem->GetEnchantmentId(EnchantmentSlot(j)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(j)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(j)));
}
if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
@@ -3128,102 +3231,184 @@ void Spell::EffectProficiency(uint32 /*i*/)
}
}
-void Spell::EffectApplyAreaAura(uint32 i)
+void Spell::EffectSummonType(uint32 i)
{
- if(!unitTarget)
- return;
- if(!unitTarget->isAlive())
+ uint32 entry = m_spellInfo->EffectMiscValue[i];
+ if(!entry)
return;
- AreaAura* Aur = new AreaAura(m_spellInfo, i, &damage, unitTarget, m_caster, m_CastItem);
- unitTarget->AddAura(Aur);
-}
-
-void Spell::EffectSummonType(uint32 i)
-{
- switch(m_spellInfo->EffectMiscValueB[i])
+ SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]);
+ if(!properties)
{
- case SUMMON_TYPE_GUARDIAN:
- EffectSummonGuardian(i);
- break;
- case SUMMON_TYPE_POSESSED:
- case SUMMON_TYPE_POSESSED2:
- case SUMMON_TYPE_POSESSED3:
- EffectSummonPossessed(i);
- break;
- case SUMMON_TYPE_WILD:
- EffectSummonWild(i);
- break;
- case SUMMON_TYPE_DEMON:
- EffectSummonDemon(i);
- break;
- case SUMMON_TYPE_SUMMON:
- EffectSummon(i);
- break;
- case SUMMON_TYPE_CRITTER:
- case SUMMON_TYPE_CRITTER2:
- case SUMMON_TYPE_CRITTER3:
- EffectSummonCritter(i);
- break;
- case SUMMON_TYPE_TOTEM_SLOT1:
- case SUMMON_TYPE_TOTEM_SLOT2:
- case SUMMON_TYPE_TOTEM_SLOT3:
- case SUMMON_TYPE_TOTEM_SLOT4:
- case SUMMON_TYPE_TOTEM:
- EffectSummonTotem(i);
- break;
- case SUMMON_TYPE_UNKNOWN1:
- case SUMMON_TYPE_UNKNOWN3:
- case SUMMON_TYPE_UNKNOWN4:
- case SUMMON_TYPE_UNKNOWN5:
- break;
- default:
- sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
- break;
+ sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
+ return;
}
-}
-void Spell::EffectSummon(uint32 i)
-{
- uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
- if(!pet_entry)
+ if(!m_originalCaster)
return;
- if(!m_originalCaster || m_originalCaster->GetTypeId() != TYPEID_PLAYER)
- {
- EffectSummonWild(i);
- return;
- }
+ int32 duration = GetSpellDuration(m_spellInfo);
+ if(Player* modOwner = m_originalCaster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
- Player *owner = (Player*)m_originalCaster;
+ float x, y, z;
+ GetSummonPosition(i, x, y, z);
- if(owner->GetPetGUID())
- return;
+ /*//totem must be at same Z in case swimming caster and etc.
+ if( fabs( z - m_caster->GetPositionZ() ) > 5 )
+ z = m_caster->GetPositionZ();
- // Summon in dest location
- float x,y,z;
- if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ uint32 level = m_caster->getLevel();
+
+ // level of creature summoned using engineering item based at engineering skill level
+ if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
{
- x = m_targets.m_destX;
- y = m_targets.m_destY;
- z = m_targets.m_destZ;
- }
- else
- m_caster->GetClosePoint(x,y,z,owner->GetObjectSize());
+ ItemPrototype const *proto = m_CastItem->GetProto();
+ if(proto && proto->RequiredSkill == SKILL_ENGINERING)
+ {
+ uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
+ if(skill202)
+ {
+ level = skill202/5;
+ }
+ }
+ }*/
- Pet *spawnCreature = owner->SummonPet(pet_entry, x, y, z, m_caster->GetOrientation(), SUMMON_PET, GetSpellDuration(m_spellInfo));
- if(!spawnCreature)
- return;
+ TempSummon *summon = NULL;
- spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
- spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
- spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+ switch(properties->Category)
+ {
+ default:
+ switch(properties->Type)
+ {
+ case SUMMON_TYPE_PET:
+ case SUMMON_TYPE_GUARDIAN:
+ case SUMMON_TYPE_MINION:
+ SummonGuardian(entry, properties);
+ break;
+ case SUMMON_TYPE_VEHICLE:
+ case SUMMON_TYPE_VEHICLE2:
+ {
+ Vehicle *vehicle = m_caster->SummonVehicle(entry, x, y, z, m_caster->GetOrientation());
+ if(!vehicle)
+ return;
- std::string name = owner->GetName();
- name.append(petTypeSuffix[spawnCreature->getPetType()]);
- spawnCreature->SetName( name );
+ //vehicle->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
+ vehicle->setFaction(m_caster->getFaction());
+ vehicle->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+ break;
+ }
+ case SUMMON_TYPE_TOTEM:
+ {
+ summon = m_caster->GetMap()->SummonCreature(entry, x, y, z, m_caster->GetOrientation(), properties, duration, m_originalCaster);
+ if(!summon || !summon->isTotem())
+ return;
- spawnCreature->SetReactState( REACT_DEFENSIVE );
+ if(damage) // if not spell info, DB values used
+ {
+ summon->SetMaxHealth(damage);
+ summon->SetHealth(damage);
+ }
+
+ //summon->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
+
+ if(m_originalCaster->GetTypeId() == TYPEID_PLAYER
+ && properties->Slot >= SUMMON_SLOT_TOTEM
+ && properties->Slot < MAX_TOTEM_SLOT)
+ {
+ //summon->SendUpdateToPlayer((Player*)m_originalCaster);
+ WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
+ data << uint8(properties->Slot-1);
+ data << uint64(m_originalCaster->GetGUID());
+ data << uint32(duration);
+ data << uint32(m_spellInfo->Id);
+ ((Player*)m_originalCaster)->SendDirectMessage(&data);
+ }
+ break;
+ }
+ case SUMMON_TYPE_MINIPET:
+ {
+ summon = m_caster->GetMap()->SummonCreature(entry, x, y, z, m_caster->GetOrientation(), properties, duration, m_originalCaster);
+ if(!summon || !summon->HasSummonMask(SUMMON_MASK_MINION))
+ return;
+
+ //summon->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as summon...
+ summon->SelectLevel(summon->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp
+ summon->SetUInt32Value(UNIT_NPC_FLAGS, summon->GetCreatureInfo()->npcflag);
+
+ summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+
+ summon->AI()->EnterEvadeMode();
+
+ std::string name = m_originalCaster->GetName();
+ name.append(petTypeSuffix[3]);
+ summon->SetName( name );
+ break;
+ }
+ default:
+ {
+ float radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+
+ int32 amount = damage > 0 ? damage : 1;
+
+ for(int32 count = 0; count < amount; ++count)
+ {
+ float px, py, pz;
+ GetSummonPosition(i, px, py, pz, radius, count);
+
+ TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
+
+ m_originalCaster->SummonCreature(entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
+ }
+ break;
+ }
+ }//switch
+ break;
+ case SUMMON_CATEGORY_PET:
+ SummonGuardian(entry, properties);
+ break;
+ case SUMMON_CATEGORY_POSSESSED:
+ {
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ float x, y, z;
+ m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
+
+ int32 duration = GetSpellDuration(m_spellInfo);
+
+ Pet* pet = ((Player*)m_caster)->SummonPet(entry, x, y, z, m_caster->GetOrientation(), POSSESSED_PET, duration);
+ if(!pet)
+ return;
+
+ pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+ break;
+ }
+ case SUMMON_CATEGORY_VEHICLE:
+ {
+ float x, y, z;
+ m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
+ Vehicle *vehicle = m_caster->SummonVehicle(entry, x, y, z, m_caster->GetOrientation());
+ if(!vehicle)
+ return;
+
+ vehicle->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
+ vehicle->setFaction(m_caster->getFaction());
+ vehicle->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+
+ if(damage)
+ {
+ m_caster->CastSpell(vehicle, damage, true);
+ m_caster->EnterVehicle(vehicle);
+ }
+ break;
+ }
+ }
+
+ if(summon)
+ {
+ summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+ }
}
void Spell::EffectLearnSpell(uint32 i)
@@ -3241,8 +3426,8 @@ void Spell::EffectLearnSpell(uint32 i)
Player *player = (Player*)unitTarget;
- uint32 spellToLearn = (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) ? damage : m_spellInfo->EffectTriggerSpell[i];
- player->learnSpell(spellToLearn);
+ uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
+ player->learnSpell(spellToLearn,false);
sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
}
@@ -3252,8 +3437,7 @@ void Spell::EffectDispel(uint32 i)
if(!unitTarget)
return;
- // Fill possible dispel list
- std::vector <Aura *> dispel_list;
+ std::list < Aura * > dispel_list;
// Create dispel mask by dispel type
uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
@@ -3262,7 +3446,7 @@ void Spell::EffectDispel(uint32 i)
for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
Aura *aur = (*itr).second;
- if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
+ if (aur && ((1<<aur->GetSpellProto()->Dispel) & dispelMask))
{
if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
{
@@ -3277,80 +3461,67 @@ void Spell::EffectDispel(uint32 i)
if(positive == unitTarget->IsFriendlyTo(m_caster))
continue;
}
- // Add every aura stack to dispel list
- for(uint32 stack_amount = 0; stack_amount < aur->GetStackAmount(); ++stack_amount)
+ for (uint8 i = aur->GetStackAmount();i!=0;--i)
dispel_list.push_back(aur);
}
}
// Ok if exist some buffs for dispel try dispel it
- if (!dispel_list.empty())
+ if (uint32 list_size = dispel_list.size())
{
- std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
- std::list < uint32 > fail_list; // spell_id
- int32 list_size = dispel_list.size();
+ uint32 failCount = 0;
+ std::list < Aura * > success_list;
+ WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4);
// dispel N = damage buffs (or while exist buffs for dispel)
- for (int32 count=0; count < damage && list_size > 0; ++count)
+ for (int32 count=0; count < damage && list_size > 0; ++count, list_size = dispel_list.size())
{
// Random select buff for dispel
- Aura *aur = dispel_list[urand(0, list_size-1)];
-
- SpellEntry const* spellInfo = aur->GetSpellProto();
- // Base dispel chance
- // TODO: possible chance depend from spell level??
- int32 miss_chance = 0;
- // Apply dispel mod from aura caster
- if (Unit *caster = aur->GetCaster())
+ std::list < Aura * > ::iterator itr = dispel_list.begin();
+ for (uint32 i=urand(0, list_size-1);i>0;--i)
+ itr++;
+
+ if (GetDispelChance((*itr)->GetCaster(), (*itr)->GetId()))
{
- if ( Player* modOwner = caster->GetSpellModOwner() )
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
+ success_list.push_back(*itr);
+ dispel_list.erase(itr);
}
- // Try dispel
- if (roll_chance_i(miss_chance))
- fail_list.push_back(aur->GetId());
else
- success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
- // Remove buff from list for prevent doubles
- for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
{
- Aura *dispelled = *j;
- if (dispelled->GetId() == aur->GetId() && dispelled->GetCasterGUID() == aur->GetCasterGUID())
+ if (!failCount)
{
- j = dispel_list.erase(j);
- --list_size;
- break;
+ // Failed to dispell
+ dataFail << uint64(m_caster->GetGUID()); // Caster GUID
+ dataFail << uint64(unitTarget->GetGUID()); // Victim GUID
+ dataFail << uint32(m_spellInfo->Id); // dispel spell id
}
- else
- ++j;
+ failCount++;
+ dataFail << uint32((*itr)->GetId()); // Spell Id
}
}
- // Send success log and really remove auras
- if (!success_list.empty())
+ if (failCount)
{
- int32 count = success_list.size();
- WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
- data.append(unitTarget->GetPackGUID()); // Victim GUID
- data.append(m_caster->GetPackGUID()); // Caster GUID
- data << uint32(m_spellInfo->Id); // dispel spell id
- data << uint8(0); // not used
- data << uint32(count); // count
- for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
+ m_caster->SendMessageToSet(&dataFail, true);
+ }
+ if (success_list.size())
+ {
+ WorldPacket dataSuccess(SMSG_SPELLDISPELLOG, 8+8+4+1+4+damage*5);
+ // Send packet header
+ dataSuccess.append(unitTarget->GetPackGUID()); // Victim GUID
+ dataSuccess.append(m_caster->GetPackGUID()); // Caster GUID
+ dataSuccess << uint32(m_spellInfo->Id); // dispel spell id
+ dataSuccess << uint8(0); // not used
+ dataSuccess << uint32(success_list.size()); // count
+ for (std::list < Aura * > ::iterator itr = success_list.begin();itr!=success_list.end();++itr)
{
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
- data << uint32(spellInfo->Id); // Spell Id
- data << uint8(0); // 0 - dispelled !=0 cleansed
- if(spellInfo->StackAmount!= 0)
- {
- //Why are Aura's Removed by EffIndex? Auras should be removed as a whole.....
- unitTarget->RemoveSingleAuraFromStackByDispel(spellInfo->Id);
- }
- else
- unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
- }
- m_caster->SendMessageToSet(&data, true);
+ // Send dispelled spell info
+ dataSuccess << uint32((*itr)->GetId()); // Spell Id
+ dataSuccess << uint8(0); // 0 - dispelled !=0 cleansed
+ unitTarget->RemoveAurasDueToSpellByDispel((*itr)->GetId(), (*itr)->GetCasterGUID(), m_caster);
+ }
+ m_caster->SendMessageToSet(&dataSuccess, true);
// On succes dispel
// Devour Magic
- if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC)
{
uint32 heal_spell = 0;
switch (m_spellInfo->Id)
@@ -3361,6 +3532,7 @@ void Spell::EffectDispel(uint32 i)
case 19736: heal_spell = 19735; break;
case 27276: heal_spell = 27278; break;
case 27277: heal_spell = 27279; break;
+ case 48011: heal_spell = 48010; break;
default:
sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
break;
@@ -3369,18 +3541,6 @@ void Spell::EffectDispel(uint32 i)
m_caster->CastSpell(m_caster, heal_spell, true);
}
}
- // Send fail log to client
- if (!fail_list.empty())
- {
- // Failed to dispell
- WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
- data << uint64(m_caster->GetGUID()); // Caster GUID
- data << uint64(unitTarget->GetGUID()); // Victim GUID
- data << uint32(m_spellInfo->Id); // dispel spell id
- for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
- data << uint32(*j); // Spell Id
- m_caster->SendMessageToSet(&data, true);
- }
}
}
@@ -3422,7 +3582,7 @@ void Spell::EffectDistract(uint32 /*i*/)
// Set creature Distracted, Stop it, And turn it
unitTarget->SetOrientation(angle);
unitTarget->StopMoving();
- unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
+ unitTarget->GetMotionMaster()->MoveDistract(damage*IN_MILISECONDS);
}
}
@@ -3450,8 +3610,7 @@ void Spell::EffectPickPocket(uint32 /*i*/)
{
// Reveal action + get attack
m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
- if (((Creature*)unitTarget)->IsAIEnabled)
- ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
+ m_caster->CombatStart(unitTarget);
}
}
}
@@ -3461,7 +3620,7 @@ void Spell::EffectAddFarsight(uint32 i)
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
int32 duration = GetSpellDuration(m_spellInfo);
DynamicObject* dynObj = new DynamicObject;
if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, 4, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius))
@@ -3477,189 +3636,8 @@ void Spell::EffectAddFarsight(uint32 i)
dynObj->GetMap()->Add(dynObj); //grid will also be loaded
// Need to update visibility of object for client to accept farsight guid
+ ((Player*)m_caster)->SetViewpoint(dynObj, true);
((Player*)m_caster)->UpdateVisibilityOf(dynObj);
- ((Player*)m_caster)->SetFarsightTarget(dynObj);
-}
-
-void Spell::EffectSummonWild(uint32 i)
-{
- uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
- if(!creature_entry)
- return;
-
- uint32 level = m_caster->getLevel();
-
- // level of creature summoned using engineering item based at engineering skill level
- if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
- {
- ItemPrototype const *proto = m_CastItem->GetProto();
- if(proto && proto->RequiredSkill == SKILL_ENGINERING)
- {
- uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
- if(skill202)
- {
- level = skill202/5;
- }
- }
- }
-
- // select center of summon position
- float center_x = m_targets.m_destX;
- float center_y = m_targets.m_destY;
- float center_z = m_targets.m_destZ;
-
- float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
-
- int32 amount = damage > 0 ? damage : 1;
-
- for(int32 count = 0; count < amount; ++count)
- {
- float px, py, pz;
- // If dest location if present
- if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
- {
- // Summon 1 unit in dest location
- if (count == 0)
- {
- px = m_targets.m_destX;
- py = m_targets.m_destY;
- pz = m_targets.m_destZ;
- }
- // Summon in random point all other units if location present
- else
- m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
- }
- // Summon if dest location not present near caster
- else
- m_caster->GetClosePoint(px,py,pz,3.0f);
-
- int32 duration = GetSpellDuration(m_spellInfo);
-
- TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
-
- if(m_originalCaster)
- m_originalCaster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
- else
- m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
- }
-}
-
-void Spell::EffectSummonGuardian(uint32 i)
-{
- uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
- if(!pet_entry)
- return;
-
- // Jewelery statue case (totem like)
- if(m_spellInfo->SpellIconID==2056)
- {
- EffectSummonTotem(i);
- return;
- }
-
- Player *caster = NULL;
- if(m_originalCaster)
- {
- if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
- caster = (Player*)m_originalCaster;
- else if(((Creature*)m_originalCaster)->isTotem())
- caster = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself();
- }
-
- if(!caster)
- {
- EffectSummonWild(i);
- return;
- }
-
- // set timer for unsummon
- int32 duration = GetSpellDuration(m_spellInfo);
-
- // Search old Guardian only for players (if casted spell not have duration or cooldown)
- // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
- // so this code hack in fact
- if(duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0)
- if(caster->HasGuardianWithEntry(pet_entry))
- return; // find old guardian, ignore summon
-
- // in another case summon new
- uint32 level = caster->getLevel();
-
- // level of pet summoned using engineering item based at engineering skill level
- if(m_CastItem)
- {
- ItemPrototype const *proto = m_CastItem->GetProto();
- if(proto && proto->RequiredSkill == SKILL_ENGINERING)
- {
- uint16 skill202 = caster->GetSkillValue(SKILL_ENGINERING);
- if(skill202)
- {
- level = skill202/5;
- }
- }
- }
-
- // select center of summon position
- float center_x = m_targets.m_destX;
- float center_y = m_targets.m_destY;
- float center_z = m_targets.m_destZ;
-
- float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
-
- int32 amount = damage > 0 ? damage : 1;
-
- for(int32 count = 0; count < amount; ++count)
- {
- float px, py, pz;
- // If dest location if present
- if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
- {
- // Summon 1 unit in dest location
- if (count == 0)
- {
- px = m_targets.m_destX;
- py = m_targets.m_destY;
- pz = m_targets.m_destZ;
- }
- // Summon in random point all other units if location present
- else
- m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
- }
- // Summon if dest location not present near caster
- else
- m_caster->GetClosePoint(px,py,pz,m_caster->GetObjectSize());
-
- Pet *spawnCreature = caster->SummonPet(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(), GUARDIAN_PET, duration);
- if(!spawnCreature)
- return;
-
- spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
- spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
- }
-}
-
-void Spell::EffectSummonPossessed(uint32 i)
-{
- uint32 entry = m_spellInfo->EffectMiscValue[i];
- if(!entry)
- return;
-
- if(m_caster->GetTypeId() != TYPEID_PLAYER)
- return;
-
- uint32 level = m_caster->getLevel();
-
- float x, y, z;
- m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
-
- int32 duration = GetSpellDuration(m_spellInfo);
-
- Pet* pet = ((Player*)m_caster)->SummonPet(entry, x, y, z, m_caster->GetOrientation(), POSSESSED_PET, duration);
- if(!pet)
- return;
-
- pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
- pet->SetCharmedOrPossessedBy(m_caster, true);
}
void Spell::EffectTeleUnitsFaceCaster(uint32 i)
@@ -3670,16 +3648,12 @@ void Spell::EffectTeleUnitsFaceCaster(uint32 i)
if(unitTarget->isInFlight())
return;
- uint32 mapid = m_caster->GetMapId();
- float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ float dis = m_caster->GetSpellRadiusForTarget(unitTarget, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
float fx,fy,fz;
m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
- if(unitTarget->GetTypeId() == TYPEID_PLAYER)
- ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
- else
- m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
+ unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget==m_caster);
}
void Spell::EffectLearnSkill(uint32 i)
@@ -3700,13 +3674,27 @@ void Spell::EffectAddHonor(uint32 /*i*/)
if(unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
- sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
-
- // TODO: find formula for honor reward based on player's level!
+ // not scale value for item based reward (/10 value expected)
+ if(m_CastItem)
+ {
+ ((Player*)unitTarget)->RewardHonor(NULL, 1, damage/10);
+ sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),((Player*)unitTarget)->GetGUIDLow());
+ return;
+ }
- // now fixed only for level 70 players:
- if (((Player*)unitTarget)->getLevel() == 70)
+ // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80
+ if( damage <= 50)
+ {
+ uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage);
+ ((Player*)unitTarget)->RewardHonor(NULL, 1, honor_reward);
+ sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow());
+ }
+ else
+ {
+ //maybe we have correct honor_gain in damage already
((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
+ sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
+ }
}
void Spell::EffectTradeSkill(uint32 /*i*/)
@@ -3718,7 +3706,7 @@ void Spell::EffectTradeSkill(uint32 /*i*/)
// ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
}
-void Spell::EffectEnchantItemPerm(uint32 i)
+void Spell::EffectEnchantItemPerm(uint32 effect_idx)
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return;
@@ -3727,11 +3715,27 @@ void Spell::EffectEnchantItemPerm(uint32 i)
Player* p_caster = (Player*)m_caster;
- p_caster->UpdateCraftSkill(m_spellInfo->Id);
-
- if (m_spellInfo->EffectMiscValue[i])
+ // Handle vellums
+ if (itemTarget->IsWeaponVellum() || itemTarget->IsArmorVellum())
{
- uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
+ // destroy one vellum from stack
+ uint32 count=1;
+ p_caster->DestroyItemCount(itemTarget,count,true);
+ unitTarget=p_caster;
+ // and add a scroll
+ DoCreateItem(effect_idx,m_spellInfo->EffectItemType[effect_idx]);
+ itemTarget=NULL;
+ m_targets.setItemTarget(NULL);
+ }
+ else
+ {
+ // do not increase skill if vellum used
+ if (!(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAGS_TRIGGERED_CAST))
+ p_caster->UpdateCraftSkill(m_spellInfo->Id);
+
+ uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
+ if (!enchant_id)
+ return;
SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
if(!pEnchant)
@@ -3760,6 +3764,64 @@ void Spell::EffectEnchantItemPerm(uint32 i)
}
}
+void Spell::EffectEnchantItemPrismatic(uint32 effect_idx)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+ if (!itemTarget)
+ return;
+
+ Player* p_caster = (Player*)m_caster;
+
+ uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
+ if (!enchant_id)
+ return;
+
+ SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
+ if(!pEnchant)
+ return;
+
+ // support only enchantings with add socket in this slot
+ {
+ bool add_socket = false;
+ for(int i = 0; i < 3; ++i)
+ {
+ if(pEnchant->type[i]==ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
+ {
+ add_socket = true;
+ break;
+ }
+ }
+ if(!add_socket)
+ {
+ sLog.outError("Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not suppoted yet.",
+ m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
+ return;
+ }
+ }
+
+ // item can be in trade slot and have owner diff. from caster
+ Player* item_owner = itemTarget->GetOwner();
+ if(!item_owner)
+ return;
+
+ if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
+ {
+ sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
+ p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
+ itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
+ item_owner->GetName(),item_owner->GetSession()->GetAccountId());
+ }
+
+ // remove old enchanting before applying new if equipped
+ item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false);
+
+ itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0);
+
+ // add new enchanting if equipped
+ item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true);
+}
+
void Spell::EffectEnchantItemTmp(uint32 i)
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
@@ -3852,13 +3914,13 @@ void Spell::EffectEnchantItemTmp(uint32 i)
else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
duration = 1800; // 30 mins
// other cases with this SpellVisual already selected
- else if(m_spellInfo->SpellVisual==215)
+ else if(m_spellInfo->SpellVisual[0]==215)
duration = 1800; // 30 mins
// some fishing pole bonuses
- else if(m_spellInfo->SpellVisual==563)
+ else if(m_spellInfo->SpellVisual[0]==563)
duration = 600; // 10 mins
// shaman rockbiter enchantments
- else if(m_spellInfo->SpellVisual==0)
+ else if(m_spellInfo->SpellVisual[0]==0)
duration = 1800; // 30 mins
else if(m_spellInfo->Id==29702)
duration = 300; // 5 mins
@@ -3921,17 +3983,19 @@ void Spell::EffectTameCreature(uint32 /*i*/)
creatureTarget->RemoveCorpse();
creatureTarget->SetHealth(0); // just for nice GM-mode view
+ uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
+
// prepare visual effect for levelup
- pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1);
+ pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
// add to world
pet->GetMap()->Add((Creature*)pet);
// visual effect for levelup
- pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel());
+ pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
// caster have pet now
- m_caster->SetPet(pet);
+ m_caster->SetMinion(pet, true);
if(m_caster->GetTypeId() == TYPEID_PLAYER)
{
@@ -3951,14 +4015,16 @@ void Spell::EffectSummonPet(uint32 i)
owner = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself();
}
+ uint32 petentry = m_spellInfo->EffectMiscValue[i];
+
if(!owner)
{
- EffectSummonWild(i);
+ SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(67);
+ if(properties)
+ SummonGuardian(petentry, properties);
return;
}
- uint32 petentry = m_spellInfo->EffectMiscValue[i];
-
Pet *OldSummon = owner->GetPet();
// if pet requested type already exist
@@ -3997,7 +4063,7 @@ void Spell::EffectSummonPet(uint32 i)
Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0);
if(!pet)
return;
-
+
if(m_caster->GetTypeId() == TYPEID_UNIT)
{
if ( ((Creature*)m_caster)->isTotem() )
@@ -4008,10 +4074,6 @@ void Spell::EffectSummonPet(uint32 i)
pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
- // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
- pet->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
- pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
-
// generate new name for summon pet
std::string new_name=objmgr.GeneratePetName(petentry);
if(!new_name.empty())
@@ -4035,7 +4097,6 @@ void Spell::EffectLearnPetSpell(uint32 i)
if(!learn_spellproto)
return;
- pet->SetTP(pet->m_TrainingPoints - pet->GetTPForSpell(learn_spellproto->Id));
pet->learnSpell(learn_spellproto->Id);
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
@@ -4044,6 +4105,9 @@ void Spell::EffectLearnPetSpell(uint32 i)
void Spell::EffectTaunt(uint32 /*i*/)
{
+ if (!unitTarget)
+ return;
+
// this effect use before aura Taunt apply for prevent taunt already attacking target
// for spell as marked "non effective at already attacking target"
if(!unitTarget || !unitTarget->CanHaveThreatList()
@@ -4062,7 +4126,7 @@ void Spell::EffectTaunt(uint32 /*i*/)
unitTarget->getThreatManager().addThreat(m_caster, itsThreat - myThreat);
}
- if(((Creature*)unitTarget)->IsAIEnabled)
+ if(((Creature*)unitTarget)->IsAIEnabled && !((Creature*)unitTarget)->HasReactState(REACT_PASSIVE))
((Creature*)unitTarget)->AI()->AttackStart(m_caster);
}
@@ -4095,7 +4159,6 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
}
// some spell specific modifiers
- //float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
int32 fixed_bonus = 0;
int32 spell_bonus = 0; // bonus specific for spell
@@ -4105,23 +4168,18 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
case SPELLFAMILY_WARRIOR:
{
// Devastate bonus and sunder armor refresh
- if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508)
+ if(m_spellInfo->SpellFamilyFlags[1] & 0x40)
{
+ if (m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
+ SpellEntry const *spellInfo = NULL;
uint32 stack = 0;
- Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
- for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
+ if (AuraEffect * aur = unitTarget->GetAura(SPELL_AURA_MOD_RESISTANCE,SPELLFAMILY_WARRIOR,SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR, 0, 0, m_caster->GetGUID()))
{
- SpellEntry const *proto = (*itr)->GetSpellProto();
- if(proto->SpellFamilyName == SPELLFAMILY_WARRIOR
- && proto->SpellFamilyFlags == SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR)
- {
- int32 duration = GetSpellDuration(proto);
- (*itr)->SetAuraDuration(duration);
- (*itr)->UpdateAuraDuration();
- stack = (*itr)->GetStackAmount();
- break;
- }
+ aur->GetParentAura()->RefreshAura();
+ spellInfo = aur->GetSpellProto();
+ stack = aur->GetParentAura()->GetStackAmount();
}
for(int j = 0; j < 3; j++)
@@ -4133,7 +4191,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
}
}
- if(stack < 5)
+ if(!spellInfo)
{
// get highest rank of the Sunder Armor spell
const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
@@ -4143,68 +4201,99 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
continue;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
- if (!spellInfo)
+ SpellEntry const *spellProto = sSpellStore.LookupEntry(itr->first);
+ if (!spellProto)
continue;
- if (spellInfo->SpellFamilyFlags == SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR
- && spellInfo->Id != m_spellInfo->Id
- && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR)
+ if (spellProto->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR
+ && spellProto->Id != m_spellInfo->Id
+ && spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR)
{
- m_caster->CastSpell(unitTarget, spellInfo, true);
+ spellInfo = spellProto;
break;
}
}
}
+ if (!spellInfo)
+ break;
+ m_caster->CastSpell(unitTarget, spellInfo, true);
+ if (stack)
+ spell_bonus += stack * CalculateDamage(2, unitTarget);
}
break;
}
case SPELLFAMILY_ROGUE:
{
// Hemorrhage
- if(m_spellInfo->SpellFamilyFlags & 0x2000000)
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x2000000)
{
if(m_caster->GetTypeId()==TYPEID_PLAYER)
((Player*)m_caster)->AddComboPoints(unitTarget, 1);
}
+ // Fan of Knives
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x40000)
+ {
+ // 50% more damage with daggers
+ if (Item* item = ((Player*)m_caster)->GetWeaponForAttack(m_attackType))
+ if (item->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
+ totalDamagePercentMod *= 1.5f;
+ }
// Mutilate (for each hand)
- else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
+ else if(m_spellInfo->SpellFamilyFlags[1] & 0x6)
{
- Unit::AuraMap const& auras = unitTarget->GetAuras();
- for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
+ bool found = false;
+ // fast check
+ if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON, m_spellInfo, m_caster))
+ found = true;
+ // full aura scan
+ else
{
- if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
+ Unit::AuraMap const& auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
{
- totalDamagePercentMod *= 1.5f; // 150% if poisoned
- break;
+ if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
+ {
+ found = true;
+ break;
+ }
}
}
+
+ if(found)
+ totalDamagePercentMod *= 1.2f; // 120% if poisoned
}
break;
}
case SPELLFAMILY_PALADIN:
{
// Seal of Command - receive benefit from Spell Damage and Healing
- if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
+ if(m_spellInfo->SpellFamilyFlags[0] & 0x2000000)
{
- spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
+ spell_bonus += int32(0.23f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
}
+
+ // Seal of Command Unleashed
+ else if(m_spellInfo->Id==20467)
+ {
+ spell_bonus += int32(0.16f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
+ spell_bonus += int32(0.25f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
+ }
break;
}
case SPELLFAMILY_SHAMAN:
{
// Skyshatter Harness item set bonus
// Stormstrike
- if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
+ if(m_spellInfo->SpellFamilyFlags[1] & 0x0010)
{
- Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
+ Unit::AuraEffectList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraEffectList::const_iterator citr = m_OverrideClassScript.begin(); citr != m_OverrideClassScript.end(); ++citr)
{
// Stormstrike AP Buff
- if ( (*i)->GetModifier()->m_miscvalue == 5634 )
+ if ( (*citr)->GetMiscValue() == 5634 )
{
- m_caster->CastSpell(m_caster,38430,true,NULL,*i);
+ m_caster->CastSpell(m_caster,38430,true,NULL,*citr);
break;
}
}
@@ -4214,7 +4303,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
case SPELLFAMILY_DRUID:
{
// Mangle (Cat): CP
- if(m_spellInfo->SpellFamilyFlags==0x0000040000000000LL)
+ if(m_spellInfo->SpellFamilyFlags.IsEqual(0,0x00000400))
{
if(m_caster->GetTypeId()==TYPEID_PLAYER)
((Player*)m_caster)->AddComboPoints(unitTarget,1);
@@ -4239,6 +4328,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
break;
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
+ break;
default:
break; // not weapon damage effect, just skip
}
@@ -4299,33 +4389,6 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
// Add melee damage bonuses (also check for negative)
m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
m_damage+= eff_damage;
-
- // take ammo
- if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
- {
- Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
-
- // wands don't have ammo
- if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
- return;
-
- if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
- {
- if(pItem->GetMaxStackCount()==1)
- {
- // decrease durability for non-stackable throw weapon
- ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
- }
- else
- {
- // decrease items amount for stackable throw weapon
- uint32 count = 1;
- ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
- }
- }
- else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
- ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
- }
}
void Spell::EffectThreat(uint32 /*i*/)
@@ -4346,10 +4409,9 @@ void Spell::EffectHealMaxHealth(uint32 /*i*/)
if(!unitTarget->isAlive())
return;
- uint32 addhealth = unitTarget->GetMaxHealth() - unitTarget->GetHealth();
- unitTarget->SetHealth(unitTarget->GetMaxHealth());
+ int32 addhealth = unitTarget->GetMaxHealth() - unitTarget->GetHealth();
if(m_originalCaster)
- m_originalCaster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
+ m_originalCaster->DealHeal(unitTarget, addhealth, m_spellInfo);
}
void Spell::EffectInterruptCast(uint32 i)
@@ -4370,7 +4432,7 @@ void Spell::EffectInterruptCast(uint32 i)
{
if(m_originalCaster)
{
- int32 duration = m_originalCaster->CalculateSpellDuration(m_spellInfo, i, unitTarget);
+ int32 duration = m_originalCaster->ModSpellDuration(m_spellInfo, unitTarget, m_originalCaster->CalcSpellDuration(m_spellInfo), false);
unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), duration/*GetSpellDuration(m_spellInfo)*/);
}
unitTarget->InterruptSpell(i,false);
@@ -4402,14 +4464,14 @@ void Spell::EffectSummonObjectWild(uint32 i)
Map *map = target->GetMap();
if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
- x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
{
delete pGameObj;
return;
}
int32 duration = GetSpellDuration(m_spellInfo);
- pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
@@ -4450,9 +4512,9 @@ void Spell::EffectSummonObjectWild(uint32 i)
{
GameObject* linkedGO = new GameObject;
if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
- x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
{
- linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
linkedGO->SetSpellId(m_spellInfo->Id);
m_caster->AddGameObject(linkedGO);
@@ -4471,450 +4533,741 @@ void Spell::EffectScriptEffect(uint32 effIndex)
{
// TODO: we must implement hunter pet summon at login there (spell 6962)
- // by spell id
- switch(m_spellInfo->Id)
+ switch(m_spellInfo->SpellFamilyName)
{
- // PX-238 Winter Wondervolt TRAP
- case 26275:
+ case SPELLFAMILY_GENERIC:
{
- if( unitTarget->HasAura(26272,0)
- || unitTarget->HasAura(26157,0)
- || unitTarget->HasAura(26273,0)
- || unitTarget->HasAura(26274,0))
- return;
+ switch(m_spellInfo->Id)
+ {
+ // PX-238 Winter Wondervolt TRAP
+ case 26275:
+ {
+ uint32 spells[4] = { 26272, 26157, 26273, 26274 };
- uint32 iTmpSpellId;
+ // check presence
+ for(int j = 0; j < 4; ++j)
+ if(unitTarget->HasAuraEffect(spells[j],0))
+ return;
- switch(urand(0,3))
- {
- case 0:
- iTmpSpellId = 26272;
+ // select spell
+ uint32 iTmpSpellId = spells[urand(0,3)];
+
+ // cast
+ unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
+ return;
+ }
+ // Bending Shinbone
+ case 8856:
+ {
+ if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
+
+ uint32 spell_id = 0;
+ switch(urand(1,5))
+ {
+ case 1: spell_id = 8854; break;
+ default: spell_id = 8855; break;
+ }
+
+ m_caster->CastSpell(m_caster,spell_id,true,NULL);
+ return;
+ }
+ // Brittle Armor - need remove one 24575 Brittle Armor aura
+ case 24590:
+ unitTarget->RemoveAuraFromStack(24575);
+ return;
+ // Mercurial Shield - need remove one 26464 Mercurial Shield aura
+ case 26465:
+ unitTarget->RemoveAuraFromStack(26464);
+ return;
+ // Orb teleport spells
+ case 25140:
+ case 25143:
+ case 25650:
+ case 25652:
+ case 29128:
+ case 29129:
+ case 35376:
+ case 35727:
+ {
+ if(!unitTarget)
+ return;
+
+ uint32 spellid;
+ switch(m_spellInfo->Id)
+ {
+ case 25140: spellid = 32571; break;
+ case 25143: spellid = 32572; break;
+ case 25650: spellid = 30140; break;
+ case 25652: spellid = 30141; break;
+ case 29128: spellid = 32568; break;
+ case 29129: spellid = 32569; break;
+ case 35376: spellid = 25649; break;
+ case 35727: spellid = 35730; break;
+ default:
+ return;
+ }
+
+ unitTarget->CastSpell(unitTarget,spellid,false);
+ return;
+ }
+ // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
+ case 22539:
+ case 22972:
+ case 22975:
+ case 22976:
+ case 22977:
+ case 22978:
+ case 22979:
+ case 22980:
+ case 22981:
+ case 22982:
+ case 22983:
+ case 22984:
+ case 22985:
+ {
+ if(!unitTarget || !unitTarget->isAlive())
+ return;
+
+ // Onyxia Scale Cloak
+ if(unitTarget->GetDummyAura(22683))
+ return;
+
+ // Shadow Flame
+ m_caster->CastSpell(unitTarget, 22682, true);
+ return;
+ }
+ // Summon Black Qiraji Battle Tank
+ case 26656:
+ {
+ if(!unitTarget)
+ return;
+
+ // Prevent stacking of mounts
+ unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
+
+ // Two separate mounts depending on area id (allows use both in and out of specific instance)
+ if (unitTarget->GetAreaId() == 3428)
+ unitTarget->CastSpell(unitTarget, 25863, false);
+ else
+ unitTarget->CastSpell(unitTarget, 26655, false);
+ return;
+ }
+ // Piccolo of the Flaming Fire
+ case 17512:
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+ unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
+ return;
+ }
+ // Escape artist
+ case 20589:
+ {
+ if(!unitTarget)
+ return;
+ // It is said that removing effects by script should include dispel resist mods
+ unitTarget->RemoveAurasByTypeWithDispel(SPELL_AURA_MOD_ROOT, this);
+ unitTarget->RemoveAurasByTypeWithDispel(SPELL_AURA_MOD_DECREASE_SPEED, this);
+ return;
+ }
+ // Decimate
+ case 28374:
+ case 54426:
+ if(unitTarget)
+ {
+ int32 damage = (int32)unitTarget->GetHealth() - (int32)unitTarget->GetMaxHealth() * 0.05f;
+ if(damage > 0)
+ m_caster->CastCustomSpell(28375, SPELLVALUE_BASE_POINT0, damage, unitTarget);
+ }
+ return;
+ // Mirren's Drinking Hat
+ case 29830:
+ {
+ uint32 item = 0;
+ switch ( urand(1,6) )
+ {
+ case 1:case 2:case 3:
+ item = 23584;break; // Loch Modan Lager
+ case 4:case 5:
+ item = 23585;break; // Stouthammer Lite
+ case 6:
+ item = 23586;break; // Aerie Peak Pale Ale
+ }
+ if (item)
+ DoCreateItem(effIndex,item);
break;
- case 1:
- iTmpSpellId = 26157;
+ }
+ // Improved Sprint
+ case 30918:
+ {
+ // Removes snares and roots.
+ uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
+ Unit::AuraMap& Auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end();)
+ {
+ Aura *aur = iter->second;
+ if (!aur->IsPositive()) //only remove negative spells
+ {
+ // check for mechanic mask
+ if(GetAllSpellMechanicMask(aur->GetSpellProto()) & mechanic_mask)
+ {
+ unitTarget->RemoveAura(iter);
+ }
+ else
+ iter++;
+ }
+ else
+ iter++;
+ }
break;
- case 2:
- iTmpSpellId = 26273;
+ }
+ /*// Flame Crash
+ case 41126:
+ {
+ if(!unitTarget)
+ return;
+
+ unitTarget->CastSpell(unitTarget, 41131, true);
break;
- case 3:
- iTmpSpellId = 26274;
+ }*/
+ // Draw Soul
+ case 40904:
+ {
+ if(!unitTarget)
+ return;
+
+ unitTarget->CastSpell(m_caster, 40903, true);
break;
- }
+ }
+ case 48025: // Headless Horseman's Mount
+ {
+ if(!unitTarget)
+ return;
- unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
+ switch(((Player*)unitTarget)->GetBaseSkillValue(762))
+ {
+ case 75: unitTarget->CastSpell(unitTarget, 51621, true); break;;
+ case 150: unitTarget->CastSpell(unitTarget, 48024, true); break;
+ case 225: unitTarget->CastSpell(unitTarget, 51617, true); break;
+ case 300: unitTarget->CastSpell(unitTarget, 48023, true); break;
+ default: break;
+ }
+ break;
+ }
+ case 47977: // Magic Broom
+ {
+ if(!unitTarget)
+ return;
- return;
- }
+ if(unitTarget)
+ {
+ switch(((Player*)unitTarget)->GetBaseSkillValue(762))
+ {
+ case 75: unitTarget->CastSpell(unitTarget, 42680, true); break;;
+ case 150: case 225: case 300: unitTarget->CastSpell(unitTarget, 42683, true); break;
+ default: break;
+ }
+ }
+ break;
+ }
+ case 41931:
+ {
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
- // Bending Shinbone
- case 8856:
- {
- if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
- return;
+ int bag=19;
+ int slot=0;
+ Item* item = NULL;
- uint32 spell_id = 0;
- switch(urand(1,5))
- {
- case 1: spell_id = 8854; break;
- default: spell_id = 8855; break;
- }
+ while (bag < 256)
+ {
+ item = ((Player*)m_caster)->GetItemByPos(bag,slot);
+ if (item && item->GetEntry() == 38587) break;
+ slot++;
+ if (slot == 39)
+ {
+ slot = 0;
+ bag++;
+ }
+ }
+ if (bag < 256)
+ {
+ if (((Player*)m_caster)->GetItemByPos(bag,slot)->GetCount() == 1) ((Player*)m_caster)->RemoveItem(bag,slot,true);
+ else ((Player*)m_caster)->GetItemByPos(bag,slot)->SetCount(((Player*)m_caster)->GetItemByPos(bag,slot)->GetCount()-1);
+ // Spell 42518 (Braufest - Gratisprobe des Braufest herstellen)
+ m_caster->CastSpell(m_caster,42518,true);
+ return;
+ }
+ break;
+ }
+ // Force Cast - Portal Effect: Sunwell Isle
+ case 44876:
+ {
+ if(!unitTarget)
+ return;
- m_caster->CastSpell(m_caster,spell_id,true,NULL);
- return;
- }
+ unitTarget->CastSpell(unitTarget, 44870, true);
+ break;
+ }
+ // spell of Brutallus - Stomp
+ case 45185:
+ {
+ if(!unitTarget)
+ return;
- // Healthstone creating spells
- case 6201:
- case 6202:
- case 5699:
- case 11729:
- case 11730:
- case 27230:
- {
- uint32 itemtype;
- uint32 rank = 0;
- Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
- {
- if((*i)->GetId() == 18692)
+ if(unitTarget->HasAura(46394)) // spell of Brutallus - Burn
+ unitTarget->RemoveAurasDueToSpell(46394);
+
+ break;
+ }
+ // Negative Energy
+ case 46289:
{
- rank = 1;
+ if(!unitTarget)
+ return;
+
+ m_caster->CastSpell(unitTarget, 46285, true);
break;
- }
- else if((*i)->GetId() == 18693)
+ }
+ // Goblin Weather Machine
+ case 46203:
{
- rank = 2;
+ if(!unitTarget)
+ return;
+
+ uint32 spellId = 0;
+ switch(rand()%4)
+ {
+ case 0: spellId = 46740; break;
+ case 1: spellId = 46739; break;
+ case 2: spellId = 46738; break;
+ case 3: spellId = 46736; break;
+ }
+ unitTarget->CastSpell(unitTarget, spellId, true);
break;
}
- }
+ // 5,000 Gold
+ case 46642:
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
- static uint32 const itypes[6][3] = {
- { 5512,19004,19005}, // Minor Healthstone
- { 5511,19006,19007}, // Lesser Healthstone
- { 5509,19008,19009}, // Healthstone
- { 5510,19010,19011}, // Greater Healthstone
- { 9421,19012,19013}, // Major Healthstone
- {22103,22104,22105} // Master Healthstone
- };
+ ((Player*)unitTarget)->ModifyMoney(50000000);
- switch(m_spellInfo->Id)
- {
- case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
- case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
- case 5699: itemtype=itypes[2][rank];break; // Healthstone
- case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
- case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
- case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
- default:
- return;
- }
- DoCreateItem( effIndex, itemtype );
- return;
- }
- // Brittle Armor - need remove one 24575 Brittle Armor aura
- case 24590:
- unitTarget->RemoveSingleAuraFromStack(24575, 0);
- unitTarget->RemoveSingleAuraFromStack(24575, 1);
- return;
- // Mercurial Shield - need remove one 26464 Mercurial Shield aura
- case 26465:
- unitTarget->RemoveSingleAuraFromStack(26464, 0);
- return;
- // Orb teleport spells
- case 25140:
- case 25143:
- case 25650:
- case 25652:
- case 29128:
- case 29129:
- case 35376:
- case 35727:
- {
- if(!unitTarget)
- return;
+ break;
+ }
+ // Vigilance
+ case 50725:
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
- uint32 spellid;
- switch(m_spellInfo->Id)
- {
- case 25140: spellid = 32571; break;
- case 25143: spellid = 32572; break;
- case 25650: spellid = 30140; break;
- case 25652: spellid = 30141; break;
- case 29128: spellid = 32568; break;
- case 29129: spellid = 32569; break;
- case 35376: spellid = 25649; break;
- case 35727: spellid = 35730; break;
- default:
- return;
- }
+ // Remove Taunt cooldown
+ ((Player*)unitTarget)->RemoveSpellCooldown(355, true);
- unitTarget->CastSpell(unitTarget,spellid,false);
- return;
- }
+ return;
+ }
+ // Emblazon Runeblade
+ case 51770:
+ {
+ if(!m_originalCaster)
+ return;
- // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
- case 22539:
- case 22972:
- case 22975:
- case 22976:
- case 22977:
- case 22978:
- case 22979:
- case 22980:
- case 22981:
- case 22982:
- case 22983:
- case 22984:
- case 22985:
- {
- if(!unitTarget || !unitTarget->isAlive())
- return;
+ m_originalCaster->CastSpell(m_originalCaster, damage, false);
+ break;
+ }
+ // Death Gate
+ case 52751:
+ {
+ if(!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
+ return;
+ // triggered spell is stored in m_spellInfo->EffectBasePoints[0]
+ unitTarget->CastSpell(unitTarget, damage, false);
+ break;
+ }
+ // Winged Steed of the Ebon Blade
+ case 54729:
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
- // Onyxia Scale Cloak
- if(unitTarget->GetDummyAura(22683))
- return;
+ // Prevent stacking of mounts
+ unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
- // Shadow Flame
- m_caster->CastSpell(unitTarget, 22682, true);
- return;
- }
- break;
+ // Triggered spell id dependent of riding skill
+ if(uint16 skillval = ((Player*)unitTarget)->GetSkillValue(SKILL_RIDING))
+ {
+ if (skillval >= 300)
+ unitTarget->CastSpell(unitTarget, 54727, true);
+ else
+ unitTarget->CastSpell(unitTarget, 54726, true);
+ }
+ return;
+ }
+ case 58418: // Portal to Orgrimmar
+ case 58420: // Portal to Stormwind
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex!=0)
+ return;
- // Summon Black Qiraji Battle Tank
- case 26656:
- {
- if(!unitTarget)
- return;
+ uint32 spellID = m_spellInfo->CalculateSimpleValue(0);
+ uint32 questID = m_spellInfo->CalculateSimpleValue(1);
- // Prevent stacking of mounts
- unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+ if (((Player*)unitTarget)->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE && !((Player*)unitTarget)->GetQuestRewardStatus (questID))
+ unitTarget->CastSpell(unitTarget, spellID, true);
- // Two separate mounts depending on area id (allows use both in and out of specific instance)
- if (unitTarget->GetAreaId() == 3428)
- unitTarget->CastSpell(unitTarget, 25863, false);
- else
- unitTarget->CastSpell(unitTarget, 26655, false);
- break;
- }
- // Piccolo of the Flaming Fire
- case 17512:
- {
- if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
- return;
- unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
- break;
- }
- // Netherbloom
- case 28702:
- {
- if(!unitTarget)
- return;
- // 25% chance of casting a random buff
- if(roll_chance_i(75))
- return;
+ return;
+ }
+ case 58941: // Rock Shards
+ if(unitTarget && m_originalCaster)
+ {
+ for(uint32 i = 0; i < 3; ++i)
+ {
+ m_originalCaster->CastSpell(unitTarget, 58689, true);
+ m_originalCaster->CastSpell(unitTarget, 58692, true);
+ }
+ if(m_originalCaster->GetMap()->IsHeroic())
+ {
+ m_originalCaster->CastSpell(unitTarget, 60883, true);
+ m_originalCaster->CastSpell(unitTarget, 60884, true);
+ }
+ else
+ {
+ m_originalCaster->CastSpell(unitTarget, 58695, true);
+ m_originalCaster->CastSpell(unitTarget, 58696, true);
+ }
+ }
+ return;
+ case 59317: // Teleporting
+ if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
- // triggered spells are 28703 to 28707
- // Note: some sources say, that there was the possibility of
- // receiving a debuff. However, this seems to be removed by a patch.
- const uint32 spellid = 28703;
+ // return from top
+ if (((Player*)unitTarget)->GetAreaId() == 4637)
+ unitTarget->CastSpell(unitTarget, 59316, true);
+ // teleport atop
+ else
+ unitTarget->CastSpell(unitTarget, 59314, true);
- // don't overwrite an existing aura
- for(uint8 i=0; i<5; i++)
- if(unitTarget->HasAura(spellid+i, 0))
return;
- unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
- break;
- }
-
- // Nightmare Vine
- case 28720:
- {
- if(!unitTarget)
- return;
- // 25% chance of casting Nightmare Pollen
- if(roll_chance_i(75))
- return;
- unitTarget->CastSpell(unitTarget, 28721, true);
- break;
- }
+ // random spell learn instead placeholder
+ case 60893: // Northrend Alchemy Research
+ case 61177: // Northrend Inscription Research
+ case 61288: // Minor Inscription Research
+ case 61756: // Northrend Inscription Research (FAST QA VERSION)
+ {
+ if(m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
- // Mirren's Drinking Hat
- case 29830:
- {
- uint32 item = 0;
- switch ( urand(1,6) )
- {
- case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
- case 4: case 5: item = 23585; break;// Stouthammer Lite
- case 6: item = 23586; break;// Aerie Peak Pale Ale
+ // learn random explicit discovery recipe (if any)
+ if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, (Player*)m_caster))
+ ((Player*)m_caster)->learnSpell(discoveredSpell,false);
+ return;
+ }
}
- if (item)
- DoCreateItem(effIndex,item);
break;
}
- // Improved Sprint
- case 30918:
+ case SPELLFAMILY_WARLOCK:
{
- // Removes snares and roots.
- uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
- Unit::AuraMap& Auras = unitTarget->GetAuras();
- for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
+ switch(m_spellInfo->Id)
{
- next = iter;
- ++next;
- Aura *aur = iter->second;
- if (!aur->IsPositive()) //only remove negative spells
+ // Healthstone creating spells
+ case 6201:
+ case 6202:
+ case 5699:
+ case 11729:
+ case 11730:
+ case 27230:
+ case 47871:
+ case 47878:
{
- // check for mechanic mask
- if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
+ uint32 itemtype;
+ uint32 rank = 0;
+ Unit::AuraEffectList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
{
- unitTarget->RemoveAurasDueToSpell(aur->GetId());
- if(Auras.empty())
+ if((*i)->GetId() == 18692)
+ {
+ rank = 1;
break;
- else
- next = Auras.begin();
+ }
+ else if((*i)->GetId() == 18693)
+ {
+ rank = 2;
+ break;
+ }
}
- }
- }
- break;
- }
- // Goblin Weather Machine
- case 46203:
- {
- if(!unitTarget)
- return;
+ static uint32 const itypes[8][3] = {
+ { 5512,19004,19005}, // Minor Healthstone
+ { 5511,19006,19007}, // Lesser Healthstone
+ { 5509,19008,19009}, // Healthstone
+ { 5510,19010,19011}, // Greater Healthstone
+ { 9421,19012,19013}, // Major Healthstone
+ {22103,22104,22105}, // Master Healthstone
+ {36889,36890,36891}, // Demonic Healthstone
+ {36892,36893,36894} // Fel Healthstone
+ };
- uint32 spellId;
- switch(rand()%4)
- {
- case 0:
- spellId=46740;
- break;
- case 1:
- spellId=46739;
- break;
- case 2:
- spellId=46738;
- break;
- case 3:
- spellId=46736;
- break;
- }
- unitTarget->CastSpell(unitTarget, spellId, true);
- break;
- }
- case 48025: // Headless Horseman's Mount
- {
- if(!unitTarget)
+ switch(m_spellInfo->Id)
+ {
+ case 6201:
+ itemtype=itypes[0][rank];break; // Minor Healthstone
+ case 6202:
+ itemtype=itypes[1][rank];break; // Lesser Healthstone
+ case 5699:
+ itemtype=itypes[2][rank];break; // Healthstone
+ case 11729:
+ itemtype=itypes[3][rank];break; // Greater Healthstone
+ case 11730:
+ itemtype=itypes[4][rank];break; // Major Healthstone
+ case 27230:
+ itemtype=itypes[5][rank];break; // Master Healthstone
+ case 47871:
+ itemtype=itypes[6][rank];break; // Demonic Healthstone
+ case 47878:
+ itemtype=itypes[7][rank];break; // Fel Healthstone
+ default:
+ return;
+ }
+ DoCreateItem( effIndex, itemtype );
return;
-
- if(unitTarget)
+ }
+ // Everlasting Affliction
+ case 47422:
+ // Refresh corruption on target
+ if (AuraEffect * aur = unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, m_caster->GetGUID()))
+ aur->GetParentAura()->RefreshAura();
+ return;
+ // Demonic Empowerment
+ case 47193:
{
- switch(((Player*)unitTarget)->GetBaseSkillValue(762))
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || !((Creature *)unitTarget)->isPet())
+ return;
+ CreatureInfo const * ci = objmgr.GetCreatureTemplate(unitTarget->GetEntry());
+ switch (ci->family)
{
- case 75: unitTarget->CastSpell(unitTarget, 51621, true); break;;
- case 150: unitTarget->CastSpell(unitTarget, 48024, true); break;
- case 225: unitTarget->CastSpell(unitTarget, 51617, true); break;
- case 300: unitTarget->CastSpell(unitTarget, 48023, true); break;
- default: break;
+ case CREATURE_FAMILY_SUCCUBUS:
+ unitTarget->CastSpell(unitTarget, 54435, true);
+ break;
+ case CREATURE_FAMILY_VOIDWALKER:
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(54443);
+ int32 hp = unitTarget->GetMaxHealth() * m_caster->CalculateSpellDamage(spellInfo, 0, spellInfo->EffectBasePoints[0], unitTarget) /100;
+ unitTarget->CastCustomSpell(unitTarget, 54443,&hp, NULL, NULL,true);
+ //unitTarget->CastSpell(unitTarget, 54441, true);
+ break;
+ }
+ case CREATURE_FAMILY_FELGUARD:
+ unitTarget->CastSpell(unitTarget, 54508, true);
+ break;
+ case CREATURE_FAMILY_FELHUNTER:
+ unitTarget->CastSpell(unitTarget, 54509, true);
+ break;
+ case CREATURE_FAMILY_IMP:
+ unitTarget->CastSpell(unitTarget, 54444, true);
+ break;
}
+ return;
}
- break;
+ }
+ break;
}
- case 47977: // Magic Broom
+ case SPELLFAMILY_PRIEST:
{
- if(!unitTarget)
- return;
-
- if(unitTarget)
+ switch(m_spellInfo->Id)
{
- switch(((Player*)unitTarget)->GetBaseSkillValue(762))
+ // Pain and Suffering
+ case 47948:
{
- case 75: unitTarget->CastSpell(unitTarget, 42680, true); break;;
- case 150: case 225: case 300: unitTarget->CastSpell(unitTarget, 42683, true); break;
- default: break;
+ if (!unitTarget)
+ return;
+ // Refresh Shadow Word: Pain on target
+ if (AuraEffect * aur = unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, m_caster->GetGUID()))
+ aur->GetParentAura()->RefreshAura();
+ return;
}
+ // Divine Hymn
+ case 47951:
+ {
+ if (!unitTarget)
+ return;
+ Unit * target=NULL;
+ unitTarget->CastSpell(target, 59600, false);
+ unitTarget->CastSpell(target, 47953, false);
+ return;
+ }
+ default:
+ break;
}
break;
}
- }
-
- if(!unitTarget || !unitTarget->isAlive()) // can we remove this check?
- {
- sLog.outError("Spell %u in EffectScriptEffect does not have unitTarget", m_spellInfo->Id);
- return;
- }
-
- switch(m_spellInfo->Id)
- {
- // Dreaming Glory
- case 28698: unitTarget->CastSpell(unitTarget, 28694, true); break;
- // Needle Spine
- //case 39835: unitTarget->CastSpell(unitTarget, 39968, true); break;
- // Draw Soul
- case 40904: unitTarget->CastSpell(m_caster, 40903, true); break;
- // Flame Crash
- //case 41126: unitTarget->CastSpell(unitTarget, 41131, true); break;
- case 41931:
+ case SPELLFAMILY_HUNTER:
{
- int bag=19;
- int slot=0;
- Item* item = NULL;
-
- while (bag < 256)
+ switch(m_spellInfo->Id)
{
- item = ((Player*)m_caster)->GetItemByPos(bag,slot);
- if (item && item->GetEntry() == 38587) break;
- slot++;
- if (slot == 39)
+ // Chimera Shot
+ case 53209:
{
- slot = 0;
- bag++;
+ uint32 spellId = 0;
+ int32 basePoint = 0;
+ Unit::AuraMap& Auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
+ {
+ Aura *aura = (*i).second;
+ if (aura->GetCasterGUID() != m_caster->GetGUID())
+ continue;
+ // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
+ flag96 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
+ if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000))
+ continue;
+
+ // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
+ if (familyFlag[0] & 0x4000)
+ {
+ spellId = 53353; // 53353 Chimera Shot - Serpent
+ basePoint = aura->GetPartAura(0)->GetAmount() * 5 * 40 / 100;
+ }
+ // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
+ if (familyFlag[1] & 0x00000080)
+ {
+ int32 tickCount = aura->GetPartAura(0)->GetTickNumber();
+ spellId = 53358; // 53358 Chimera Shot - Viper
+ // Amount of one aura tick
+ basePoint = aura->GetPartAura(0)->GetAmount() * aura->GetTarget()->GetMaxPower(POWER_MANA) / 100 ;
+ int32 casterBasePoint = aura->GetPartAura(0)->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50 ;
+ if (basePoint > casterBasePoint)
+ basePoint = casterBasePoint;
+ basePoint = basePoint * tickCount * 60 / 100;
+ }
+ // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
+ if (familyFlag[0] & 0x00008000)
+ spellId = 53359; // 53359 Chimera Shot - Scorpid
+ // ?? nothing say in spell desc (possibly need addition check)
+ //if (familyFlag & 0x0000010000000000LL || // dot
+ // familyFlag & 0x0000100000000000LL) // stun
+ //{
+ // spellId = 53366; // 53366 Chimera Shot - Wyvern
+ //}
+
+ // Refresh aura duration
+ aura->RefreshAura();
+ break;
+ }
+ if (spellId)
+ m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true);
+ return;
}
+ default:
+ break;
}
- if (bag < 256)
- {
- if (((Player*)m_caster)->GetItemByPos(bag,slot)->GetCount() == 1) ((Player*)m_caster)->RemoveItem(bag,slot,true);
- else ((Player*)m_caster)->GetItemByPos(bag,slot)->SetCount(((Player*)m_caster)->GetItemByPos(bag,slot)->GetCount()-1);
- // Spell 42518 (Braufest - Gratisprobe des Braufest herstellen)
- m_caster->CastSpell(m_caster,42518,true);
- return;
- }
- }
- // Force Cast - Portal Effect: Sunwell Isle
- case 44876: unitTarget->CastSpell(unitTarget, 44870, true); break;
- // spell of Brutallus - Stomp
- case 45185:
- {
- if(unitTarget->HasAura(46394, 0)) // spell of Brutallus - Burn
- unitTarget->RemoveAurasDueToSpell(46394);
break;
}
- // Negative Energy
- case 46289: m_caster->CastSpell(unitTarget, 46285, true); break;
- //5,000 Gold
- case 46642:
- {
- if(unitTarget->GetTypeId() == TYPEID_PLAYER)
- ((Player*)unitTarget)->ModifyMoney(50000000);
- break;
- }
- }
-
- if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
- {
- switch(m_spellInfo->SpellFamilyFlags)
+ case SPELLFAMILY_PALADIN:
{
// Judgement
- case 0x800000:
+ if (m_spellInfo->SpellFamilyFlags[0] & 0x800000)
{
+ if(!unitTarget || !unitTarget->isAlive())
+ return;
+ uint32 spellId1 = 0;
uint32 spellId2 = 0;
- // all seals have aura dummy
- Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
+ // Judgement self add switch
+ switch (m_spellInfo->Id)
{
- SpellEntry const *spellInfo = (*itr)->GetSpellProto();
-
- // search seal (all seals have judgement's aura dummy spell id in 2 effect
- if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
- continue;
-
- // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
- spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
-
- if(spellId2 <= 1)
- continue;
-
- // found, remove seal
- m_caster->RemoveAurasDueToSpell((*itr)->GetId());
-
- // Sanctified Judgement
- Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
+ case 41467: break; // Judgement
+ case 53407: spellId1 = 20184; break; // Judgement of Justice
+ case 20271: // Judgement of Light
+ case 57774: spellId1 = 20185; break; // Judgement of Light
+ case 53408: spellId1 = 20186; break; // Judgement of Wisdom
+ default:
+ return;
+ }
+ // all seals have aura dummy in 2 effect
+ Unit::AuraMap & sealAuras = m_caster->GetAuras();
+ for(Unit::AuraMap::iterator iter = sealAuras.begin(); iter != sealAuras.end();)
+ {
+ if (IsSealSpell(iter->second->GetSpellProto()))
{
- if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
+ if (AuraEffect * aureff = iter->second->GetPartAura(2))
+ if (aureff->GetAuraName()==SPELL_AURA_DUMMY)
+ {
+ if (sSpellStore.LookupEntry(aureff->GetAmount()))
+ spellId2 = aureff->GetAmount();
+ break;
+ }
+ if (!spellId2)
{
- int32 chance = (*i)->GetModifier()->m_amount;
- if ( roll_chance_i(chance) )
+ switch (iter->first)
{
- int32 mana = spellInfo->manaCost;
- if ( Player* modOwner = m_caster->GetSpellModOwner() )
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
- mana = int32(mana* 0.8f);
- m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
+ // Seal of light, Seal of wisdom, Seal of justice
+ case 20165:
+ case 20166:
+ case 20164:
+ spellId2 = 54158;
}
- break;
}
+ break;
}
+ else
+ ++iter;
+ }
+ if (spellId1)
+ m_caster->CastSpell(unitTarget, spellId1, true);
+ if (spellId2)
+ m_caster->CastSpell(unitTarget, spellId2, true);
+ return;
+ }
+ }
+ case SPELLFAMILY_POTION:
+ {
+ switch(m_spellInfo->Id)
+ {
+ // Dreaming Glory
+ case 28698:
+ {
+ if(!unitTarget)
+ return;
+ unitTarget->CastSpell(unitTarget, 28694, true);
+ break;
+ }
+ // Netherbloom
+ case 28702:
+ {
+ if(!unitTarget)
+ return;
+ // 25% chance of casting a random buff
+ if(roll_chance_i(75))
+ return;
+
+ // triggered spells are 28703 to 28707
+ // Note: some sources say, that there was the possibility of
+ // receiving a debuff. However, this seems to be removed by a patch.
+ const uint32 spellid = 28703;
+ // don't overwrite an existing aura
+ for(uint8 i=0; i<5; i++)
+ if(unitTarget->HasAuraEffect(spellid+i, 0))
+ return;
+ unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
break;
}
- m_caster->CastSpell(unitTarget,spellId2,true);
- return;
+ // Nightmare Vine
+ case 28720:
+ {
+ if(!unitTarget)
+ return;
+ // 25% chance of casting Nightmare Pollen
+ if(roll_chance_i(75))
+ return;
+ unitTarget->CastSpell(unitTarget, 28721, true);
+ break;
+ }
}
+ break;
}
}
@@ -4930,7 +5283,7 @@ void Spell::EffectSanctuary(uint32 /*i*/)
std::list<Unit*> targets;
Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, World::GetMaxVisibleDistance());
- Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(targets, u_check);
+ Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(unitTarget, targets, u_check);
unitTarget->VisitNearbyObject(World::GetMaxVisibleDistance(), searcher);
for(std::list<Unit*>::iterator iter = targets.begin(); iter != targets.end(); ++iter)
{
@@ -4950,9 +5303,9 @@ void Spell::EffectSanctuary(uint32 /*i*/)
unitTarget->CombatStop();
unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
// Vanish allows to remove all threat and cast regular stealth so other spells can be used
- if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
+ if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VANISH))
{
- ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
+ ((Player *)m_caster)->RemoveAurasByType(SPELL_AURA_MOD_ROOT);
}
}
@@ -4985,6 +5338,7 @@ void Spell::EffectDuel(uint32 i)
// Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
// Don't have to check the target's map since you cannot challenge someone across maps
if(caster->GetMap()->Instanceable())
+ //if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
{
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
return;
@@ -5010,11 +5364,12 @@ void Spell::EffectDuel(uint32 i)
uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
Map *map = m_caster->GetMap();
- if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
+ if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id,
+ map, m_caster->GetPhaseMask(),
m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
m_caster->GetPositionZ(),
- m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
+ m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
{
delete pGameObj;
return;
@@ -5023,7 +5378,7 @@ void Spell::EffectDuel(uint32 i)
pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
int32 duration = GetSpellDuration(m_spellInfo);
- pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
m_caster->AddGameObject(pGameObj);
@@ -5100,7 +5455,7 @@ void Spell::EffectSummonPlayer(uint32 /*i*/)
WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
data << uint64(m_caster->GetGUID()); // summoner guid
data << uint32(m_caster->GetZoneId()); // summoner zone
- data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
+ data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILISECONDS); // auto decline after msecs
((Player*)unitTarget)->GetSession()->SendPacket(&data);
}
@@ -5123,89 +5478,40 @@ void Spell::EffectActivateObject(uint32 effect_idx)
sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
}
-void Spell::EffectSummonTotem(uint32 i)
+void Spell::EffectApplyGlyph(uint32 i)
{
- uint8 slot = 0;
- switch(m_spellInfo->EffectMiscValueB[i])
- {
- case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
- case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
- case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
- case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
- // Battle standard case
- case SUMMON_TYPE_TOTEM: slot = 254; break;
- // jewelery statue case, like totem without slot
- case SUMMON_TYPE_GUARDIAN: slot = 255; break;
- default: return;
- }
-
- if(slot < MAX_TOTEM)
- {
- uint64 guid = m_caster->m_TotemSlot[slot];
- if(guid != 0)
- {
- Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
- if(OldTotem && OldTotem->isTotem())
- ((Totem*)OldTotem)->UnSummon();
- }
- }
-
- uint32 team = 0;
- if (m_caster->GetTypeId()==TYPEID_PLAYER)
- team = ((Player*)m_caster)->GetTeam();
-
- Totem* pTotem = new Totem;
-
- if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
- {
- delete pTotem;
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- }
-
- float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
-
- float x,y,z;
- m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
-
- // totem must be at same Z in case swimming caster and etc.
- if( fabs( z - m_caster->GetPositionZ() ) > 5 )
- z = m_caster->GetPositionZ();
- pTotem->Relocate(x, y, z, m_caster->GetOrientation());
-
- if(slot < MAX_TOTEM)
- m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
-
- pTotem->SetOwner(m_caster->GetGUID());
- pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
-
- int32 duration=GetSpellDuration(m_spellInfo);
- if(Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
- pTotem->SetDuration(duration);
+ Player *player = (Player*)m_caster;
- if (damage) // if not spell info, DB values used
+ // apply new one
+ if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
{
- pTotem->SetMaxHealth(damage);
- pTotem->SetHealth(damage);
- }
-
- pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
- pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
-
- pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
- pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
+ if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
+ {
+ if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
+ {
+ if(gp->TypeFlags != gs->TypeFlags)
+ {
+ SendCastResult(SPELL_FAILED_INVALID_GLYPH);
+ return; // glyph slot mismatch
+ }
+ }
- pTotem->Summon(m_caster);
+ // remove old glyph
+ if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
+ {
+ if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
+ {
+ player->RemoveAurasDueToSpell(old_gp->SpellId);
+ player->SetGlyph(m_glyphIndex, 0);
+ }
+ }
- if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
- data << uint8(slot);
- data << uint64(pTotem->GetGUID());
- data << uint32(duration);
- data << uint32(m_spellInfo->Id);
- ((Player*)m_caster)->SendDirectMessage(&data);
+ player->CastSpell(m_caster, gp->SpellId, true);
+ player->SetGlyph(m_glyphIndex, glyph);
+ }
}
}
@@ -5246,7 +5552,7 @@ void Spell::EffectEnchantHeldItem(uint32 i)
return;
// Apply the temporary enchantment
- item->SetEnchantment(slot, enchant_id, duration*1000, 0);
+ item->SetEnchantment(slot, enchant_id, duration*IN_MILISECONDS, 0);
item_owner->ApplyEnchantment(item,slot,true);
}
}
@@ -5289,7 +5595,8 @@ void Spell::EffectFeedPet(uint32 i)
Player *_player = (Player*)m_caster;
- if(!itemTarget)
+ Item* foodItem = m_targets.getItemTarget();
+ if(!foodItem)
return;
Pet *pet = _player->GetPet();
@@ -5299,15 +5606,15 @@ void Spell::EffectFeedPet(uint32 i)
if(!pet->isAlive())
return;
- int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
+ int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
if(benefit <= 0)
return;
uint32 count = 1;
- _player->DestroyItemCount(itemTarget,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(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
+ m_caster->CastCustomSpell(pet,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
}
void Spell::EffectDismissPet(uint32 /*i*/)
@@ -5315,7 +5622,7 @@ void Spell::EffectDismissPet(uint32 /*i*/)
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- Pet* pet = m_caster->GetPet();
+ Pet* pet = ((Player*)m_caster)->GetPet();
// not let dismiss dead pet
if(!pet||!pet->isAlive())
@@ -5343,7 +5650,7 @@ void Spell::EffectSummonObject(uint32 i)
{
GameObject* obj = NULL;
if( m_caster )
- obj = ObjectAccessor::GetGameObject(*m_caster, guid);
+ obj = m_caster->GetMap()->GetGameObject(guid);
if(obj) obj->Delete();
m_caster->m_ObjectSlot[slot] = 0;
@@ -5351,9 +5658,6 @@ void Spell::EffectSummonObject(uint32 i)
GameObject* pGameObj = new GameObject;
- float rot2 = sin(m_caster->GetOrientation()/2);
- float rot3 = cos(m_caster->GetOrientation()/2);
-
float x,y,z;
// If dest location if present
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
@@ -5367,7 +5671,8 @@ void Spell::EffectSummonObject(uint32 i)
m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
Map *map = m_caster->GetMap();
- if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
+ if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
+ m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
{
delete pGameObj;
return;
@@ -5375,7 +5680,7 @@ void Spell::EffectSummonObject(uint32 i)
//pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
int32 duration = GetSpellDuration(m_spellInfo);
- pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
m_caster->AddGameObject(pGameObj);
@@ -5446,18 +5751,14 @@ void Spell::EffectAddExtraAttacks(uint32 /*i*/)
void Spell::EffectParry(uint32 /*i*/)
{
- if (unitTarget->GetTypeId() == TYPEID_PLAYER)
- {
+ if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->SetCanParry(true);
- }
}
void Spell::EffectBlock(uint32 /*i*/)
{
- if (unitTarget->GetTypeId() != TYPEID_PLAYER)
- return;
-
- ((Player*)unitTarget)->SetCanBlock(true);
+ if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)unitTarget)->SetCanBlock(true);
}
void Spell::EffectMomentMove(uint32 i)
@@ -5469,7 +5770,7 @@ void Spell::EffectMomentMove(uint32 i)
return;
uint32 mapid = m_caster->GetMapId();
- float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ float dis = m_caster->GetSpellRadiusForTarget(unitTarget, sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
// src point
float *fx = new float[11], *fy = new float[11], *fz = new float[11];
@@ -5507,26 +5808,9 @@ void Spell::EffectMomentMove(uint32 i)
if (hit == false)
itr_j = last_valid;
-
- if (unitTarget->GetTypeId() == TYPEID_PLAYER)
- ((Player*)unitTarget)->TeleportTo(mapid, fx[itr_j], fy[itr_j], fz[itr_j] + 0.07531, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget == m_caster ? TELE_TO_SPELL : 0));
- else
- MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx[itr_j], fy[itr_j], fz[itr_j] + 0.07531, orientation);
+ unitTarget->NearTeleportTo(fx[itr_j], fy[itr_j], fz[itr_j] + 0.07531, orientation, unitTarget==m_caster);
delete [] fx; delete [] fy; delete [] fz;
-
-/* uint32 mapid = unitTarget->GetMapId();
- float ox,oy,oz;
- unitTarget->GetPosition(ox,oy,oz);
-
- float fx,fy,fz; // getObjectHitPos overwrite last args in any result case
- if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, m_targets.m_destX,m_targets.m_destY,oz+0.5,fx,fy,fz, -0.5))
- unitTarget->UpdateGroundPositionZ(fx,fy,fz);
-
- if(unitTarget->GetTypeId() == TYPEID_PLAYER)
- ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
- else
- MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());*/
}
void Spell::EffectReputation(uint32 i)
@@ -5545,7 +5829,7 @@ void Spell::EffectReputation(uint32 i)
if(!factionEntry)
return;
- _player->ModifyFactionReputation(factionEntry,rep_change);
+ _player->GetReputationMgr().ModifyReputation(factionEntry,rep_change);
}
void Spell::EffectQuestComplete(uint32 i)
@@ -5639,97 +5923,11 @@ void Spell::EffectCharge(uint32 /*i*/)
m_caster->Attack(target, true);
}
-void Spell::EffectSummonCritter(uint32 i)
-{
- if(m_caster->GetTypeId() != TYPEID_PLAYER)
- return;
- Player* player = (Player*)m_caster;
-
- uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
- if(!pet_entry)
- return;
-
- Pet* old_critter = player->GetMiniPet();
-
- // for same pet just despawn
- if(old_critter && old_critter->GetEntry() == pet_entry)
- {
- player->RemoveMiniPet();
- return;
- }
-
- // despawn old pet before summon new
- if(old_critter)
- player->RemoveMiniPet();
-
- // summon new pet
- Pet* critter = new Pet(MINI_PET);
-
- Map *map = m_caster->GetMap();
- uint32 pet_number = objmgr.GeneratePetNumber();
- if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
- map, pet_entry, pet_number))
- {
- sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
- delete critter;
- return;
- }
-
- float x,y,z;
- // If dest location if present
- if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
- {
- x = m_targets.m_destX;
- y = m_targets.m_destY;
- z = m_targets.m_destZ;
- }
- // Summon if dest location not present near caster
- else
- m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
-
- critter->Relocate(x,y,z,m_caster->GetOrientation());
-
- if(!critter->IsPositionValid())
- {
- sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
- critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
- delete critter;
- return;
- }
-
- critter->SetOwnerGUID(m_caster->GetGUID());
- critter->SetCreatorGUID(m_caster->GetGUID());
- critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
- critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
-
- critter->AIM_Initialize();
- critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
- critter->SetMaxHealth(1);
- critter->SetHealth(1);
- critter->SetLevel(1);
-
- // set timer for unsummon
- int32 duration = GetSpellDuration(m_spellInfo);
- if(duration > 0)
- critter->SetDuration(duration);
-
- std::string name = player->GetName();
- name.append(petTypeSuffix[critter->getPetType()]);
- critter->SetName( name );
- player->SetMiniPet(critter);
-
- map->Add((Creature*)critter);
-}
-
void Spell::EffectKnockBack(uint32 i)
{
if(!unitTarget)
return;
- // Effect only works on players
- if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
- return;
-
float x, y;
if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
{
@@ -5742,31 +5940,26 @@ void Spell::EffectKnockBack(uint32 i)
y = m_caster->GetPositionY();
}
- float dx = unitTarget->GetPositionX() - x;
- float dy = unitTarget->GetPositionY() - y;
- float vcos, vsin;
- if(dx < 0.001f && dy < 0.001f)
+ float speedxy = float(m_spellInfo->EffectMiscValue[i])/10;
+ float speedz = float(damage/10);
+
+ unitTarget->KnockbackFrom(x, y, speedxy, speedz);
+}
+
+void Spell::EffectJump2(uint32 i)
+{
+ float speedxy = float(m_spellInfo->EffectMiscValue[i])/10;
+ float speedz = float(damage/10);
+ if(!speedxy)
{
- float angle = rand_norm()*2*M_PI;
- vcos = cos(angle);
- vsin = sin(angle);
+ if(m_targets.getUnitTarget())
+ m_caster->JumpTo(m_targets.getUnitTarget(), speedz);
}
else
{
- float dist = sqrt((dx*dx) + (dy*dy));
- vcos = dx / dist;
- vsin = dy / dist;
+ //1891: Disengage
+ m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891);
}
-
- WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
- data.append(unitTarget->GetPackGUID());
- data << uint32(0); // Sequence
- data << float(vcos); // x direction
- data << float(vsin); // y direction
- data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
- data << float(damage/-10); // Z Movement speed (vertical)
-
- ((Player*)unitTarget)->GetSession()->SendPacket(&data);
}
void Spell::EffectSendTaxi(uint32 i)
@@ -5774,38 +5967,7 @@ void Spell::EffectSendTaxi(uint32 i)
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
- TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
- if(!entry)
- return;
-
- std::vector<uint32> nodes;
-
- nodes.resize(2);
- nodes[0] = entry->from;
- nodes[1] = entry->to;
-
- uint32 mountid = 0;
- switch(m_spellInfo->Id)
- {
- case 31606: //Stormcrow Amulet
- mountid = 17447;
- break;
- case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
- case 45113: //Quest - Sunwell Daily - Ship Bombing Run
- case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
- mountid = 22840;
- break;
- case 34905: //Stealth Flight
- mountid = 6851;
- break;
- case 41533: //Fly of the Netherwing
- case 41540: //Fly of the Netherwing
- mountid = 23468;
- break;
- }
-
- ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
-
+ ((Player*)unitTarget)->ActivateTaxiPathTo(m_spellInfo->EffectMiscValue[i],m_spellInfo->Id);
}
void Spell::EffectPlayerPull(uint32 i)
@@ -5839,22 +6001,21 @@ void Spell::EffectDispelMechanic(uint32 i)
uint32 mechanic = m_spellInfo->EffectMiscValue[i];
+ std::queue < std::pair < uint32, uint64 > > dispel_list;
+
Unit::AuraMap& Auras = unitTarget->GetAuras();
- for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
+ for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); iter++)
{
- next = iter;
- ++next;
- SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
- if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
- {
- unitTarget->RemoveAurasDueToSpell(spell->Id);
- if(Auras.empty())
- break;
- else
- next = Auras.begin();
- }
+ if((GetAllSpellMechanicMask(iter->second->GetSpellProto()) & (1<<(mechanic))) && GetDispelChance(iter->second->GetCaster(), iter->second->GetId()))
+ {
+ dispel_list.push(std::make_pair(iter->second->GetId(), iter->second->GetCasterGUID() ) );
+ }
+ }
+
+ for(;dispel_list.size();dispel_list.pop())
+ {
+ unitTarget->RemoveAura(dispel_list.front().first, dispel_list.front().second, AURA_REMOVE_BY_ENEMY_SPELL);
}
- return;
}
void Spell::EffectSummonDeadPet(uint32 /*i*/)
@@ -5869,39 +6030,43 @@ void Spell::EffectSummonDeadPet(uint32 /*i*/)
return;
if(damage < 0)
return;
+
pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
pet->setDeathState( ALIVE );
pet->clearUnitState(UNIT_STAT_ALL_STATE);
pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
- pet->AIM_Initialize();
-
- _player->PetSpellInitialize();
+ //pet->AIM_Initialize();
+ //_player->PetSpellInitialize();
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
}
void Spell::EffectDestroyAllTotems(uint32 /*i*/)
{
- float mana = 0;
- for(int slot = 0; slot < MAX_TOTEM; ++slot)
+ int32 mana = 0;
+ for(int slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot)
{
- if(!m_caster->m_TotemSlot[slot])
+ if(!m_caster->m_SummonSlot[slot])
continue;
- Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
+ Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_SummonSlot[slot]);
if(totem && totem->isTotem())
{
uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
if(spellInfo)
- mana += spellInfo->manaCost * damage / 100;
+ {
+ mana += spellInfo->manaCost;
+ mana += spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100;
+ }
((Totem*)totem)->UnSummon();
}
}
+ mana = mana * damage / 100;
- int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
- m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
+ if (mana)
+ m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true);
}
void Spell::EffectDurabilityDamage(uint32 i)
@@ -5984,13 +6149,14 @@ void Spell::EffectTransmitted(uint32 effIndex)
//FIXME: this can be better check for most objects but still hack
else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
{
- float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
+ float dis = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
}
else
{
- float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
- float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
+ //GO is always friendly to it's creator, get range for friends
+ float min_dis = GetSpellMinRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
+ float max_dis = GetSpellMaxRangeForFriend(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
float dis = rand_norm() * (max_dis - min_dis) + min_dis;
m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
@@ -6019,7 +6185,7 @@ void Spell::EffectTransmitted(uint32 effIndex)
GameObject* pGameObj = new GameObject;
if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
- fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
{
delete pGameObj;
return;
@@ -6032,15 +6198,11 @@ void Spell::EffectTransmitted(uint32 effIndex)
case GAMEOBJECT_TYPE_FISHINGNODE:
{
m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
- // Orientation3
- pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 2, 0.88431775569915771 );
- // Orientation4
- pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 3, -0.4668855369091033 );
m_caster->AddGameObject(pGameObj); // will removed at spell cancel
// end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
// start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
- int32 lastSec;
+ int32 lastSec = 0;
switch(urand(0, 3))
{
case 0: lastSec = 3; break;
@@ -6049,7 +6211,7 @@ void Spell::EffectTransmitted(uint32 effIndex)
case 3: lastSec = 17; break;
}
- duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
+ duration = duration - lastSec*IN_MILISECONDS + FISHING_BOBBER_READY_TIME*IN_MILISECONDS;
break;
}
case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
@@ -6069,14 +6231,14 @@ void Spell::EffectTransmitted(uint32 effIndex)
}
}
- pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetOwnerGUID(m_caster->GetGUID() );
//pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
pGameObj->SetSpellId(m_spellInfo->Id);
- DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
+ DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted");
//m_caster->AddGameObject(pGameObj);
//m_ObjToDel.push_back(pGameObj);
@@ -6090,9 +6252,9 @@ void Spell::EffectTransmitted(uint32 effIndex)
{
GameObject* linkedGO = new GameObject;
if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
- fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
+ m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
{
- linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
//linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
linkedGO->SetSpellId(m_spellInfo->Id);
linkedGO->SetOwnerGUID(m_caster->GetGUID() );
@@ -6130,6 +6292,28 @@ void Spell::EffectProspecting(uint32 /*i*/)
((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
}
+void Spell::EffectMilling(uint32 /*i*/)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player* p_caster = (Player*)m_caster;
+ if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
+ return;
+
+ if(itemTarget->GetCount() < 5)
+ return;
+
+ if( sWorld.getConfig(CONFIG_SKILL_MILLING))
+ {
+ uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
+ uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
+ p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
+ }
+
+ ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
+}
+
void Spell::EffectSkill(uint32 /*i*/)
{
sLog.outDebug("WORLD: SkillEFFECT");
@@ -6137,26 +6321,34 @@ void Spell::EffectSkill(uint32 /*i*/)
void Spell::EffectSummonDemon(uint32 i)
{
- float px = m_targets.m_destX;
- float py = m_targets.m_destY;
- float pz = m_targets.m_destZ;
+ float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
- Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
- if (!Charmed)
- return;
+ int32 amount = damage > 0 ? damage : 1;
- // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
- Charmed->SetLevel(m_caster->getLevel());
+ for(int32 count = 0; count < amount; ++count)
+ {
+ float px, py, pz;
+ GetSummonPosition(i, px, py, pz, radius, count);
- // TODO: Add damage/mana/hp according to level
+ int32 duration = GetSpellDuration(m_spellInfo);
- if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
- {
- // Enslave demon effect, without mana cost and cooldown
- m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
+ Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,duration);
+ if (!Charmed) // something fatal, not attempt more
+ return;
+
+ // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
+ Charmed->SetLevel(m_caster->getLevel());
+
+ // TODO: Add damage/mana/hp according to level
+
+ if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
+ {
+ // Enslave demon effect, without mana cost and cooldown
+ m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
- // Inferno effect
- Charmed->CastSpell(Charmed, 22703, true, 0);
+ // Inferno effect
+ Charmed->CastSpell(Charmed, 22703, true, 0);
+ }
}
}
@@ -6198,7 +6390,7 @@ void Spell::EffectStealBeneficialBuff(uint32 i)
if(!unitTarget || unitTarget==m_caster) // can't steal from self
return;
- std::vector <Aura *> steal_list;
+ std::list <Aura *> steal_list;
// Create dispel mask by dispel type
uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
Unit::AuraMap const& auras = unitTarget->GetAuras();
@@ -6208,53 +6400,38 @@ void Spell::EffectStealBeneficialBuff(uint32 i)
if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
{
// Need check for passive? this
- if (aur->IsPositive() && !aur->IsPassive())
+ if (aur->IsPositive() && !aur->IsPassive() && !(aur->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_NOT_STEALABLE))
steal_list.push_back(aur);
}
}
// Ok if exist some buffs for dispel try dispel it
- if (!steal_list.empty())
+ if (uint32 list_size = steal_list.size())
{
- std::list < std::pair<uint32,uint64> > success_list;
- int32 list_size = steal_list.size();
+ std::list < Aura * > success_list;
+
// dispel N = damage buffs (or while exist buffs for dispel)
- for (int32 count=0; count < damage && list_size > 0; ++count)
+ for (int32 count=0; count < damage && list_size > 0; ++count, list_size = steal_list.size())
{
// Random select buff for dispel
- Aura *aur = steal_list[urand(0, list_size-1)];
- // Not use chance for steal
- // TODO possible need do it
- success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
-
- // Remove buff from list for prevent doubles
- for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
- {
- Aura *stealed = *j;
- if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
- {
- j = steal_list.erase(j);
- --list_size;
- }
- else
- ++j;
- }
+ std::list < Aura * > ::iterator itr = steal_list.begin();
+ for (uint32 i=urand(0, list_size-1);i>0;--i)
+ itr++;
+ success_list.push_back(*itr);
+ steal_list.erase(itr);
}
- // Really try steal and send log
- if (!success_list.empty())
+ if (success_list.size())
{
- int32 count = success_list.size();
- WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
+ WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+damage*5);
data.append(unitTarget->GetPackGUID()); // Victim GUID
data.append(m_caster->GetPackGUID()); // Caster GUID
data << uint32(m_spellInfo->Id); // dispel spell id
data << uint8(0); // not used
- data << uint32(count); // count
- for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
+ data << uint32(success_list.size()); // count
+ for (std::list < Aura * > ::iterator itr = success_list.begin();itr!=success_list.end();++itr)
{
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
- data << uint32(spellInfo->Id); // Spell Id
+ data << uint32((*itr)->GetId()); // Spell Id
data << uint8(0); // 0 - steals !=0 transfers
- unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
+ unitTarget->RemoveAurasDueToSpellBySteal((*itr)->GetId(), (*itr)->GetCasterGUID(), m_caster);
}
m_caster->SendMessageToSet(&data, true);
}
@@ -6266,7 +6443,15 @@ void Spell::EffectKillCredit(uint32 i)
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
- ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
+ int32 creatureEntry = m_spellInfo->EffectMiscValue[i];
+ if(!creatureEntry)
+ {
+ if(m_spellInfo->Id == 42793) // Burn Body
+ creatureEntry = 24008; // Fallen Combatant
+ }
+
+ if(creatureEntry)
+ ((Player*)unitTarget)->RewardPlayerAndGroupAtEvent(creatureEntry, unitTarget);
}
void Spell::EffectQuestFail(uint32 i)
@@ -6277,9 +6462,149 @@ void Spell::EffectQuestFail(uint32 i)
((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
}
+void Spell::EffectActivateRune(uint32 eff_idx)
+{
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player *plr = (Player*)m_caster;
+
+ if(plr->getClass() != CLASS_DEATH_KNIGHT)
+ return;
+
+ for(uint32 j = 0; j < MAX_RUNES; ++j)
+ {
+ if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[eff_idx])
+ {
+ plr->SetRuneCooldown(j, 0);
+ }
+ }
+}
+
+void Spell::EffectTitanGrip(uint32 /*eff_idx*/)
+{
+ if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)unitTarget)->SetCanTitanGrip(true);
+}
+
void Spell::EffectRedirectThreat(uint32 /*i*/)
{
if(unitTarget)
- m_caster->SetReducedThreatPercent(100, unitTarget->GetGUID());
+ m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID());
+}
+
+void Spell::EffectWMODamage(uint32 /*i*/)
+{
+ if(gameObjTarget && gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
+ gameObjTarget->TakenDamage((uint32)damage);
+}
+
+void Spell::EffectWMORepair(uint32 /*i*/)
+{
+ if(gameObjTarget && gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
+ gameObjTarget->Rebuild();
}
+void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties)
+{
+ Unit *caster = m_originalCaster;
+ if(caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem())
+ caster = ((Totem*)caster)->GetOwner();
+ if(!caster)
+ return;
+
+ // in another case summon new
+ uint32 level = caster->getLevel();
+
+ // level of pet summoned using engineering item based at engineering skill level
+ if(m_CastItem && caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ ItemPrototype const *proto = m_CastItem->GetProto();
+ if(proto && proto->RequiredSkill == SKILL_ENGINERING)
+ {
+ uint16 skill202 = ((Player*)caster)->GetSkillValue(SKILL_ENGINERING);
+ if(skill202)
+ {
+ level = skill202/5;
+ }
+ }
+ }
+
+ //float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
+ float radius = 5.0f;
+ int32 amount = damage > 0 ? damage : 1;
+ switch(m_spellInfo->Id)
+ {
+ case 1122: // Inferno
+ case 18662: // Curse of Doom
+ amount = 1;
+ break;
+ }
+ int32 duration = GetSpellDuration(m_spellInfo);
+ TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
+ Map *map = caster->GetMap();
+
+ for(int32 count = 0; count < amount; ++count)
+ {
+ float px, py, pz;
+ GetSummonPosition(0, px, py, pz, radius, count);
+
+ TempSummon *summon = map->SummonCreature(entry, px, py, pz, m_caster->GetOrientation(), properties, duration, caster);
+ if(!summon)
+ return;
+
+ if(summon->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ ((Guardian*)summon)->InitStatsForLevel(level);
+
+ summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+
+ summon->AI()->EnterEvadeMode();
+ }
+}
+
+void Spell::GetSummonPosition(uint32 i, float &x, float &y, float &z, float radius, uint32 count)
+{
+ if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ // Summon 1 unit in dest location
+ if (count == 0)
+ {
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+ }
+ // Summon in random point all other units if location present
+ else
+ {
+ //This is a workaround. Do not have time to write much about it
+ switch(m_spellInfo->EffectImplicitTargetA[i])
+ {
+ case TARGET_MINION:
+ case TARGET_DEST_CASTER_RANDOM:
+ m_caster->GetGroundPointAroundUnit(x, y, z, radius * rand_norm(), rand_norm()*2*M_PI);
+ break;
+ case TARGET_DEST_DEST_RANDOM:
+ case TARGET_DEST_TARGET_RANDOM:
+ m_caster->GetRandomPoint(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ,radius,x,y,z);
+ break;
+ default:
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+ break;
+ }
+ }
+ }
+ // Summon if dest location not present near caster
+ else
+ m_caster->GetClosePoint(x,y,z,3.0f);
+}
+
+void Spell::EffectRenamePet(uint32 /*eff_idx*/)
+{
+ if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
+ !((Creature*)unitTarget)->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
+ return;
+
+ unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);
+} \ No newline at end of file
diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp
index efa9c6feebd..ca675dcd931 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,36 +19,40 @@
*/
#include "Common.h"
-#include "Database/DBCStores.h"
+#include "DBCStores.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Log.h"
#include "Opcodes.h"
#include "Spell.h"
-#include "SpellAuras.h"
-#include "BattleGround.h"
-#include "MapManager.h"
#include "ScriptCalls.h"
#include "Totem.h"
#include "TemporarySummon.h"
+#include "SpellAuras.h"
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{
// TODO: add targets.read() check
- CHECK_PACKET_SIZE(recvPacket,1+1+1+1+8);
+ CHECK_PACKET_SIZE(recvPacket,1+1+1+4+8+4+1);
Player* pUser = _player;
+
+ // ignore for remote control state
+ if(pUser->m_mover != pUser)
+ return;
+
uint8 bagIndex, slot;
- uint8 spell_count; // number of spells at item, not used
+ uint8 unk_flags; // flags (if 0x02 - some additional data are received)
uint8 cast_count; // next cast if exists (single or not)
uint64 item_guid;
+ uint32 glyphIndex; // something to do with glyphs?
+ uint32 spellid; // casted spell id
- recvPacket >> bagIndex >> slot >> spell_count >> cast_count >> item_guid;
+ recvPacket >> bagIndex >> slot >> cast_count >> spellid >> item_guid >> glyphIndex >> unk_flags;
- Item *pItem = pUser->GetItemByPos(bagIndex, slot);
+ Item *pItem = pUser->GetUseableItemByPos(bagIndex, slot);
if(!pItem)
{
pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
@@ -61,7 +65,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
return;
}
- sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, spell_count: %u , cast_count: %u, Item: %u, data length = %i", bagIndex, slot, spell_count, cast_count, pItem->GetEntry(), recvPacket.size());
+ sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, cast_count: %u, spellid: %u, Item: %u, glyphIndex: %u, unk_flags: %u, data length = %i", bagIndex, slot, cast_count, spellid, pItem->GetEntry(), glyphIndex, unk_flags, (uint32)recvPacket.size());
ItemPrototype const *proto = pItem->GetProto();
if(!proto)
@@ -95,7 +99,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
if (pUser->isInCombat())
{
- for(int i = 0; i < 5; ++i)
+ for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId))
{
@@ -126,57 +130,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
if(!Script->ItemUse(pUser,pItem,targets))
{
// no script or script not process request by self
-
- // special learning case
- if(pItem->GetProto()->Spells[0].SpellId==SPELL_ID_GENERIC_LEARN)
- {
- uint32 learning_spell_id = pItem->GetProto()->Spells[1].SpellId;
-
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(SPELL_ID_GENERIC_LEARN);
- if(!spellInfo)
- {
- sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, SPELL_ID_GENERIC_LEARN);
- pUser->SendEquipError(EQUIP_ERR_NONE,pItem,NULL);
- return;
- }
-
- Spell *spell = new Spell(pUser, spellInfo, false);
- spell->m_CastItem = pItem;
- spell->m_cast_count = cast_count; //set count of casts
- spell->m_currentBasePoints[0] = learning_spell_id;
- spell->prepare(&targets);
- return;
- }
-
- // use triggered flag only for items with many spell casts and for not first cast
- int count = 0;
-
- for(int i = 0; i < 5; ++i)
- {
- _Spell const& spellData = pItem->GetProto()->Spells[i];
-
- // no spell
- if(!spellData.SpellId)
- continue;
-
- // wrong triggering type
- if( spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
- continue;
-
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellData.SpellId);
- if(!spellInfo)
- {
- sLog.outError("Item (Entry: %u) in have wrong spell id %u, ignoring ",proto->ItemId, spellData.SpellId);
- continue;
- }
-
- Spell *spell = new Spell(pUser, spellInfo, (count > 0));
- spell->m_CastItem = pItem;
- spell->m_cast_count = cast_count; //set count of casts
- spell->prepare(&targets);
-
- ++count;
- }
+ pUser->CastItemUseSpell(pItem,targets,cast_count,glyphIndex);
}
}
@@ -190,9 +144,14 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,1+1);
- sLog.outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i",recvPacket.size());
+ sLog.outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i",(uint32)recvPacket.size());
Player* pUser = _player;
+
+ // ignore for remote control state
+ if(pUser->m_mover != pUser)
+ return;
+
uint8 bagIndex, slot;
recvPacket >> bagIndex >> slot;
@@ -227,7 +186,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
}
// required picklocking
- if(lockInfo->requiredlockskill || lockInfo->requiredminingskill)
+ if(lockInfo->Skill[1] || lockInfo->Skill[0])
{
pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL );
return;
@@ -270,7 +229,12 @@ void WorldSession::HandleGameObjectUseOpcode( WorldPacket & recv_data )
recv_data >> guid;
sLog.outDebug( "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid));
- GameObject *obj = ObjectAccessor::GetGameObject(*_player, guid);
+
+ // ignore for remote control state
+ if(_player->m_mover != _player)
+ return;
+
+ GameObject *obj = GetPlayer()->GetMap()->GetGameObject(guid);
if(!obj)
return;
@@ -281,17 +245,46 @@ void WorldSession::HandleGameObjectUseOpcode( WorldPacket & recv_data )
obj->Use(_player);
}
+void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket)
+{
+ CHECK_PACKET_SIZE(recvPacket,8);
+
+ uint64 guid;
+ recvPacket >> guid;
+
+ sLog.outDebug( "WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [in game guid: %u]", GUID_LOPART(guid));
+
+ // ignore for remote control state
+ if(_player->m_mover != _player)
+ return;
+
+ GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);
+ if(!go)
+ return;
+
+ if(!go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))
+ return;
+
+ _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry());
+}
+
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
{
- CHECK_PACKET_SIZE(recvPacket,4+1+2);
+ CHECK_PACKET_SIZE(recvPacket,1+4+1);
uint32 spellId;
- uint8 cast_count;
- recvPacket >> spellId;
+ uint8 cast_count, unk_flags;
recvPacket >> cast_count;
+ recvPacket >> spellId;
+ recvPacket >> unk_flags; // flags (if 0x02 - some additional data are received)
+
+ // ignore for remote control state (for player case)
+ Unit* mover = _player->m_mover;
+ if(mover != _player && mover->GetTypeId()==TYPEID_PLAYER)
+ return;
- sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u data length = %i",
- spellId, cast_count, recvPacket.size());
+ sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u, unk_flags %u, data length = %i",
+ spellId, cast_count, unk_flags, (uint32)recvPacket.size());
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
@@ -301,11 +294,23 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
return;
}
- // not have spell or spell passive and not casted by client
- if ( !_player->HasSpell (spellId) || IsPassiveSpell(spellId) )
+ if(mover->GetTypeId()==TYPEID_PLAYER)
{
- //cheater? kick? ban?
- return;
+ // not have spell in spellbook or spell passive and not casted by client
+ if (!((Player*)mover)->HasActiveSpell (spellId) || IsPassiveSpell(spellId) )
+ {
+ //cheater? kick? ban?
+ return;
+ }
+ }
+ else
+ {
+ // not have spell in spellbook or spell passive and not casted by client
+ if (!((Creature*)mover)->HasSpell(spellId) || IsPassiveSpell(spellId) )
+ {
+ //cheater? kick? ban?
+ return;
+ }
}
// can't use our own spells when we're in possession of another unit,
@@ -314,7 +319,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
// client provided targets
SpellCastTargets targets;
- if(!targets.read(&recvPacket,_player))
+ if(!targets.read(&recvPacket,mover))
return;
// auto-selection buff level base at target level (in spellInfo)
@@ -327,16 +332,19 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
spellInfo = actualSpellInfo;
}
- Spell *spell = new Spell(_player, spellInfo, false);
+ Spell *spell = new Spell(mover, spellInfo, false);
spell->m_cast_count = cast_count; // set count of casts
spell->prepare(&targets);
}
void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket)
{
- CHECK_PACKET_SIZE(recvPacket,4);
+ CHECK_PACKET_SIZE(recvPacket,5);
+ // increments with every CANCEL packet, don't use for now
+ uint8 counter;
uint32 spellId;
+ recvPacket >> counter;
recvPacket >> spellId;
if(_player->IsNonMeleeSpellCasted(false))
@@ -358,43 +366,18 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL))
return;
- // lifebloom must delete final heal effect
- if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && (spellInfo->SpellFamilyFlags & 0x1000000000LL) )
- {
- Unit::AuraMap::iterator iter;
- while((iter = _player->m_Auras.find(Unit::spellEffectPair(spellId, 1))) != _player->m_Auras.end())
- {
- _player->m_modAuras[SPELL_AURA_DUMMY].remove(iter->second);
-
- Aura* Aur = iter->second;
- _player->m_Auras.erase(iter);
- ++_player->m_removedAuras; // internal count used by unit update
-
- delete Aur;
-
- if( _player->m_Auras.empty() )
- iter = _player->m_Auras.end();
- else
- iter = _player->m_Auras.begin();
-
- }
- }
-
// channeled spell case (it currently casted then)
- if(IsChanneledSpell(spellInfo))
+ if (IsChanneledSpell(spellInfo))
{
- if(Spell* spell = _player->m_currentSpells[CURRENT_CHANNELED_SPELL])
- {
- if(spell->m_spellInfo->Id==spellId)
- {
- spell->cancel();
- }
- }
+ if (_player->m_currentSpells[CURRENT_CHANNELED_SPELL] &&
+ _player->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id==spellId)
+ _player->InterruptSpell(CURRENT_CHANNELED_SPELL);
return;
}
// non channeled case
- _player->RemoveAurasDueToSpellByCancel(spellId);
+ // maybe should only remove one buff when there are multiple?
+ _player->RemoveAurasDueToSpell(spellId, 0, AURA_REMOVE_BY_CANCEL);
}
void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
@@ -414,7 +397,7 @@ void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
return;
}
- Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
+ Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid);
if(!pet)
{
@@ -422,7 +405,7 @@ void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
return;
}
- if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
+ if(pet != GetPlayer()->GetGuardianPet() && pet != GetPlayer()->GetCharm())
{
sLog.outError( "HandlePetCancelAura.Pet %u isn't pet of player %s", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
return;
@@ -466,17 +449,22 @@ void WorldSession::HandleTotemDestroy( WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket, 1);
+ // ignore for remote control state
+ if(_player->m_mover != _player)
+ return;
+
uint8 slotId;
recvPacket >> slotId;
- if (slotId >= MAX_TOTEM)
+ ++slotId;
+ if (slotId >= MAX_TOTEM_SLOT)
return;
- if(!_player->m_TotemSlot[slotId])
+ if(!_player->m_SummonSlot[slotId])
return;
- Creature* totem = ObjectAccessor::GetCreature(*_player,_player->m_TotemSlot[slotId]);
+ Creature* totem = GetPlayer()->GetMap()->GetCreature(_player->m_SummonSlot[slotId]);
// Don't unsummon sentry totem
if(totem && totem->isTotem() && totem->GetEntry() != SENTRY_TOTEM_ENTRY)
((Totem*)totem)->UnSummon();
@@ -496,3 +484,30 @@ void WorldSession::HandleSelfResOpcode( WorldPacket & /*recv_data*/ )
}
}
+void WorldSession::HandleSpellClick( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 guid;
+ recv_data >> guid;
+
+ Creature *unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
+
+ if(!unit)
+ return;
+
+ SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap;
+ for(SpellClickInfoMap::const_iterator itr = map.lower_bound(unit->GetEntry()); itr != map.upper_bound(unit->GetEntry()); ++itr)
+ {
+ if(itr->second.questId == 0 || _player->GetQuestStatus(itr->second.questId) == itr->second.questStatus)
+ {
+ Unit *caster = (itr->second.castFlags & 0x1) ? (Unit*)_player : (Unit*)unit;
+ Unit *target = (itr->second.castFlags & 0x2) ? (Unit*)_player : (Unit*)unit;
+
+ caster->CastSpell(target, itr->second.spellId, true);
+ }
+ }
+
+ if(unit->isVehicle())
+ _player->EnterVehicle((Vehicle*)unit);
+}
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 48bae52983c..67e6380d5ea 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,10 +22,12 @@
#include "ObjectMgr.h"
#include "SpellAuraDefines.h"
#include "ProgressBar.h"
-#include "Database/DBCStores.h"
+#include "DBCStores.h"
#include "World.h"
#include "Chat.h"
#include "Spell.h"
+#include "BattleGroundMgr.h"
+#include "CreatureAI.h"
bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS];
@@ -38,25 +40,17 @@ SpellMgr::SpellMgr()
case SPELL_EFFECT_PERSISTENT_AREA_AURA: //27
case SPELL_EFFECT_SUMMON: //28
case SPELL_EFFECT_TRIGGER_MISSILE: //32
- case SPELL_EFFECT_SUMMON_WILD: //41
- case SPELL_EFFECT_SUMMON_GUARDIAN: //42
case SPELL_EFFECT_TRANS_DOOR: //50 summon object
case SPELL_EFFECT_SUMMON_PET: //56
case SPELL_EFFECT_ADD_FARSIGHT: //72
- case SPELL_EFFECT_SUMMON_POSSESSED: //73
- case SPELL_EFFECT_SUMMON_TOTEM: //74
case SPELL_EFFECT_SUMMON_OBJECT_WILD: //76
- case SPELL_EFFECT_SUMMON_TOTEM_SLOT1: //87
- case SPELL_EFFECT_SUMMON_TOTEM_SLOT2: //88
- case SPELL_EFFECT_SUMMON_TOTEM_SLOT3: //89
- case SPELL_EFFECT_SUMMON_TOTEM_SLOT4: //90
- case SPELL_EFFECT_SUMMON_CRITTER: //97
+ //case SPELL_EFFECT_SUMMON_CRITTER: //97 not 303
case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: //104
case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: //105
case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: //106
case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: //107
case SPELL_EFFECT_SUMMON_DEAD_PET: //109
- case SPELL_EFFECT_SUMMON_DEMON: //112
+ //case SPELL_EFFECT_SUMMON_DEMON: //112 not 303
case SPELL_EFFECT_TRIGGER_SPELL_2: //151 ritual of summon
EffectTargetType[i] = SPELL_REQUIRE_DEST;
break;
@@ -71,8 +65,12 @@ SpellMgr::SpellMgr()
case SPELL_EFFECT_ENCHANT_ITEM:
case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
case SPELL_EFFECT_DISENCHANT:
- case SPELL_EFFECT_FEED_PET:
+ //in 243 this is 0, in 309 it is 1
+ //so both item target and unit target is pushed, and cause crash
+ //case SPELL_EFFECT_FEED_PET:
case SPELL_EFFECT_PROSPECTING:
+ case SPELL_EFFECT_MILLING:
+ case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC:
EffectTargetType[i] = SPELL_REQUIRE_ITEM;
break;
//caster must be pushed otherwise no sound
@@ -81,8 +79,18 @@ SpellMgr::SpellMgr()
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
case SPELL_EFFECT_APPLY_AREA_AURA_PET:
case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
+ case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
+ case SPELL_EFFECT_CHARGE:
+ case SPELL_EFFECT_JUMP:
+ case SPELL_EFFECT_JUMP2:
+ case SPELL_EFFECT_138:
EffectTargetType[i] = SPELL_REQUIRE_CASTER;
break;
+ //case SPELL_EFFECT_WMO_DAMAGE:
+ //case SPELL_EFFECT_WMO_REPAIR:
+ //case SPELL_EFFECT_WMO_CHANGE:
+ // EffectTargetType[i] = SPELL_REQUIRE_GOBJECT;
+ // break;
default:
EffectTargetType[i] = SPELL_REQUIRE_UNIT;
break;
@@ -256,6 +264,21 @@ int32 GetSpellMaxDuration(SpellEntry const *spellInfo)
return (du->Duration[2] == -1) ? -1 : abs(du->Duration[2]);
}
+bool GetDispelChance(Unit* caster, uint32 spellId)
+{
+ // we assume that aura dispel chance is 100% on start
+ // need formula for level difference based chance
+ int32 miss_chance = 0;
+ // Apply dispel mod from aura caster
+ if (caster)
+ {
+ if ( Player* modOwner = caster->GetSpellModOwner() )
+ modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance);
+ }
+ // Try dispel
+ return !roll_chance_i(miss_chance);
+}
+
uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)
{
SpellCastTimesEntry const *spellCastTimeEntry = sSpellCastTimesStore.LookupEntry(spellInfo->CastingTimeIndex);
@@ -266,21 +289,10 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)
int32 castTime = spellCastTimeEntry->CastTime;
- if (spell)
- {
- if(Player* modOwner = spell->GetCaster()->GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
+ if (spell && spell->GetCaster())
+ spell->GetCaster()->ModSpellCastTime(spellInfo, castTime, spell);
- if( !(spellInfo->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) )
- castTime = int32(castTime * spell->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED));
- else
- {
- if (spell->IsRangedSpell() && !spell->IsAutoRepeat())
- castTime = int32(castTime * spell->GetCaster()->m_modAttackSpeedPct[RANGED_ATTACK]);
- }
- }
-
- if (spellInfo->Attributes & SPELL_ATTR_RANGED && (!spell || !(spell->IsAutoRepeat())))
+ if (spellInfo->Attributes & SPELL_ATTR_REQ_AMMO && (!spell || !(spell->IsAutoRepeat())))
castTime += 500;
return (castTime > 0) ? uint32(castTime) : 0;
@@ -294,32 +306,21 @@ bool IsPassiveSpell(uint32 spellId)
return (spellInfo->Attributes & SPELL_ATTR_PASSIVE) != 0;
}
-/*bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2)
+bool IsAutocastableSpell(uint32 spellId)
{
- SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
- SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
- if(!spellInfo_1 || !spellInfo_2) return false;
- if(spellInfo_1->Id == spellId_2) return false;
-
- if (spellInfo_1->Effect[effIndex_1] != spellInfo_2->Effect[effIndex_2] ||
- spellInfo_1->EffectItemType[effIndex_1] != spellInfo_2->EffectItemType[effIndex_2] ||
- spellInfo_1->EffectMiscValue[effIndex_1] != spellInfo_2->EffectMiscValue[effIndex_2] ||
- spellInfo_1->EffectApplyAuraName[effIndex_1] != spellInfo_2->EffectApplyAuraName[effIndex_2])
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
+ if(!spellInfo)
+ return false;
+ if(spellInfo->Attributes & SPELL_ATTR_PASSIVE)
+ return false;
+ if(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET)
return false;
-
return true;
-}*/
+}
-int32 CompareAuraRanks(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2)
+bool IsHigherHankOfSpell(uint32 spellId_1, uint32 spellId_2)
{
- SpellEntry const*spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
- SpellEntry const*spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
- if(!spellInfo_1 || !spellInfo_2) return 0;
- if (spellId_1 == spellId_2) return 0;
-
- int32 diff = spellInfo_1->EffectBasePoints[effIndex_1] - spellInfo_2->EffectBasePoints[effIndex_2];
- if (spellInfo_1->EffectBasePoints[effIndex_1]+1 < 0 && spellInfo_2->EffectBasePoints[effIndex_2]+1 < 0) return -diff;
- else return diff;
+ return spellmgr.GetSpellRank(spellId_1)<spellmgr.GetSpellRank(spellId_2);
}
SpellSpecific GetSpellSpecific(uint32 spellId)
@@ -336,44 +337,55 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
if (spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED)
{
for(int i = 0; i < 3; i++)
- if( spellInfo->EffectApplyAuraName[i]==SPELL_AURA_MOD_POWER_REGEN)
+ if( spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POWER_REGEN
+ || spellInfo->EffectApplyAuraName[i] == SPELL_AURA_OBS_MOD_ENERGY)
return SPELL_DRINK;
- else if ( spellInfo->EffectApplyAuraName[i]==SPELL_AURA_MOD_REGEN)
+ else if ( spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_REGEN
+ || spellInfo->EffectApplyAuraName[i] == SPELL_AURA_OBS_MOD_HEALTH)
return SPELL_FOOD;
}
// this may be a hack
else if((spellInfo->AttributesEx2 & SPELL_ATTR_EX2_FOOD)
&& !spellInfo->Category)
return SPELL_WELL_FED;
-
- switch(spellInfo->Id)
- {
- case 12880: // warrior's Enrage rank 1
- case 14201: // Enrage rank 2
- case 14202: // Enrage rank 3
- case 14203: // Enrage rank 4
- case 14204: // Enrage rank 5
- case 12292: // Death Wish
- return SPELL_WARRIOR_ENRAGE;
- break;
- default: break;
- }
+ // scrolls effects
+ else
+ {
+ uint32 firstSpell = spellmgr.GetFirstSpellInChain(spellInfo->Id);
+ switch (firstSpell)
+ {
+ case 8118: // Strength
+ case 8099: // Stamina
+ case 8112: // Spirit
+ case 8096: // Intellect
+ case 8115: // Agility
+ case 8091: // Armor
+ return SPELL_SCROLL;
+ case 12880: // Enrage
+ case 12292: // Death Wish
+ return SPELL_WARRIOR_ENRAGE;
+ }
+ }
break;
}
case SPELLFAMILY_MAGE:
{
// family flags 18(Molten), 25(Frost/Ice), 28(Mage)
- if (spellInfo->SpellFamilyFlags & 0x12040000)
+ if (spellInfo->SpellFamilyFlags[0] & 0x12040000)
return SPELL_MAGE_ARMOR;
- if ((spellInfo->SpellFamilyFlags & 0x1000000) && spellInfo->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE)
+ // Arcane brillance and Arcane intelect (normal check fails because of flags difference)
+ if (spellInfo->SpellFamilyFlags[0] & 0x400)
+ return SPELL_MAGE_ARCANE_BRILLANCE;
+
+ if ((spellInfo->SpellFamilyFlags[0] & 0x1000000) && spellInfo->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE)
return SPELL_MAGE_POLYMORPH;
break;
}
case SPELLFAMILY_WARRIOR:
{
- if (spellInfo->SpellFamilyFlags & 0x00008000010000LL)
+ if (spellInfo->SpellFamilyFlags[1] & 0x000080 || spellInfo->SpellFamilyFlags[0] & 0x10000LL)
return SPELL_POSITIVE_SHOUT;
break;
@@ -384,12 +396,12 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
if (spellInfo->Dispel == DISPEL_CURSE)
return SPELL_CURSE;
- // family flag 37 (only part spells have family name)
- if (spellInfo->SpellFamilyFlags & 0x2000000000LL)
+ // Warlock (Demon Armor | Demon Skin | Fel Armor)
+ if (spellInfo->SpellFamilyFlags[1] & 0x20000020 || spellInfo->SpellFamilyFlags[2] & 0x00000010)
return SPELL_WARLOCK_ARMOR;
//seed of corruption and corruption
- if (spellInfo->SpellFamilyFlags & 0x1000000002LL)
+ if (spellInfo->SpellFamilyFlags[1] & 0x10 || spellInfo->SpellFamilyFlags[0] & 0x2)
return SPELL_WARLOCK_CORRUPTION;
break;
}
@@ -399,6 +411,10 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
if (spellInfo->Dispel == DISPEL_POISON)
return SPELL_STING;
+ // only hunter aspects have this
+ if( spellInfo->SpellFamilyFlags[1] & 0x00440000 || spellInfo->SpellFamilyFlags[0] & 0x00380000 || spellInfo->SpellFamilyFlags[2] & 0x00001010)
+ return SPELL_ASPECT;
+
break;
}
case SPELLFAMILY_PALADIN:
@@ -406,16 +422,16 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
if (IsSealSpell(spellInfo))
return SPELL_SEAL;
- if (spellInfo->SpellFamilyFlags & 0x10000100LL)
+ if (spellInfo->SpellFamilyFlags[0] & 0x11010002)
return SPELL_BLESSING;
- if ((spellInfo->SpellFamilyFlags & 0x00000820180400LL) && (spellInfo->AttributesEx3 & 0x200))
+ if ((spellInfo->SpellFamilyFlags[1] & 0x000008 || spellInfo->SpellFamilyFlags[0] & 0x20180400) && (spellInfo->AttributesEx3 & 0x200))
return SPELL_JUDGEMENT;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 3; ++i)
{
- // only paladin auras have this
- if (spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
+ // only paladin auras have this (for palaldin class family)
+ if (spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID)
return SPELL_AURA;
}
break;
@@ -430,19 +446,11 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
case SPELLFAMILY_POTION:
return spellmgr.GetSpellElixirSpecific(spellInfo->Id);
- }
-
- // only warlock armor/skin have this (in additional to family cases)
- if( spellInfo->SpellVisual == 130 && spellInfo->SpellIconID == 89)
- {
- return SPELL_WARLOCK_ARMOR;
- }
- // only hunter aspects have this (but not all aspects in hunter family)
- if( spellInfo->activeIconID == 122 && (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NATURE) &&
- (spellInfo->Attributes & 0x50000) != 0 && (spellInfo->Attributes & 0x9000010) == 0)
- {
- return SPELL_ASPECT;
+ case SPELLFAMILY_DEATHKNIGHT:
+ if ((spellInfo->Attributes & 0x10) && (spellInfo->AttributesEx2 & 0x10) && (spellInfo->AttributesEx4 & 0x200000))
+ return SPELL_PRESENCE;
+ break;
}
for(int i = 0; i < 3; ++i)
@@ -451,18 +459,17 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
{
switch(spellInfo->EffectApplyAuraName[i])
{
- case SPELL_AURA_TRACK_CREATURES:
- case SPELL_AURA_TRACK_RESOURCES:
- case SPELL_AURA_TRACK_STEALTHED:
- return SPELL_TRACKER;
case SPELL_AURA_MOD_CHARM:
case SPELL_AURA_MOD_POSSESS_PET:
case SPELL_AURA_MOD_POSSESS:
return SPELL_CHARM;
+ case SPELL_AURA_TRACK_CREATURES:
+ case SPELL_AURA_TRACK_RESOURCES:
+ case SPELL_AURA_TRACK_STEALTHED:
+ return SPELL_TRACKER;
}
}
}
-
// elixirs can have different families, but potion most ofc.
if(SpellSpecific sp = spellmgr.GetSpellElixirSpecific(spellInfo->Id))
return sp;
@@ -498,11 +505,14 @@ bool IsSingleFromSpellSpecificPerTarget(uint32 spellSpec1,uint32 spellSpec2)
case SPELL_MAGE_ARMOR:
case SPELL_ELEMENTAL_SHIELD:
case SPELL_MAGE_POLYMORPH:
+ case SPELL_PRESENCE:
case SPELL_WELL_FED:
case SPELL_DRINK:
case SPELL_FOOD:
case SPELL_CHARM:
- case SPELL_WARRIOR_ENRAGE:
+ case SPELL_SCROLL:
+ case SPELL_WARRIOR_ENRAGE:
+ case SPELL_MAGE_ARCANE_BRILLANCE:
return spellSpec1==spellSpec2;
case SPELL_BATTLE_ELIXIR:
return spellSpec2==SPELL_BATTLE_ELIXIR
@@ -532,8 +542,6 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB)
case TARGET_DST_TARGET_ENEMY:
case TARGET_UNIT_CHANNEL:
return false;
- case TARGET_SRC_CASTER:
- return (targetB == TARGET_UNIT_AREA_PARTY_SRC || targetB == TARGET_UNIT_AREA_ALLY_SRC);
default:
break;
}
@@ -542,27 +550,31 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB)
return true;
}
-bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
+bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep)
{
SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
if (!spellproto) return false;
switch(spellId)
{
- case 23333: // BG spell
- case 23335: // BG spell
- case 34976: // BG spell
- case 31579: // Arcane Empowerment Rank1 talent aura with one positive and one negative (check not needed in wotlk)
- case 31582: // Arcane Empowerment Rank2
- case 31583: // Arcane Empowerment Rank3
- return true;
case 28441: // not positive dummy spell
case 37675: // Chaos Blast
case 41519: // Mark of Stormrage
case 34877: // Custodian of Time
case 34700: // Allergic Reaction
case 31719: // Suspension
+ case 61987: // Avenging Wrath Marker
return false;
+ case 12042: // Arcane Power
+ return true;
+ }
+
+ switch(spellproto->Mechanic)
+ {
+ case MECHANIC_IMMUNE_SHIELD:
+ return true;
+ default:
+ break;
}
switch(spellproto->Effect[effIndex])
@@ -588,6 +600,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
{
case 13139: // net-o-matic special effect
case 23445: // evil twin
+ case 35679: // Protectorate Demolitionist
case 38637: // Nether Exhaustion (red)
case 38638: // Nether Exhaustion (green)
case 38639: // Nether Exhaustion (blue)
@@ -599,15 +612,17 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
case SPELL_AURA_MOD_STAT:
case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from bas point sign (negative -> negative)
case SPELL_AURA_MOD_HEALING_DONE:
+ case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
{
- if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
+ if(spellproto->CalculateSimpleValue(effIndex) < 0)
return false;
break;
}
case SPELL_AURA_ADD_TARGET_TRIGGER:
return true;
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
- if(spellId != spellproto->EffectTriggerSpell[effIndex])
+ if(!deep)
{
uint32 spellTriggeredId = spellproto->EffectTriggerSpell[effIndex];
SpellEntry const *spellTriggeredProto = sSpellStore.LookupEntry(spellTriggeredId);
@@ -617,14 +632,15 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
// non-positive targets of main spell return early
for(int i = 0; i < 3; ++i)
{
+ if (!spellTriggeredProto->Effect[i])
+ continue;
// if non-positive trigger cast targeted to positive target this main cast is non-positive
// this will place this spell auras as debuffs
- if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !IsPositiveEffect(spellTriggeredId,i))
+ if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !IsPositiveEffect(spellTriggeredId,i, true))
return false;
}
}
}
- break;
case SPELL_AURA_PROC_TRIGGER_SPELL:
// many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example)
break;
@@ -698,19 +714,35 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
switch(spellproto->EffectMiscValue[effIndex])
{
case SPELLMOD_COST: // dependent from bas point sign (negative -> positive)
- if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) > 0)
- return false;
+ if(spellproto->CalculateSimpleValue(effIndex) > 0)
+ {
+ if (!deep)
+ {
+ bool negative = true;
+ for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i)
+ {
+ if (i != effIndex)
+ if (IsPositiveEffect(spellId, i, true))
+ {
+ negative = false;
+ break;
+ }
+ }
+ if (negative)
+ return false;
+ }
+ }
break;
default:
break;
}
} break;
case SPELL_AURA_MOD_HEALING_PCT:
- if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
+ if(spellproto->CalculateSimpleValue(effIndex) < 0)
return false;
break;
case SPELL_AURA_MOD_SKILL:
- if(spellproto->EffectBasePoints[effIndex]+int32(spellproto->EffectBaseDice[effIndex]) < 0)
+ if(spellproto->CalculateSimpleValue(effIndex) < 0)
return false;
break;
case SPELL_AURA_FORCE_REACTION:
@@ -734,19 +766,25 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
if(spellproto->AttributesEx & SPELL_ATTR_EX_NEGATIVE)
return false;
+ if (!deep && spellproto->EffectTriggerSpell[effIndex]
+ && !spellproto->EffectApplyAuraName[effIndex]
+ && IsPositiveTarget(spellproto->EffectImplicitTargetA[effIndex],spellproto->EffectImplicitTargetB[effIndex])
+ && !IsPositiveSpell(spellproto->EffectTriggerSpell[effIndex], true))
+ return false;
+
// ok, positive
return true;
}
-bool IsPositiveSpell(uint32 spellId)
+bool IsPositiveSpell(uint32 spellId, bool deep)
{
SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
if (!spellproto) return false;
// spells with at least one negative effect are considered negative
// some self-applied spells have negative effects but in self casting case negative check ignored.
- for (int i = 0; i < 3; i++)
- if (!IsPositiveEffect(spellId, i))
+ for (int i = 0; i < 3; ++i)
+ if (!IsPositiveEffect(spellId, i, deep))
return false;
return true;
}
@@ -762,6 +800,8 @@ bool IsSingleTargetSpell(SpellEntry const *spellInfo)
{
case SPELL_JUDGEMENT:
return true;
+ default:
+ break;
}
// single target triggered spell.
@@ -791,6 +831,8 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI
if(GetSpellSpecific(spellInfo2->Id) == spec1)
return true;
break;
+ default:
+ break;
}
return false;
@@ -801,19 +843,19 @@ bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId)
SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
if (!spellproto) return false;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 3; ++i)
if (spellproto->EffectApplyAuraName[i] == auraType)
return true;
return false;
}
-uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
+SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
{
// talents that learn spells can have stance requirements that need ignore
// (this requirement only for client-side stance show in talent description)
if( GetTalentSpellCost(spellInfo->Id) > 0 &&
(spellInfo->Effect[0]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[1]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[2]==SPELL_EFFECT_LEARN_SPELL) )
- return 0;
+ return SPELL_CAST_OK;
uint32 stanceMask = (form ? 1 << (form - 1) : 0);
@@ -821,7 +863,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
return SPELL_FAILED_NOT_SHAPESHIFT;
if (stanceMask & spellInfo->Stances) // can explicitly be casted in this stance
- return 0;
+ return SPELL_CAST_OK;
bool actAsShifted = false;
if (form > 0)
@@ -830,7 +872,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
if (!shapeInfo)
{
sLog.outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form);
- return 0;
+ return SPELL_CAST_OK;
}
actAsShifted = !(shapeInfo->flags1 & 1); // shapeshift acts as normal form for spells
}
@@ -849,7 +891,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
return SPELL_FAILED_ONLY_SHAPESHIFT;
}
- return 0;
+ return SPELL_CAST_OK;
}
void SpellMgr::LoadSpellTargetPositions()
@@ -943,8 +985,8 @@ void SpellMgr::LoadSpellAffects()
uint32 count = 0;
- // 0 1 2
- QueryResult *result = WorldDatabase.Query("SELECT entry, effectId, SpellFamilyMask FROM spell_affect");
+ // 0 1 2 3 4
+ QueryResult *result = WorldDatabase.Query("SELECT entry, effectId, SpellClassMask0, SpellClassMask1, SpellClassMask2 FROM spell_affect");
if( !result )
{
@@ -991,26 +1033,22 @@ void SpellMgr::LoadSpellAffects()
continue;
}
- uint64 spellAffectMask = fields[2].GetUInt64();
+ flag96 affect(fields[2].GetUInt32(), fields[3].GetUInt32(), fields[4].GetUInt32());
- // Spell.dbc have own data for low part of SpellFamilyMask
- if( spellInfo->EffectItemType[effectId])
- {
- if(spellInfo->EffectItemType[effectId] == spellAffectMask)
- {
- sLog.outErrorDb("Spell %u listed in `spell_affect` have redundant (same with EffectItemType%d) data for effect index (%u) and not needed, skipped.", entry,effectId+1,effectId);
- continue;
- }
+ // Spell.dbc have own data
+ if (effectId>3)
+ continue;
- // 24429 have wrong data in EffectItemType and overwrites by DB, possible bug in client
- if(spellInfo->Id!=24429 && spellInfo->EffectItemType[effectId] != spellAffectMask)
- {
- sLog.outErrorDb("Spell %u listed in `spell_affect` have different low part from EffectItemType%d for effect index (%u) and not needed, skipped.", entry,effectId+1,effectId);
- continue;
- }
+ flag96 dbc_affect;
+ dbc_affect = spellInfo->EffectSpellClassMask[effectId];
+ if(dbc_affect[0] == affect[0] || dbc_affect[1] == affect[1] || dbc_affect[2] == affect[2])
+ {
+ char text[]="ABC";
+ sLog.outErrorDb("Spell %u listed in `spell_affect` have redundant (same with EffectSpellClassMask%c) data for effect index (%u) and not needed, skipped.", entry, text[effectId], effectId);
+ continue;
}
- mSpellAffectMap.insert(SpellAffectMap::value_type((entry<<8) + effectId,spellAffectMask));
+ mSpellAffectMap[(entry<<8) + effectId] = affect;
++count;
} while( result->NextRow() );
@@ -1018,7 +1056,7 @@ void SpellMgr::LoadSpellAffects()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u spell affect definitions", count );
+ sLog.outString( ">> Loaded %u custom spell affect definitions", count );
for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id)
{
@@ -1034,7 +1072,9 @@ void SpellMgr::LoadSpellAffects()
spellInfo->EffectApplyAuraName[effectId] != SPELL_AURA_ADD_TARGET_TRIGGER) )
continue;
- if(spellInfo->EffectItemType[effectId] != 0)
+ flag96 dbc_affect;
+ dbc_affect = spellInfo->EffectSpellClassMask[effectId];
+ if(dbc_affect)
continue;
if(mSpellAffectMap.find((id<<8) + effectId) != mSpellAffectMap.end())
@@ -1045,33 +1085,19 @@ void SpellMgr::LoadSpellAffects()
}
}
-bool SpellMgr::IsAffectedBySpell(SpellEntry const *spellInfo, uint32 spellId, uint8 effectId, uint64 familyFlags) const
+bool SpellMgr::IsAffectedByMod(SpellEntry const *spellInfo, SpellModifier *mod) const
{
// false for spellInfo == NULL
- if (!spellInfo)
+ if (!spellInfo || !mod)
return false;
- SpellEntry const *affect_spell = sSpellStore.LookupEntry(spellId);
- // false for affect_spell == NULL
- if (!affect_spell)
+ SpellEntry const *affect_spell = sSpellStore.LookupEntry(mod->spellId);
+ // False if affect_spell == NULL or spellFamily not equal
+ if (!affect_spell || affect_spell->SpellFamilyName != spellInfo->SpellFamilyName)
return false;
- // False if spellFamily not equal
- if (affect_spell->SpellFamilyName != spellInfo->SpellFamilyName)
- return false;
-
- // If familyFlags == 0
- if (!familyFlags)
- {
- // Get it from spellAffect table
- familyFlags = GetSpellAffectMask(spellId,effectId);
- // false if familyFlags == 0
- if (!familyFlags)
- return false;
- }
-
// true
- if (familyFlags & spellInfo->SpellFamilyFlags)
+ if (mod->mask & spellInfo->SpellFamilyFlags)
return true;
return false;
@@ -1083,15 +1109,12 @@ void SpellMgr::LoadSpellProcEvents()
uint32 count = 0;
- // 0 1 2 3 4 5 6 7 8
- QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
+ // 0 1 2 3 4 5 6 7 8 9 10
+ QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
if( !result )
{
-
barGoLink bar( 1 );
-
bar.step();
-
sLog.outString();
sLog.outString( ">> Loaded %u spell proc event conditions", count );
return;
@@ -1105,7 +1128,7 @@ void SpellMgr::LoadSpellProcEvents()
bar.step();
- uint16 entry = fields[0].GetUInt16();
+ uint32 entry = fields[0].GetUInt32();
const SpellEntry *spell = sSpellStore.LookupEntry(entry);
if (!spell)
@@ -1118,12 +1141,14 @@ void SpellMgr::LoadSpellProcEvents()
spe.schoolMask = fields[1].GetUInt32();
spe.spellFamilyName = fields[2].GetUInt32();
- spe.spellFamilyMask = fields[3].GetUInt64();
- spe.procFlags = fields[4].GetUInt32();
- spe.procEx = fields[5].GetUInt32();
- spe.ppmRate = fields[6].GetFloat();
- spe.customChance = fields[7].GetFloat();
- spe.cooldown = fields[8].GetUInt32();
+ spe.spellFamilyMask[0] = fields[3].GetUInt32();
+ spe.spellFamilyMask[1] = fields[4].GetUInt32();
+ spe.spellFamilyMask[2] = fields[5].GetUInt32();
+ spe.procFlags = fields[6].GetUInt32();
+ spe.procEx = fields[7].GetUInt32();
+ spe.ppmRate = fields[8].GetFloat();
+ spe.customChance = fields[9].GetFloat();
+ spe.cooldown = fields[10].GetUInt32();
mSpellProcEventMap[entry] = spe;
@@ -1143,82 +1168,56 @@ void SpellMgr::LoadSpellProcEvents()
sLog.outString();
if (customProc)
- sLog.outString( ">> Loaded %u custom spell proc event conditions +%u custom", count, customProc );
+ sLog.outString( ">> Loaded %u extra spell proc event conditions +%u custom", count, customProc );
else
- sLog.outString( ">> Loaded %u spell proc event conditions", count );
+ sLog.outString( ">> Loaded %u extra spell proc event conditions", count );
+}
- /*
- // Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event)
- for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id)
+void SpellMgr::LoadSpellBonusess()
+{
+ mSpellBonusMap.clear(); // need for reload case
+ uint32 count = 0;
+ // 0 1 2 3
+ QueryResult *result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus FROM spell_bonus_data");
+ if( !result )
{
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
- if (!spellInfo)
- continue;
-
- bool found = false;
- for (int effectId = 0; effectId < 3; ++effectId)
- {
- // at this moment check only SPELL_AURA_PROC_TRIGGER_SPELL
- if( spellInfo->EffectApplyAuraName[effectId] == SPELL_AURA_PROC_TRIGGER_SPELL )
- {
- found = true;
- break;
- }
- }
+ barGoLink bar( 1 );
+ bar.step();
+ sLog.outString();
+ sLog.outString( ">> Loaded %u spell bonus data", count);
+ return;
+ }
- if(!found)
- continue;
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+ uint32 entry = fields[0].GetUInt32();
- if(GetSpellProcEvent(id))
+ const SpellEntry *spell = sSpellStore.LookupEntry(entry);
+ if (!spell)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry);
continue;
+ }
- sLog.outErrorDb("Spell %u (%s) misses spell_proc_event",id,spellInfo->SpellName[sWorld.GetDBClang()]);
- }
- */
-}
+ SpellBonusEntry sbe;
-/*
-bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags )
-{
- if((procFlags & spellProcEvent->procFlags) == 0)
- return false;
-
- // Additional checks in case spell cast/hit/crit is the event
- // Check (if set) school, category, skill line, spell talent mask
- if(spellProcEvent->schoolMask && (!procSpell || (GetSpellSchoolMask(procSpell) & spellProcEvent->schoolMask) == 0))
- return false;
- if(spellProcEvent->category && (!procSpell || procSpell->Category != spellProcEvent->category))
- return false;
- if(spellProcEvent->skillId)
- {
- if (!procSpell)
- return false;
+ sbe.direct_damage = fields[1].GetFloat();
+ sbe.dot_damage = fields[2].GetFloat();
+ sbe.ap_bonus = fields[3].GetFloat();
- SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(procSpell->Id);
- SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(procSpell->Id);
+ mSpellBonusMap[entry] = sbe;
+ } while( result->NextRow() );
- bool found = false;
- for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
- {
- if(_spell_idx->second->skillId == spellProcEvent->skillId)
- {
- found = true;
- break;
- }
- }
- if (!found)
- return false;
- }
- if(spellProcEvent->spellFamilyName && (!procSpell || spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
- return false;
- if(spellProcEvent->spellFamilyMask && (!procSpell || (spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0))
- return false;
+ delete result;
- return true;
+ sLog.outString();
+ sLog.outString( ">> Loaded %u extra spell bonus data", count);
}
-*/
-bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active)
+bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active)
{
// No extra req need
uint32 procEvent_procEx = PROC_EX_NONE;
@@ -1227,6 +1226,8 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellP
if((procFlags & EventProcFlag) == 0)
return false;
+ bool hasFamilyMask = false;
+
/* Check Periodic Auras
* Both hots and dots can trigger if spell has no PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL
@@ -1263,9 +1264,8 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellP
}
// Always trigger for this
- if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL_AND_GET_XP))
+ if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_ON_TRAP_ACTIVATION))
return true;
-
if (spellProcEvent) // Exist event data
{
// Store extra req
@@ -1291,12 +1291,20 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellP
// spellFamilyName is Ok need check for spellFamilyMask if present
if(spellProcEvent->spellFamilyMask)
{
- if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0)
+ if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags ) == 0)
return false;
active = true; // Spell added manualy -> so its active spell
+ hasFamilyMask = true;
}
}
}
+
+ if (procExtra & PROC_EX_INTERNAL_REQ_FAMILY)
+ {
+ if (!hasFamilyMask)
+ return false;
+ }
+
// Check for extra req (if none) and hit/crit
if (procEvent_procEx == PROC_EX_NONE)
{
@@ -1307,7 +1315,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellP
else // Passive spells hits here only if resist/reflect/immune/evade
{
// Exist req for PROC_EX_EX_TRIGGER_ALWAYS
- if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
+ if ((procExtra & AURA_SPELL_PROC_EX_MASK) && (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS))
return true;
// Passive spells can`t trigger if need hit
if ((procEvent_procEx & PROC_EX_NORMAL_HIT) && !active)
@@ -1379,58 +1387,6 @@ void SpellMgr::LoadSpellThreats()
sLog.outString();
}
-void SpellMgr::LoadSpellEnchantProcData()
-{
- mSpellEnchantProcEventMap.clear(); // need for reload case
-
- uint32 count = 0;
-
- // 0 1 2 3
- QueryResult *result = WorldDatabase.Query("SELECT entry, customChance, PPMChance, procEx FROM spell_enchant_proc_data");
- if( !result )
- {
-
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u spell enchant proc event conditions", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
- do
- {
- Field *fields = result->Fetch();
-
- bar.step();
-
- uint32 enchantId = fields[0].GetUInt32();
-
- SpellItemEnchantmentEntry const *ench = sSpellItemEnchantmentStore.LookupEntry(enchantId);
- if (!ench)
- {
- sLog.outErrorDb("Enchancment %u listed in `spell_enchant_proc_data` does not exist", enchantId);
- continue;
- }
-
- SpellEnchantProcEntry spe;
-
- spe.customChance = fields[1].GetUInt32();
- spe.PPMChance = fields[2].GetFloat();
- spe.procEx = fields[3].GetUInt32();
-
- mSpellEnchantProcEventMap[enchantId] = spe;
-
- ++count;
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString( ">> Loaded %u enchant proc data definitions", count);
-}
-
bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const
{
SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
@@ -1442,113 +1398,57 @@ bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellI
bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo)
{
+ if(IsPassiveSpell(spellInfo->Id)) // ranked passive spell
+ return false;
if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH)
return false;
- if(IsProfessionSpell(spellInfo->Id))
+ if(IsProfessionOrRidingSpell(spellInfo->Id))
+ return false;
+
+ if(spellmgr.IsSkillBonusSpell(spellInfo->Id))
return false;
// All stance spells. if any better way, change it.
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 3; ++i)
{
- // Paladin aura Spell
- if(spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN
- && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
- return false;
- // Druid form Spell
- if(spellInfo->SpellFamilyName == SPELLFAMILY_DRUID
- && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA
- && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
- return false;
- // Rogue Stealth
- if(spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE
- && spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA
- && spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
- return false;
+ switch(spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_PALADIN:
+ // Paladin aura Spell
+ if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_RAID)
+ return false;
+ break;
+ case SPELLFAMILY_DRUID:
+ // Druid form Spell
+ if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA &&
+ spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
+ return false;
+ break;
+ case SPELLFAMILY_ROGUE:
+ // Rogue Stealth
+ if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA &&
+ spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
+ return false;
+ }
}
return true;
}
-bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool sameCaster) const
-{
- //if(spellId_1 == spellId_2) // auras due to the same spell
- // return false;
- SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
- SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
- if(!spellInfo_1 || !spellInfo_2)
- return false;
-
- SpellSpecific spellId_spec_1 = GetSpellSpecific(spellId_1);
- SpellSpecific spellId_spec_2 = GetSpellSpecific(spellId_2);
- if (spellId_spec_1 && spellId_spec_2)
- if (IsSingleFromSpellSpecificPerTarget(spellId_spec_1, spellId_spec_2)
- ||(IsSingleFromSpellSpecificPerCaster(spellId_spec_1, spellId_spec_2) && sameCaster))
- return true;
-
- // spells with different specific always stack
- if(spellId_spec_1 != spellId_spec_2)
+bool SpellMgr::IsProfessionOrRidingSpell(uint32 spellId)
+{
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
+ if(!spellInfo)
return false;
- if(spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
+ if(spellInfo->Effect[1] != SPELL_EFFECT_SKILL)
return false;
- // generic spells
- if(!spellInfo_1->SpellFamilyName)
- {
- if(!spellInfo_1->SpellIconID
- || spellInfo_1->SpellIconID == 1
- || spellInfo_1->SpellIconID != spellInfo_2->SpellIconID)
- return false;
- }
-
- // check for class spells
- else
- {
- if (spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags)
- return false;
- }
-
- if(!sameCaster)
- {
- for(uint32 i = 0; i < 3; ++i)
- if (spellInfo_1->Effect[i] == SPELL_EFFECT_APPLY_AURA
- || spellInfo_1->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
- // not area auras (shaman totem)
- switch(spellInfo_1->EffectApplyAuraName[i])
- {
- // DOT or HOT from different casters will stack
- case SPELL_AURA_PERIODIC_DAMAGE:
- case SPELL_AURA_PERIODIC_HEAL:
- case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
- case SPELL_AURA_PERIODIC_ENERGIZE:
- case SPELL_AURA_PERIODIC_MANA_LEECH:
- case SPELL_AURA_PERIODIC_LEECH:
- case SPELL_AURA_POWER_BURN_MANA:
- case SPELL_AURA_OBS_MOD_MANA:
- case SPELL_AURA_OBS_MOD_HEALTH:
- return false;
- default:
- break;
- }
- }
-
-// not needed now because we compare effects last rank of spells
-// if(spellInfo_1->SpellFamilyName && IsRankSpellDueToSpell(spellInfo_1, spellId_2))
-// return true;
-
- //use data of highest rank spell(needed for spells which ranks have different effects)
- spellInfo_1=sSpellStore.LookupEntry(GetLastSpellInChain(spellId_1));
- spellInfo_2=sSpellStore.LookupEntry(GetLastSpellInChain(spellId_2));
-
- //if spells have exactly the same effect they cannot stack
- for(uint32 i = 0; i < 3; ++i)
- if(spellInfo_1->Effect[i] != spellInfo_2->Effect[i]
- || spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i]
- || spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i]) // paladin resist aura
- return false; // need itemtype check? need an example to add that check
+ uint32 skill = spellInfo->EffectMiscValue[1];
- return true;
+ return IsProfessionOrRidingSkill(skill);
}
+
bool SpellMgr::IsProfessionSpell(uint32 spellId)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
@@ -1582,6 +1482,24 @@ bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const
return IsPrimaryProfessionSpell(spellId) && GetSpellRank(spellId)==1;
}
+bool SpellMgr::IsSkillBonusSpell(uint32 spellId) const
+{
+ SkillLineAbilityMap::const_iterator lower = GetBeginSkillLineAbilityMap(spellId);
+ SkillLineAbilityMap::const_iterator upper = GetEndSkillLineAbilityMap(spellId);
+
+ for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
+ {
+ SkillLineAbilityEntry const *pAbility = _spell_idx->second;
+ if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL)
+ continue;
+
+ if(pAbility->req_skill_value > 0)
+ return true;
+ }
+
+ return false;
+}
+
SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const
{
// ignore passive spells
@@ -1589,11 +1507,12 @@ SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spell
return spellInfo;
bool needRankSelection = false;
- for(int i=0;i<3;i++)
+ for(int i=0;i<3;++i)
{
if( IsPositiveEffect(spellInfo->Id, i) && (
spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA ||
- spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY
+ spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY ||
+ spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID
) )
{
needRankSelection = true;
@@ -1622,265 +1541,6 @@ SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spell
return NULL;
}
-void SpellMgr::LoadSpellRequired()
-{
- mSpellsReqSpell.clear(); // need for reload case
- mSpellReq.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT spell_id, req_spell from spell_required");
-
- if(result == NULL)
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded 0 spell required records" );
- sLog.outErrorDb("`spell_required` table is empty!");
- return;
- }
- uint32 rows = 0;
-
- barGoLink bar( result->GetRowCount() );
- do
- {
- bar.step();
- Field *fields = result->Fetch();
-
- uint32 spell_id = fields[0].GetUInt32();
- uint32 spell_req = fields[1].GetUInt32();
-
- mSpellsReqSpell.insert (std::pair<uint32, uint32>(spell_req, spell_id));
- mSpellReq[spell_id] = spell_req;
- ++rows;
- } while( result->NextRow() );
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u spell required records", rows );
-}
-
-struct SpellRankEntry
-{
- uint32 SkillId;
- char const *SpellName;
- uint32 DurationIndex;
- uint32 RangeIndex;
- uint32 SpellVisual;
- uint32 ProcFlags;
- uint64 SpellFamilyFlags;
- uint32 TargetAuraState;
- uint32 ManaCost;
-
- bool operator()(const SpellRankEntry & _Left,const SpellRankEntry & _Right)const
- {
- return (_Left.SkillId != _Right.SkillId ? _Left.SkillId < _Right.SkillId
- : _Left.SpellName!=_Right.SpellName ? _Left.SpellName < _Right.SpellName
- : _Left.ProcFlags!=_Right.ProcFlags ? _Left.ProcFlags < _Right.ProcFlags
- : _Left.SpellFamilyFlags!=_Right.SpellFamilyFlags ? _Left.SpellFamilyFlags < _Right.SpellFamilyFlags
- : (_Left.SpellVisual!=_Right.SpellVisual) && (!_Left.SpellVisual || !_Right.SpellVisual) ? _Left.SpellVisual < _Right.SpellVisual
- : (_Left.ManaCost!=_Right.ManaCost) && (!_Left.ManaCost || !_Right.ManaCost) ? _Left.ManaCost < _Right.ManaCost
- : (_Left.DurationIndex!=_Right.DurationIndex) && (!_Left.DurationIndex || !_Right.DurationIndex)? _Left.DurationIndex < _Right.DurationIndex
- : (_Left.RangeIndex!=_Right.RangeIndex) && (!_Left.RangeIndex || !_Right.RangeIndex || _Left.RangeIndex==1 || !_Right.RangeIndex==1) ? _Left.RangeIndex < _Right.RangeIndex
- : _Left.TargetAuraState < _Right.TargetAuraState
- );
- }
-};
-
-struct SpellRankValue
-{
- uint32 Id;
- char const *Rank;
-};
-
-void SpellMgr::LoadSpellChains()
-{
- mSpellChains.clear(); // need for reload case
-
- std::vector<uint32> ChainedSpells;
- for (uint32 ability_id=0;ability_id<sSkillLineAbilityStore.GetNumRows();ability_id++)
- {
- SkillLineAbilityEntry const *AbilityInfo=sSkillLineAbilityStore.LookupEntry(ability_id);
- if (!AbilityInfo)
- continue;
- if (AbilityInfo->spellId==20154) //exception to these rules (not needed in 3.0.3)
- continue;
- if (!AbilityInfo->forward_spellid)
- continue;
- ChainedSpells.push_back(AbilityInfo->forward_spellid);
- }
-
- std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry> RankMap;
-
- for (uint32 ability_id=0;ability_id<sSkillLineAbilityStore.GetNumRows();ability_id++)
- {
- SkillLineAbilityEntry const *AbilityInfo=sSkillLineAbilityStore.LookupEntry(ability_id);
- if (!AbilityInfo)
- continue;
-
- //get only spell with lowest ability_id to prevent doubles
- uint32 spell_id=AbilityInfo->spellId;
- if (spell_id==20154) //exception to these rules (not needed in 3.0.3)
- continue;
- bool found=false;
- for (uint32 i=0; i<ChainedSpells.size(); i++)
- {
- if (ChainedSpells.at(i)==spell_id)
- found=true;
- }
- if (found)
- continue;
-
- if(mSkillLineAbilityMap.lower_bound(spell_id)->second->id!=ability_id)
- continue;
- SpellEntry const *SpellInfo=sSpellStore.LookupEntry(spell_id);
- if (!SpellInfo)
- continue;
- std::string sRank = SpellInfo->Rank[sWorld.GetDefaultDbcLocale()];
- if(sRank.empty())
- continue;
- //exception to polymorph spells-make pig and turtle other chain than sheep
- if ((SpellInfo->SpellFamilyName==SPELLFAMILY_MAGE) && (SpellInfo->SpellFamilyFlags & 0x1000000) && (SpellInfo->SpellIconID!=82))
- continue;
-
- SpellRankEntry entry;
- SpellRankValue value;
- entry.SkillId=AbilityInfo->skillId;
- entry.SpellName=SpellInfo->SpellName[sWorld.GetDefaultDbcLocale()];
- entry.DurationIndex=SpellInfo->DurationIndex;
- entry.RangeIndex=SpellInfo->rangeIndex;
- entry.ProcFlags=SpellInfo->procFlags;
- entry.SpellFamilyFlags=SpellInfo->SpellFamilyFlags;
- entry.TargetAuraState=SpellInfo->TargetAuraState;
- entry.SpellVisual=SpellInfo->SpellVisual;
- entry.ManaCost=SpellInfo->manaCost;
-
- for (;;)
- {
- AbilityInfo=mSkillLineAbilityMap.lower_bound(spell_id)->second;
- value.Id=spell_id;
- value.Rank=SpellInfo->Rank[sWorld.GetDefaultDbcLocale()];
- RankMap.insert(std::pair<SpellRankEntry, SpellRankValue>(entry,value));
- spell_id=AbilityInfo->forward_spellid;
- SpellInfo=sSpellStore.LookupEntry(spell_id);
- if (!SpellInfo)
- break;
- }
- }
-
- barGoLink bar(RankMap.size());
-
- uint32 count=0;
-
- for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr = RankMap.begin();itr!=RankMap.end();)
- {
- SpellRankEntry entry=itr->first;
- //trac errors in extracted data
- std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator> RankErrorMap;
- for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++)
- {
- bar.step();
- RankErrorMap.insert(std::pair<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator>(itr2->second.Rank,itr2));
- }
- for (std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator>::iterator itr2 = RankErrorMap.begin();itr2!=RankErrorMap.end();)
- {
- char const * err_entry=itr2->first;
- uint32 rank_count=RankErrorMap.count(itr2->first);
- if (rank_count>1)
- for (itr2 = RankErrorMap.lower_bound(err_entry);itr2!=RankErrorMap.upper_bound(err_entry);itr2++)
- {
- sLog.outDebug("There is a duplicate rank entry (%s) for spell: %u",itr2->first,itr2->second->second.Id);
- sLog.outDebug("Spell %u removed from chain data.",itr2->second->second.Id);
- RankMap.erase(itr2->second);
- itr=RankMap.lower_bound(entry);
- }
- else
- itr2++;
- }
- //do not proceed for spells with less than 2 ranks
- uint32 spell_max_rank=RankMap.count(entry);
- if (spell_max_rank<2)
- {
- itr=RankMap.upper_bound(entry);
- continue;
- }
-
- itr=RankMap.upper_bound(entry);
-
- //order spells by spells by spellLevel
- std::list<uint32> RankedSpells;
- uint32 min_spell_lvl=0;
- std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator min_itr;
- for (;RankMap.count(entry);)
- {
- for (std::multimap<SpellRankEntry, SpellRankValue,SpellRankEntry>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++)
- {
- SpellEntry const *SpellInfo=sSpellStore.LookupEntry(itr2->second.Id);
- if (SpellInfo->spellLevel<min_spell_lvl || itr2==RankMap.lower_bound(entry))
- {
- min_spell_lvl=SpellInfo->spellLevel;
- min_itr=itr2;
- }
- }
- RankedSpells.push_back(min_itr->second.Id);
- RankMap.erase(min_itr);
- }
-
- //use data from talent.dbc
- uint16 talent_id=0;
- for(std::list<uint32>::iterator itr2 = RankedSpells.begin();itr2!=RankedSpells.end();)
- {
- if (TalentSpellPos const* TalentPos=GetTalentSpellPos(*itr2))
- {
- talent_id=TalentPos->talent_id;
- RankedSpells.erase(itr2);
- itr2 = RankedSpells.begin();
- }
- else
- itr2++;
- }
- if (talent_id)
- {
- TalentEntry const *TalentInfo = sTalentStore.LookupEntry(talent_id);
- for (uint8 rank=5;rank;rank--)
- {
- if (TalentInfo->RankID[rank-1])
- RankedSpells.push_front(TalentInfo->RankID[rank-1]);
- }
- }
-
- count++;
-
- itr=RankMap.upper_bound(entry);
- uint32 spell_rank=1;
- for(std::list<uint32>::iterator itr2 = RankedSpells.begin();itr2!=RankedSpells.end();spell_rank++)
- {
- uint32 spell_id=*itr2;
- mSpellChains[spell_id].rank=spell_rank;
- mSpellChains[spell_id].first=RankedSpells.front();
- mSpellChains[spell_id].last=RankedSpells.back();
-
- itr2++;
- if (spell_rank<2)
- mSpellChains[spell_id].prev=0;
-
- if (spell_id==RankedSpells.back())
- mSpellChains[spell_id].next=0;
- else
- {
- mSpellChains[*itr2].prev=spell_id;
- mSpellChains[spell_id].next=*itr2;
- }
- }
- }
-
-//uncomment these two lines to print yourself list of spell_chains on startup
-// for (UNORDERED_MAP<uint32, SpellChainNode>::iterator itr=mSpellChains.begin();itr!=mSpellChains.end();itr++)
-// sLog.outString( "Id: %u, Rank: %d , %s",itr->first,itr->second.rank, sSpellStore.LookupEntry(itr->first)->Rank[sWorld.GetDefaultDbcLocale()]);
-
- sLog.outString();
- sLog.outString( ">> Loaded %u spell chains",count);
-}
void SpellMgr::LoadSpellLearnSkills()
{
@@ -1888,8 +1548,10 @@ void SpellMgr::LoadSpellLearnSkills()
// search auto-learned skills and add its to map also for use in unlearn spells/talents
uint32 dbc_count = 0;
+ barGoLink bar( sSpellStore.GetNumRows() );
for(uint32 spell = 0; spell < sSpellStore.GetNumRows(); ++spell)
{
+ bar.step();
SpellEntry const* entry = sSpellStore.LookupEntry(spell);
if(!entry)
@@ -1902,10 +1564,10 @@ void SpellMgr::LoadSpellLearnSkills()
SpellLearnSkillNode dbc_node;
dbc_node.skill = entry->EffectMiscValue[i];
if ( dbc_node.skill != SKILL_RIDING )
- dbc_node.value = 1;
+ dbc_node.value = 1;
else
- dbc_node.value = (entry->EffectBasePoints[i]+1)*75;
- dbc_node.maxvalue = (entry->EffectBasePoints[i]+1)*75;
+ dbc_node.value = entry->CalculateSimpleValue(i)*75;
+ dbc_node.maxvalue = entry->CalculateSimpleValue(i)*75;
SpellLearnSkillNode const* db_node = GetSpellLearnSkill(spell);
@@ -1924,7 +1586,8 @@ void SpellMgr::LoadSpellLearnSpells()
{
mSpellLearnSpells.clear(); // need for reload case
- QueryResult *result = WorldDatabase.Query("SELECT entry, SpellID FROM spell_learn_spell");
+ // 0 1 2
+ QueryResult *result = WorldDatabase.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");
if(!result)
{
barGoLink bar( 1 );
@@ -1948,6 +1611,7 @@ void SpellMgr::LoadSpellLearnSpells()
SpellLearnSpellNode node;
node.spell = fields[1].GetUInt32();
+ node.active = fields[2].GetBool();
node.autoLearned= false;
if(!sSpellStore.LookupEntry(spell_id))
@@ -1984,7 +1648,16 @@ void SpellMgr::LoadSpellLearnSpells()
{
SpellLearnSpellNode dbc_node;
dbc_node.spell = entry->EffectTriggerSpell[i];
- dbc_node.autoLearned = true;
+ dbc_node.active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
+
+ // ignore learning not existed spells (broken/outdated/or generic learnig spell 483
+ if(!sSpellStore.LookupEntry(dbc_node.spell))
+ continue;
+
+ // talent or passive spells or skill-step spells auto-casted and not need dependent learning,
+ // pet teaching spells don't must be dependent learning (casted)
+ // other required explicit dependent learning
+ dbc_node.autoLearned = entry->EffectImplicitTargetA[i] == TARGET_UNIT_PET || GetTalentSpellCost(spell) > 0 || IsPassiveSpell(spell) || IsSpellHaveEffect(entry,SPELL_EFFECT_SKILL_STEP);
SpellLearnSpellMap::const_iterator db_node_begin = GetBeginSpellLearnSpell(spell);
SpellLearnSpellMap::const_iterator db_node_end = GetEndSpellLearnSpell(spell);
@@ -2029,8 +1702,7 @@ void SpellMgr::LoadSpellScriptTarget()
bar.step();
sLog.outString();
- sLog.outString( ">> Loaded 0 spell script target" );
- sLog.outErrorDb("`spell_script_target` table is empty!");
+ sLog.outErrorDb(">> Loaded 0 SpellScriptTarget. DB table `spell_script_target` is empty.");
return;
}
@@ -2216,7 +1888,7 @@ void SpellMgr::LoadSpellPetAuras()
continue;
}
- PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_PET, spellInfo->EffectBasePoints[i] + spellInfo->EffectBaseDice[i]);
+ PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_PET, spellInfo->CalculateSimpleValue(i));
mSpellPetAuraMap[spell] = pa;
}
@@ -2229,240 +1901,232 @@ void SpellMgr::LoadSpellPetAuras()
sLog.outString( ">> Loaded %u spell pet auras", count );
}
-// set data in core for now
-void SpellMgr::LoadSpellCustomAttr()
+static uint32 family2skillline[MAX_CREATURE_FAMILY][2] = {
+ /* ----------------------------- = 0 */ {0, 0 },
+ /*CREATURE_FAMILY_WOLF = 1 */ {208, 270},
+ /*CREATURE_FAMILY_CAT = 2 */ {209, 270},
+ /*CREATURE_FAMILY_SPIDER = 3 */ {203, 270},
+ /*CREATURE_FAMILY_BEAR = 4 */ {210, 270},
+ /*CREATURE_FAMILY_BOAR = 5 */ {211, 270},
+ /*CREATURE_FAMILY_CROCOLISK = 6 */ {212, 270},
+ /*CREATURE_FAMILY_CARRION_BIRD = 7 */ {213, 270},
+ /*CREATURE_FAMILY_CRAB = 8 */ {214, 270},
+ /*CREATURE_FAMILY_GORILLA = 9 */ {215, 270},
+ /*CREATURE_FAMILY_HORSE_CUSTOM = 10*/ {0, 0 },
+ /*CREATURE_FAMILY_RAPTOR = 11*/ {217, 270},
+ /*CREATURE_FAMILY_TALLSTRIDER = 12*/ {218, 270},
+ /* ----------------------------- = 13*/ {0, 0 },
+ /* ----------------------------- = 14*/ {0, 0 },
+ /*CREATURE_FAMILY_FELHUNTER = 15*/ {189, 0 },
+ /*CREATURE_FAMILY_VOIDWALKER = 16*/ {204, 0 },
+ /*CREATURE_FAMILY_SUCCUBUS = 17*/ {205, 0 },
+ /* ----------------------------- = 18*/ {0, 0 },
+ /*CREATURE_FAMILY_DOOMGUARD = 19*/ {207, 0 },
+ /*CREATURE_FAMILY_SCORPID = 20*/ {236, 270},
+ /*CREATURE_FAMILY_TURTLE = 21*/ {251, 270},
+ /* ----------------------------- = 22*/ {0, 0 },
+ /*CREATURE_FAMILY_IMP = 23*/ {188, 0 },
+ /*CREATURE_FAMILY_BAT = 24*/ {653, 270},
+ /*CREATURE_FAMILY_HYENA = 25*/ {654, 270},
+ /*CREATURE_FAMILY_BIRD_OF_PREY = 26*/ {655, 270},
+ /*CREATURE_FAMILY_WIND_SERPENT = 27*/ {656, 270},
+ /*CREATURE_FAMILY_REMOTE_CONTROL = 28*/ {758, 0 },
+ /*CREATURE_FAMILY_FELGUARD = 29*/ {761, 0 },
+ /*CREATURE_FAMILY_DRAGONHAWK = 30*/ {763, 270},
+ /*CREATURE_FAMILY_RAVAGER = 31*/ {767, 270},
+ /*CREATURE_FAMILY_WARP_STALKER = 32*/ {766, 270},
+ /*CREATURE_FAMILY_SPOREBAT = 33*/ {765, 270},
+ /*CREATURE_FAMILY_NETHER_RAY = 34*/ {764, 270},
+ /*CREATURE_FAMILY_SERPENT = 35*/ {768, 270},
+ /* ----------------------------- = 36*/ {0, 0 },
+ /*CREATURE_FAMILY_MOTH = 37*/ {775, 270},
+ /*CREATURE_FAMILY_CHIMAERA = 38*/ {780, 270},
+ /*CREATURE_FAMILY_DEVILSAUR = 39*/ {781, 270},
+ /*CREATURE_FAMILY_GHOUL = 40*/ {782, 0 },
+ /*CREATURE_FAMILY_SILITHID = 41*/ {783, 270},
+ /*CREATURE_FAMILY_WORM = 42*/ {784, 270},
+ /*CREATURE_FAMILY_RHINO = 43*/ {786, 270},
+ /*CREATURE_FAMILY_WASP = 44*/ {785, 270},
+ /*CREATURE_FAMILY_CORE_HOUND = 45*/ {787, 270},
+ /*CREATURE_FAMILY_SPIRIT_BEAST = 46*/ {788, 270}
+};
+
+/// Some checks for spells, to prevent adding depricated/broken spells for trainers, spell book, etc
+void SpellMgr::LoadPetLevelupSpellMap()
{
- mSpellCustomAttr.resize(GetSpellStore()->GetNumRows());
+ mPetLevelupSpellMap.clear(); // need for reload case
- SpellEntry *spellInfo;
- for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i)
+ uint32 count = 0;
+ uint32 family_count = 0;
+
+ for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i)
{
- mSpellCustomAttr[i] = 0;
- spellInfo = (SpellEntry*)GetSpellStore()->LookupEntry(i);
- if(!spellInfo)
+ CreatureFamilyEntry const *creatureFamily = sCreatureFamilyStore.LookupEntry(i);
+ if(!creatureFamily) // not exist
continue;
- bool auraSpell = true;
- for(uint32 j = 0; j < 3; ++j)
+ for (uint8 j = 0; j < 2; ++j)
{
- if(spellInfo->Effect[j])
- if(spellInfo->Effect[j] != SPELL_EFFECT_APPLY_AURA
- || SpellTargetType[spellInfo->EffectImplicitTargetA[j]] != TARGET_TYPE_UNIT_TARGET)
- //ignore target party for now
- {
- auraSpell = false;
- break;
- }
- }
- if(auraSpell)
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_SPELL;
+ if (!creatureFamily->skillLine[j])
+ continue;
- for(uint32 j = 0; j < 3; ++j)
- {
- switch(spellInfo->EffectApplyAuraName[j])
+ for (uint32 k = 0; k < sSkillLineAbilityStore.GetNumRows(); ++k)
{
- case SPELL_AURA_PERIODIC_DAMAGE:
- case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
- case SPELL_AURA_PERIODIC_LEECH:
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_DOT;
- break;
- case SPELL_AURA_PERIODIC_HEAL:
- case SPELL_AURA_OBS_MOD_HEALTH:
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_HOT;
- break;
- case SPELL_AURA_MOD_ROOT:
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_CC;
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_MOVEMENT_IMPAIR;
- break;
- case SPELL_AURA_MOD_DECREASE_SPEED:
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_MOVEMENT_IMPAIR;
- break;
- default:
- break;
- }
+ SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(k);
+ if( !skillLine )
+ continue;
- switch(spellInfo->Effect[j])
- {
- case SPELL_EFFECT_SCHOOL_DAMAGE:
- case SPELL_EFFECT_WEAPON_DAMAGE:
- case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
- case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
- case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
- case SPELL_EFFECT_HEAL:
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_DIRECT_DAMAGE;
- break;
- case SPELL_EFFECT_CHARGE:
- if(!spellInfo->speed && !spellInfo->SpellFamilyName)
- spellInfo->speed = SPEED_CHARGE;
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_CHARGE;
- break;
- case SPELL_EFFECT_TRIGGER_SPELL:
- if(spellInfo->Targets & (TARGET_FLAG_SOURCE_LOCATION|TARGET_FLAG_DEST_LOCATION))
- spellInfo->Effect[j] = SPELL_EFFECT_TRIGGER_MISSILE;
- break;
+ if (skillLine->skillId!=creatureFamily->skillLine[j])
+ continue;
+
+ if(skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL)
+ continue;
+
+ SpellEntry const *spell = sSpellStore.LookupEntry(skillLine->spellId);
+ if(!spell) // not exist or triggered or talent
+ continue;
+
+ if(!spell->spellLevel)
+ continue;
+
+ PetLevelupSpellSet& spellSet = mPetLevelupSpellMap[creatureFamily->ID];
+ if(spellSet.empty())
+ ++family_count;
+
+ spellSet.insert(PetLevelupSpellSet::value_type(spell->spellLevel,spell->Id));
+ count++;
}
}
+ }
- for(uint32 j = 0; j < 3; ++j)
+ sLog.outString();
+ sLog.outString( ">> Loaded %u pet levelup and default spells for %u families", count, family_count );
+}
+
+bool LoadPetDefaultSpells_helper(CreatureInfo const* cInfo, PetDefaultSpellsEntry& petDefSpells)
+{
+ // skip empty list;
+ bool have_spell = false;
+ for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
+ {
+ if(petDefSpells.spellid[j])
{
- switch(spellInfo->EffectApplyAuraName[j])
+ have_spell = true;
+ break;
+ }
+ }
+ if(!have_spell)
+ return false;
+
+ // remove duplicates with levelupSpells if any
+ if(PetLevelupSpellSet const *levelupSpells = cInfo->family ? spellmgr.GetPetLevelupSpellList(cInfo->family) : NULL)
+ {
+ for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
+ {
+ if(!petDefSpells.spellid[j])
+ continue;
+
+ for(PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr)
{
- case SPELL_AURA_MOD_POSSESS:
- case SPELL_AURA_MOD_CONFUSE:
- case SPELL_AURA_MOD_CHARM:
- case SPELL_AURA_MOD_FEAR:
- case SPELL_AURA_MOD_STUN:
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_CC;
- mSpellCustomAttr[i] &= ~SPELL_ATTR_CU_MOVEMENT_IMPAIR;
+ if (itr->second == petDefSpells.spellid[j])
+ {
+ petDefSpells.spellid[j] = 0;
break;
+ }
}
}
+ }
- if(spellInfo->SpellVisual == 3879)
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_BACK;
-
- switch(i)
+ // skip empty list;
+ have_spell = false;
+ for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
+ {
+ if(petDefSpells.spellid[j])
{
- case 26029: // dark glare
- case 37433: // spout
- case 43140: case 43215: // flame breath
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_LINE;
- break;
- case 24340: case 26558: case 28884: // Meteor
- case 36837: case 38903: case 41276: // Meteor
- case 26789: // Shard of the Fallen Star
- case 31436: // Malevolent Cleave
- case 35181: // Dive Bomb
- case 40810: case 43267: case 43268: // Saber Lash
- case 42384: // Brutal Swipe
- case 45150: // Meteor Slash
- mSpellCustomAttr[i] |= SPELL_ATTR_CU_SHARE_DAMAGE;
- break;
- case 44978: case 45001: case 45002: // Wild Magic
- case 45004: case 45006: case 45010: // Wild Magic
- case 31347: // Doom
- case 41635: // Prayer of Mending
- case 44869: // Spectral Blast
- case 45027: // Revitalize
- case 45976: // Muru Portal Channel
- case 39365: // Thundering Storm
- case 41071: // Raise Dead
- spellInfo->MaxAffectedTargets = 1;
- break;
- case 41376: // Spite
- case 39992: // Needle Spine
- case 29576: //Multi-Shot
- case 40816: //Saber Lash
- case 37790: //Spread Shot
- case 46771: //Flame Sear
- case 45248: //Shadow Blades
- case 41303: // Soul Drain
- spellInfo->MaxAffectedTargets = 3;
- break;
- case 38310: //Multi-Shot
- spellInfo->MaxAffectedTargets = 4;
- break;
- case 42005: // Bloodboil
- case 38296: //Spitfire Totem
- case 37676: //Insidious Whisper
- case 46009: //Negative Energy
- case 45641: //Fire Bloom
- spellInfo->MaxAffectedTargets = 5;
- break;
- case 40827: //Sinful Beam
- case 40859: //Sinister Beam
- case 40860: //Vile Beam
- case 40861: //Wicked Beam
- spellInfo->MaxAffectedTargets = 10;
- break;
- case 8122: case 8124: case 10888: case 10890: // Psychic Scream
- case 12494: // Frostbite
- spellInfo->Attributes |= SPELL_ATTR_BREAKABLE_BY_DAMAGE;
- break;
- case 38794: case 33711: //Murmur's Touch
- spellInfo->MaxAffectedTargets = 1;
- spellInfo->EffectTriggerSpell[0] = 33760;
- break;
- default:
+ have_spell = true;
break;
}
}
+
+ return have_spell;
}
-void SpellMgr::LoadSpellLinked()
+void SpellMgr::LoadPetDefaultSpells()
{
- mSpellLinkedMap.clear(); // need for reload case
- uint32 count = 0;
-
- // 0 1 2
- QueryResult *result = WorldDatabase.Query("SELECT spell_trigger, spell_effect, type FROM spell_linked_spell");
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
- sLog.outString();
- sLog.outString( ">> Loaded %u linked spells", count );
- return;
- }
+ mPetDefaultSpellsMap.clear();
- barGoLink bar( result->GetRowCount() );
+ uint32 countCreature = 0;
+ uint32 countData = 0;
- do
+ for(uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i )
{
- Field *fields = result->Fetch();
+ CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i);
+ if(!cInfo)
+ continue;
- bar.step();
+ if(!cInfo->PetSpellDataId)
+ continue;
- int32 trigger = fields[0].GetInt32();
- int32 effect = fields[1].GetInt32();
- int32 type = fields[2].GetInt32();
+ // for creature with PetSpellDataId get default pet spells from dbc
+ CreatureSpellDataEntry const* spellDataEntry = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
+ if(!spellDataEntry)
+ continue;
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(abs(trigger));
- if (!spellInfo)
+ int32 petSpellsId = -(int32)cInfo->PetSpellDataId;
+ PetDefaultSpellsEntry petDefSpells;
+ for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
+ petDefSpells.spellid[j] = spellDataEntry->spellId[j];
+
+ if(LoadPetDefaultSpells_helper(cInfo, petDefSpells))
{
- sLog.outErrorDb("Spell %u listed in `spell_linked_spell` does not exist", abs(trigger));
- continue;
+ mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
+ ++countData;
}
- spellInfo = sSpellStore.LookupEntry(abs(effect));
- if (!spellInfo)
- {
- sLog.outErrorDb("Spell %u listed in `spell_linked_spell` does not exist", abs(effect));
+ }
+
+ // different summon spells
+ for(uint32 i = 0; i < sSpellStore.GetNumRows(); ++i )
+ {
+ SpellEntry const* spellEntry = sSpellStore.LookupEntry(i);
+ if(!spellEntry)
continue;
- }
- if(trigger > 0)
+ for(int k = 0; k < 3; ++k)
{
- switch(type)
+ if(spellEntry->Effect[k]==SPELL_EFFECT_SUMMON || spellEntry->Effect[k]==SPELL_EFFECT_SUMMON_PET)
{
- case 0: mSpellCustomAttr[trigger] |= SPELL_ATTR_CU_LINK_CAST; break;
- case 1: mSpellCustomAttr[trigger] |= SPELL_ATTR_CU_LINK_HIT; break;
- case 2: mSpellCustomAttr[trigger] |= SPELL_ATTR_CU_LINK_AURA; break;
- }
- }
- else
- {
- mSpellCustomAttr[-trigger] |= SPELL_ATTR_CU_LINK_REMOVE;
- }
+ uint32 creature_id = spellEntry->EffectMiscValue[k];
+ CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(creature_id);
+ if(!cInfo)
+ continue;
- if(type) //we will find a better way when more types are needed
- {
- if(trigger > 0)
- trigger += SPELL_LINKED_MAX_SPELLS * type;
- else
- trigger -= SPELL_LINKED_MAX_SPELLS * type;
- }
- mSpellLinkedMap[trigger].push_back(effect);
+ // already loaded
+ if(cInfo->PetSpellDataId)
+ continue;
- ++count;
- } while( result->NextRow() );
+ // for creature without PetSpellDataId get default pet spells from creature_template
+ int32 petSpellsId = cInfo->Entry;
+ if(mPetDefaultSpellsMap.find(cInfo->Entry) != mPetDefaultSpellsMap.end())
+ continue;
- delete result;
+ PetDefaultSpellsEntry petDefSpells;
+ for(int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
+ petDefSpells.spellid[j] = cInfo->spells[j];
+
+ if(LoadPetDefaultSpells_helper(cInfo, petDefSpells))
+ {
+ mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
+ ++countCreature;
+ }
+ }
+ }
+ }
sLog.outString();
- sLog.outString( ">> Loaded %u linked spells", count );
+ sLog.outString( ">> Loaded addition spells for %u pet spell data entries and %u summonable creature templates", countData, countCreature );
}
-/// Some checks for spells, to prevent adding depricated/broken spells for trainers, spell book, etc
+/// Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book, etc
bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)
{
// not exist
@@ -2537,82 +2201,329 @@ bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)
return true;
}
-bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id)
+void SpellMgr::LoadSpellAreas()
{
- // normal case
- if( spellInfo->AreaId && spellInfo->AreaId != zone_id && spellInfo->AreaId != area_id )
- return false;
+ mSpellAreaMap.clear(); // need for reload case
+ mSpellAreaForQuestMap.clear();
+ mSpellAreaForActiveQuestMap.clear();
+ mSpellAreaForQuestEndMap.clear();
+ mSpellAreaForAuraMap.clear();
+
+ uint32 count = 0;
+
+ // 0 1 2 3 4 5 6 7 8
+ QueryResult *result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_active, quest_end, aura_spell, racemask, gender, autocast FROM spell_area");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u spell area requirements", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
- // elixirs (all area dependent elixirs have family SPELLFAMILY_POTION, use this for speedup)
- if(spellInfo->SpellFamilyName==SPELLFAMILY_POTION)
+ do
{
- if(uint32 mask = spellmgr.GetSpellElixirMask(spellInfo->Id))
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ uint32 spell = fields[0].GetUInt32();
+ SpellArea spellArea;
+ spellArea.spellId = spell;
+ spellArea.areaId = fields[1].GetUInt32();
+ spellArea.questStart = fields[2].GetUInt32();
+ spellArea.questStartCanActive = fields[3].GetBool();
+ spellArea.questEnd = fields[4].GetUInt32();
+ spellArea.auraSpell = fields[5].GetInt32();
+ spellArea.raceMask = fields[6].GetUInt32();
+ spellArea.gender = Gender(fields[7].GetUInt8());
+ spellArea.autocast = fields[8].GetBool();
+
+ if(!sSpellStore.LookupEntry(spell))
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` does not exist", spell);
+ continue;
+ }
+
{
- if(mask & ELIXIR_BATTLE_MASK)
+ bool ok = true;
+ SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId);
+ for(SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr)
{
- if(spellInfo->Id==45373) // Bloodberry Elixir
- return zone_id==4075;
+ if(spellArea.spellId && itr->second.spellId && spellArea.spellId != itr->second.spellId)
+ continue;
+ if(spellArea.areaId && itr->second.areaId && spellArea.areaId!= itr->second.areaId)
+ continue;
+ if(spellArea.questStart && itr->second.questStart && spellArea.questStart!= itr->second.questStart)
+ continue;
+ if(spellArea.auraSpell && itr->second.auraSpell && spellArea.auraSpell!= itr->second.auraSpell)
+ continue;
+ if(spellArea.raceMask && itr->second.raceMask && (spellArea.raceMask & itr->second.raceMask)==0)
+ continue;
+ if(spellArea.gender != GENDER_NONE && itr->second.gender != GENDER_NONE && spellArea.gender!= itr->second.gender)
+ continue;
+
+ // duplicate by requirements
+ ok =false;
+ break;
}
- if(mask & ELIXIR_UNSTABLE_MASK)
+
+ if(!ok)
{
- // in the Blade's Edge Mountains Plateaus and Gruul's Lair.
- return zone_id ==3522 || map_id==565;
+ sLog.outErrorDb("Spell %u listed in `spell_area` already listed with similar requirements.", spell);
+ continue;
}
- if(mask & ELIXIR_SHATTRATH_MASK)
+
+ }
+
+ if(spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId))
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell,spellArea.areaId);
+ continue;
+ }
+
+ if(spellArea.questStart && !objmgr.GetQuestTemplate(spellArea.questStart))
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have wrong start quest (%u) requirement", spell,spellArea.questStart);
+ continue;
+ }
+
+ if(spellArea.questEnd)
+ {
+ if(!objmgr.GetQuestTemplate(spellArea.questEnd))
{
- // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple, Sunwell Plateau
- if(zone_id ==3607 || map_id==534 || map_id==564 || zone_id==4075)
- return true;
+ sLog.outErrorDb("Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell,spellArea.questEnd);
+ continue;
+ }
- MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
- if(!mapEntry)
- return false;
+ if(spellArea.questEnd==spellArea.questStart && !spellArea.questStartCanActive)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have quest (%u) requirement for start and end in same time", spell,spellArea.questEnd);
+ continue;
+ }
+ }
- return mapEntry->multimap_id==206;
+ if(spellArea.auraSpell)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(abs(spellArea.auraSpell));
+ if(!spellInfo)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell,abs(spellArea.auraSpell));
+ continue;
}
- // elixirs not have another limitations
- return true;
+ if(spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_DUMMY && spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_PHASE)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy/phase aura in effect 0", spell,abs(spellArea.auraSpell));
+ continue;
+ }
+
+ if(abs(spellArea.auraSpell)==spellArea.spellId)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell,abs(spellArea.auraSpell));
+ continue;
+ }
+
+ // not allow autocast chains by auraSpell field (but allow use as alternative if not present)
+ if(spellArea.autocast && spellArea.auraSpell > 0)
+ {
+ bool chain = false;
+ SpellAreaForAuraMapBounds saBound = GetSpellAreaForAuraMapBounds(spellArea.spellId);
+ for(SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr)
+ {
+ if(itr->second->autocast && itr->second->auraSpell > 0)
+ {
+ chain = true;
+ break;
+ }
+ }
+
+ if(chain)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell,spellArea.auraSpell);
+ continue;
+ }
+
+ SpellAreaMapBounds saBound2 = GetSpellAreaMapBounds(spellArea.auraSpell);
+ for(SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2)
+ {
+ if(itr2->second.autocast && itr2->second.auraSpell > 0)
+ {
+ chain = true;
+ break;
+ }
+ }
+
+ if(chain)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell,spellArea.auraSpell);
+ continue;
+ }
+ }
+ }
+
+ if(spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE)==0)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have wrong race mask (%u) requirement", spell,spellArea.raceMask);
+ continue;
+ }
+
+ if(spellArea.gender!=GENDER_NONE && spellArea.gender!=GENDER_FEMALE && spellArea.gender!=GENDER_MALE)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_area` have wrong gender (%u) requirement", spell,spellArea.gender);
+ continue;
+ }
+
+ SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell,spellArea))->second;
+
+ // for search by current zone/subzone at zone/subzone change
+ if(spellArea.areaId)
+ mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId,sa));
+
+ // for search at quest start/reward
+ if(spellArea.questStart)
+ {
+ if(spellArea.questStartCanActive)
+ mSpellAreaForActiveQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart,sa));
+ else
+ mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart,sa));
+ }
+
+ // for search at quest start/reward
+ if(spellArea.questEnd)
+ mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd,sa));
+
+ // for search at aura apply
+ if(spellArea.auraSpell)
+ mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell),sa));
+
+ ++count;
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u spell area requirements", count );
+}
+
+SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player)
+{
+ // normal case
+ if( spellInfo->AreaGroupId > 0)
+ {
+ bool found = false;
+ AreaGroupEntry const* groupEntry = sAreaGroupStore.LookupEntry(spellInfo->AreaGroupId);
+ while (groupEntry)
+ {
+ for (uint32 i=0; i<6; ++i)
+ if( groupEntry->AreaId[i] == zone_id || groupEntry->AreaId[i] == area_id )
+ found = true;
+ if (found || !groupEntry->nextGroup)
+ break;
+ // Try search in next group
+ groupEntry = sAreaGroupStore.LookupEntry(groupEntry->nextGroup);
+ }
+
+ if(!found)
+ return SPELL_FAILED_INCORRECT_AREA;
+ }
+
+ // DB base check (if non empty then must fit at least single for allow)
+ SpellAreaMapBounds saBounds = spellmgr.GetSpellAreaMapBounds(spellInfo->Id);
+ if(saBounds.first != saBounds.second)
+ {
+ for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
+ {
+ if(itr->second.IsFitToRequirements(player,zone_id,area_id))
+ return SPELL_CAST_OK;
}
+ return SPELL_FAILED_INCORRECT_AREA;
}
- // special cases zone check (maps checked by multimap common id)
+ // bg spell checks
switch(spellInfo->Id)
{
- case 41618: // Bottled Nethergon Energy
- case 41620: // Bottled Nethergon Vapor
+ case 23333: // Warsong Flag
+ case 23335: // Silverwing Flag
+ return map_id == 489 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ case 34976: // Netherstorm Flag
+ return map_id == 566 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ case 2584: // Waiting to Resurrect
+ case 22011: // Spirit Heal Channel
+ case 22012: // Spirit Heal
+ case 24171: // Resurrection Impact Visual
+ case 42792: // Recently Dropped Flag
+ case 43681: // Inactive
+ case 44535: // Spirit Heal (mana)
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if(!mapEntry)
- return false;
+ return SPELL_FAILED_INCORRECT_AREA;
+
+ return mapEntry->IsBattleGround() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ }
+ case 44521: // Preparation
+ {
+ if(!player)
+ return SPELL_FAILED_REQUIRES_AREA;
- return mapEntry->multimap_id==206;
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if(!mapEntry)
+ return SPELL_FAILED_INCORRECT_AREA;
+
+ if(!mapEntry->IsBattleGround())
+ return SPELL_FAILED_REQUIRES_AREA;
+
+ BattleGround* bg = player->GetBattleGround();
+ return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
}
- case 41617: // Cenarion Mana Salve
- case 41619: // Cenarion Healing Salve
+ case 32724: // Gold Team (Alliance)
+ case 32725: // Green Team (Alliance)
+ case 35774: // Gold Team (Horde)
+ case 35775: // Green Team (Horde)
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if(!mapEntry)
- return false;
+ return SPELL_FAILED_INCORRECT_AREA;
- return mapEntry->multimap_id==207;
+ return mapEntry->IsBattleArena() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ }
+ case 32727: // Arena Preparation
+ {
+ if(!player)
+ return SPELL_FAILED_REQUIRES_AREA;
+
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if(!mapEntry)
+ return SPELL_FAILED_INCORRECT_AREA;
+
+ if(!mapEntry->IsBattleArena())
+ return SPELL_FAILED_REQUIRES_AREA;
+
+ BattleGround* bg = player->GetBattleGround();
+ return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
}
- case 40216: // Dragonmaw Illusion
- case 42016: // Dragonmaw Illusion
- return area_id == 3759 || area_id == 3966 || area_id == 3939;
}
- return true;
+ return SPELL_CAST_OK;
}
void SpellMgr::LoadSkillLineAbilityMap()
{
mSkillLineAbilityMap.clear();
+ barGoLink bar( sSkillLineAbilityStore.GetNumRows() );
uint32 count = 0;
- for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); i++)
+ for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); ++i)
{
+ bar.step();
SkillLineAbilityEntry const *SkillInfo = sSkillLineAbilityStore.LookupEntry(i);
if(!SkillInfo)
continue;
@@ -2622,7 +2533,7 @@ void SpellMgr::LoadSkillLineAbilityMap()
}
sLog.outString();
- sLog.outString(">> Loaded %u SkillLineAbility MultiMap", count);
+ sLog.outString(">> Loaded %u SkillLineAbility MultiMap Data", count);
}
DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto, bool triggered)
@@ -2630,56 +2541,46 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
// Explicit Diminishing Groups
switch(spellproto->SpellFamilyName)
{
- case SPELLFAMILY_MAGE:
- {
- // Polymorph
- if ((spellproto->SpellFamilyFlags & 0x00001000000LL) && spellproto->EffectApplyAuraName[0]==SPELL_AURA_MOD_CONFUSE)
- return DIMINISHING_POLYMORPH;
- break;
- }
case SPELLFAMILY_ROGUE:
{
// Kidney Shot
- if (spellproto->SpellFamilyFlags & 0x00000200000LL)
+ if (spellproto->SpellFamilyFlags[0] & 0x200000)
return DIMINISHING_KIDNEYSHOT;
// Sap
- else if (spellproto->SpellFamilyFlags & 0x00000000080LL)
+ else if (spellproto->SpellFamilyFlags[0] & 0x80)
return DIMINISHING_POLYMORPH;
// Gouge
- else if (spellproto->SpellFamilyFlags & 0x00000000008LL)
+ else if (spellproto->SpellFamilyFlags[0] & 0x8)
return DIMINISHING_POLYMORPH;
// Blind
- else if (spellproto->SpellFamilyFlags & 0x00001000000LL)
+ else if (spellproto->SpellFamilyFlags[0] & 0x00001000000)
return DIMINISHING_BLIND_CYCLONE;
break;
}
case SPELLFAMILY_WARLOCK:
{
// Death Coil
- if (spellproto->SpellFamilyFlags & 0x00000080000LL)
+ if (spellproto->SpellFamilyFlags[0] & 0x00000080000)
return DIMINISHING_DEATHCOIL;
// Seduction
- if (spellproto->SpellFamilyFlags & 0x00040000000LL)
+ else if (spellproto->SpellFamilyFlags[0] & 0x00040000000)
return DIMINISHING_FEAR;
- // Fear
- //else if (spellproto->SpellFamilyFlags & 0x40840000000LL)
- // return DIMINISHING_WARLOCK_FEAR;
// Curses/etc
- else if (spellproto->SpellFamilyFlags & 0x00080000000LL)
+ else if (spellproto->SpellFamilyFlags[0] & 0x80000000)
return DIMINISHING_LIMITONLY;
break;
}
case SPELLFAMILY_DRUID:
{
// Cyclone
- if (spellproto->SpellFamilyFlags & 0x02000000000LL)
+ if (spellproto->SpellFamilyFlags[1] & 0x020)
return DIMINISHING_BLIND_CYCLONE;
break;
}
case SPELLFAMILY_WARRIOR:
{
// Hamstring - limit duration to 10s in PvP
- if (spellproto->SpellFamilyFlags & 0x00000000002LL)
+ if (spellproto->SpellFamilyFlags[0] & 0x00000000002)
return DIMINISHING_LIMITONLY;
break;
}
@@ -2688,30 +2589,21 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
}
// Get by mechanic
- for (uint8 i=0;i<3;++i)
- {
- if (spellproto->Mechanic == MECHANIC_STUN || spellproto->EffectMechanic[i] == MECHANIC_STUN)
- return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN;
- else if (spellproto->Mechanic == MECHANIC_SLEEP || spellproto->EffectMechanic[i] == MECHANIC_SLEEP)
- return DIMINISHING_SLEEP;
- else if (spellproto->Mechanic == MECHANIC_ROOT || spellproto->EffectMechanic[i] == MECHANIC_ROOT)
- return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT;
- else if (spellproto->Mechanic == MECHANIC_FEAR || spellproto->EffectMechanic[i] == MECHANIC_FEAR)
- return DIMINISHING_FEAR;
- else if (spellproto->Mechanic == MECHANIC_CHARM || spellproto->EffectMechanic[i] == MECHANIC_CHARM)
- return DIMINISHING_CHARM;
- else if (spellproto->Mechanic == MECHANIC_SILENCE || spellproto->EffectMechanic[i] == MECHANIC_SILENCE)
- return DIMINISHING_SILENCE;
- else if (spellproto->Mechanic == MECHANIC_DISARM || spellproto->EffectMechanic[i] == MECHANIC_DISARM)
- return DIMINISHING_DISARM;
- else if (spellproto->Mechanic == MECHANIC_FREEZE || spellproto->EffectMechanic[i] == MECHANIC_FREEZE)
- return DIMINISHING_FREEZE;
- else if (spellproto->Mechanic == MECHANIC_KNOCKOUT|| spellproto->EffectMechanic[i] == MECHANIC_KNOCKOUT ||
- spellproto->Mechanic == MECHANIC_SAPPED || spellproto->EffectMechanic[i] == MECHANIC_SAPPED)
- return DIMINISHING_KNOCKOUT;
- else if (spellproto->Mechanic == MECHANIC_BANISH || spellproto->EffectMechanic[i] == MECHANIC_BANISH)
- return DIMINISHING_BANISH;
- }
+ uint32 mechanic = GetAllSpellMechanicMask(spellproto);
+ if (mechanic == MECHANIC_NONE) return DIMINISHING_NONE;
+ if (mechanic & (1<<MECHANIC_STUN)) return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN;
+ if (mechanic & (1<<MECHANIC_SLEEP)) return DIMINISHING_SLEEP;
+ if (mechanic & (1<<MECHANIC_POLYMORPH)) return DIMINISHING_POLYMORPH;
+ if (mechanic & (1<<MECHANIC_ROOT)) return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT;
+ if (mechanic & (1<<MECHANIC_FEAR)) return DIMINISHING_FEAR;
+ if (mechanic & (1<<MECHANIC_CHARM)) return DIMINISHING_CHARM;
+ if (mechanic & (1<<MECHANIC_SILENCE)) return DIMINISHING_SILENCE;
+ if (mechanic & (1<<MECHANIC_DISARM)) return DIMINISHING_DISARM;
+ if (mechanic & (1<<MECHANIC_FREEZE)) return DIMINISHING_FREEZE;
+ if (mechanic & ((1<<MECHANIC_KNOCKOUT) | (1<<MECHANIC_SAPPED))) return DIMINISHING_KNOCKOUT;
+ if (mechanic & (1<<MECHANIC_BANISH)) return DIMINISHING_BANISH;
+ if (mechanic & (1<<MECHANIC_HORROR)) return DIMINISHING_DEATHCOIL;
+
return DIMINISHING_NONE;
}
@@ -2736,6 +2628,8 @@ bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group)
case DIMINISHING_BANISH:
case DIMINISHING_LIMITONLY:
return true;
+ default:
+ return false;
}
return false;
}
@@ -2763,8 +2657,894 @@ DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
case DIMINISHING_WARLOCK_FEAR:
case DIMINISHING_KNOCKOUT:
return DRTYPE_PLAYER;
+ default:
+ break;
}
return DRTYPE_NONE;
}
+bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const
+{
+ if(gender!=GENDER_NONE)
+ {
+ // not in expected gender
+ if(!player || gender != player->getGender())
+ return false;
+ }
+
+ if(raceMask)
+ {
+ // not in expected race
+ if(!player || !(raceMask & player->getRaceMask()))
+ return false;
+ }
+
+ if(areaId)
+ {
+ // not in expected zone
+ if(newZone!=areaId && newArea!=areaId)
+ return false;
+ }
+
+ if(questStart)
+ {
+ // not in expected required quest state
+ if(!player || (!questStartCanActive || !player->IsActiveQuest(questStart)) && !player->GetQuestRewardStatus(questStart))
+ return false;
+ }
+
+ if(questEnd)
+ {
+ // not in expected forbidden quest state
+ if(!player || player->GetQuestRewardStatus(questEnd))
+ return false;
+ }
+
+ if(auraSpell)
+ {
+ // not have expected aura
+ if(!player)
+ return false;
+ if(auraSpell > 0)
+ // have expected aura
+ return player->HasAura(auraSpell);
+ else
+ // not have expected aura
+ return !player->HasAura(-auraSpell);
+ }
+
+ return true;
+}
+
+//-----------TRINITY-------------
+
+bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool sameCaster) const
+{
+ SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
+ SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
+
+ if(!spellInfo_1 || !spellInfo_2)
+ return false;
+
+ SpellSpecific spellId_spec_1 = GetSpellSpecific(spellId_1);
+ SpellSpecific spellId_spec_2 = GetSpellSpecific(spellId_2);
+ if (spellId_spec_1 && spellId_spec_2)
+ if (IsSingleFromSpellSpecificPerTarget(spellId_spec_1, spellId_spec_2)
+ ||(IsSingleFromSpellSpecificPerCaster(spellId_spec_1, spellId_spec_2) && sameCaster))
+ return true;
+
+ if(spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
+ return false;
+
+ if(!sameCaster)
+ {
+ for(uint32 i = 0; i < 3; ++i)
+ if (spellInfo_1->Effect[i] == SPELL_EFFECT_APPLY_AURA
+ || spellInfo_1->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
+ // not area auras (shaman totem)
+ switch(spellInfo_1->EffectApplyAuraName[i])
+ {
+ // DOT or HOT from different casters will stack
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_PERIODIC_HEAL:
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
+ case SPELL_AURA_PERIODIC_ENERGIZE:
+ case SPELL_AURA_PERIODIC_MANA_LEECH:
+ case SPELL_AURA_PERIODIC_LEECH:
+ case SPELL_AURA_POWER_BURN_MANA:
+ case SPELL_AURA_OBS_MOD_ENERGY:
+ case SPELL_AURA_OBS_MOD_HEALTH:
+ return false;
+ default:
+ break;
+ }
+ }
+
+ spellId_2 = GetLastSpellInChain(spellId_2);
+ spellId_1 = GetLastSpellInChain(spellId_1);
+
+ // Hack for Incanter's Absorption
+ if (spellId_1 == spellId_2 && spellId_1 == 44413)
+ return false;
+
+ if (spellId_1 == spellId_2)
+ return true;
+
+ // generic spells
+ if(!spellInfo_1->SpellFamilyName)
+ {
+ if(!spellInfo_1->SpellIconID
+ || spellInfo_1->SpellIconID == 1
+ || spellInfo_1->SpellIconID != spellInfo_2->SpellIconID)
+ return false;
+ }
+ // check for class spells
+ else
+ {
+ if (spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags)
+ return false;
+ if (!spellInfo_1->SpellFamilyFlags)
+ return false;
+ }
+
+ //use data of highest rank spell(needed for spells which ranks have different effects)
+ spellInfo_1=sSpellStore.LookupEntry(spellId_1);
+ spellInfo_2=sSpellStore.LookupEntry(spellId_2);
+
+ //if spells have exactly the same effect they cannot stack
+ for(uint32 i = 0; i < 3; ++i)
+ if(spellInfo_1->Effect[i] != spellInfo_2->Effect[i]
+ || spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i]
+ || spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i]) // paladin resist aura
+ return false; // need itemtype check? need an example to add that check
+
+ return true;
+}
+
+bool IsDispelableBySpell(SpellEntry const * dispelSpell, uint32 spellId, bool def)
+{
+ if (!dispelSpell) return false;
+ SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
+ if (!spellproto) return false;
+
+ if (spellproto->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)
+ return false;
+
+ if(dispelSpell->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)
+ return true;
+
+ return def;
+}
+
+void SpellMgr::LoadSpellEnchantProcData()
+{
+ mSpellEnchantProcEventMap.clear(); // need for reload case
+
+ uint32 count = 0;
+
+ // 0 1 2 3
+ QueryResult *result = WorldDatabase.Query("SELECT entry, customChance, PPMChance, procEx FROM spell_enchant_proc_data");
+ if( !result )
+ {
+
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u spell enchant proc event conditions", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ uint32 enchantId = fields[0].GetUInt32();
+
+ SpellItemEnchantmentEntry const *ench = sSpellItemEnchantmentStore.LookupEntry(enchantId);
+ if (!ench)
+ {
+ sLog.outErrorDb("Enchancment %u listed in `spell_enchant_proc_data` does not exist", enchantId);
+ continue;
+ }
+
+ SpellEnchantProcEntry spe;
+
+ spe.customChance = fields[1].GetUInt32();
+ spe.PPMChance = fields[2].GetFloat();
+ spe.procEx = fields[3].GetUInt32();
+
+ mSpellEnchantProcEventMap[enchantId] = spe;
+
+ ++count;
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString( ">> Loaded %u enchant proc data definitions", count);
+}
+
+void SpellMgr::LoadSpellRequired()
+{
+ mSpellsReqSpell.clear(); // need for reload case
+ mSpellReq.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT spell_id, req_spell from spell_required");
+
+ if(result == NULL)
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded 0 spell required records" );
+ sLog.outErrorDb("`spell_required` table is empty!");
+ return;
+ }
+ uint32 rows = 0;
+
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+
+ uint32 spell_id = fields[0].GetUInt32();
+ uint32 spell_req = fields[1].GetUInt32();
+
+ mSpellsReqSpell.insert (std::pair<uint32, uint32>(spell_req, spell_id));
+ mSpellReq[spell_id] = spell_req;
+ ++rows;
+ } while( result->NextRow() );
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u spell required records", rows );
+}
+
+struct SpellRankEntry
+{
+ uint32 SkillId;
+ char const *SpellName;
+ uint32 DurationIndex;
+ uint32 RangeIndex;
+ uint32 SpellVisual;
+ uint32 ProcFlags;
+ flag96 SpellFamilyFlags;
+ uint32 TargetAuraState;
+ uint32 ManaCost;
+ uint32 CastingTimeIndex;
+ flag96 Effect;
+ flag96 Aura;
+ uint16 TalentID;
+
+ bool operator < (const SpellRankEntry & _Right) const
+ {
+ return (SkillId != _Right.SkillId ? SkillId < _Right.SkillId
+ : SpellName!=_Right.SpellName ? SpellName < _Right.SpellName
+ : ProcFlags!=_Right.ProcFlags ? ProcFlags < _Right.ProcFlags
+
+ : Effect!=_Right.Effect ? Effect < _Right.Effect
+ : Aura!=_Right.Aura ? Aura < _Right.Aura
+ : TalentID!=_Right.TalentID ? TalentID < _Right.TalentID
+ : (CastingTimeIndex!=_Right.CastingTimeIndex) && (!CastingTimeIndex || !_Right.CastingTimeIndex || CastingTimeIndex==1 || !_Right.CastingTimeIndex==1) ? CastingTimeIndex < _Right.CastingTimeIndex
+
+ : SpellFamilyFlags!=_Right.SpellFamilyFlags ? SpellFamilyFlags < _Right.SpellFamilyFlags
+ : (SpellVisual!=_Right.SpellVisual) && (!SpellVisual || !_Right.SpellVisual) ? SpellVisual < _Right.SpellVisual
+ : (ManaCost!=_Right.ManaCost) && (!ManaCost || !_Right.ManaCost) ? ManaCost < _Right.ManaCost
+ : (DurationIndex!=_Right.DurationIndex) && (!DurationIndex || !_Right.DurationIndex)? DurationIndex < _Right.DurationIndex
+ : (RangeIndex!=_Right.RangeIndex) && (!RangeIndex || !_Right.RangeIndex || RangeIndex==1 || !_Right.RangeIndex==1) ? RangeIndex < _Right.RangeIndex
+ : TargetAuraState < _Right.TargetAuraState
+ );
+ }
+};
+
+struct SpellRankValue
+{
+ uint32 Id;
+ char const *Rank;
+ bool strict;
+};
+
+void SpellMgr::LoadSpellChains()
+{
+ mSpellChains.clear(); // need for reload case
+
+ std::vector<uint32> ChainedSpells;
+ for (uint32 ability_id=0;ability_id<sSkillLineAbilityStore.GetNumRows();ability_id++)
+ {
+ SkillLineAbilityEntry const *AbilityInfo=sSkillLineAbilityStore.LookupEntry(ability_id);
+ if (!AbilityInfo)
+ continue;
+ if (!AbilityInfo->forward_spellid)
+ continue;
+ ChainedSpells.push_back(AbilityInfo->forward_spellid);
+ }
+
+ std::multimap<SpellRankEntry, SpellRankValue> RankMap;
+
+ for (uint32 ability_id=0;ability_id<sSkillLineAbilityStore.GetNumRows();ability_id++)
+ {
+ SkillLineAbilityEntry const *AbilityInfo=sSkillLineAbilityStore.LookupEntry(ability_id);
+ if (!AbilityInfo)
+ continue;
+
+ //get only spell with lowest ability_id to prevent doubles
+ uint32 spell_id=AbilityInfo->spellId;
+ bool found=false;
+ for (uint32 i=0; i<ChainedSpells.size(); i++)
+ {
+ if (ChainedSpells.at(i)==spell_id)
+ found=true;
+ }
+ if (found)
+ continue;
+
+ if(mSkillLineAbilityMap.lower_bound(spell_id)->second->id!=ability_id)
+ continue;
+ SpellEntry const *SpellInfo=sSpellStore.LookupEntry(spell_id);
+ if (!SpellInfo)
+ continue;
+ std::string sRank = SpellInfo->Rank[sWorld.GetDefaultDbcLocale()];
+ if(sRank.empty())
+ continue;
+ //exception to polymorph spells-make pig and turtle other chain than sheep
+ if ((SpellInfo->SpellFamilyName==SPELLFAMILY_MAGE) && (SpellInfo->SpellFamilyFlags[0] & 0x1000000) && (SpellInfo->SpellIconID!=82))
+ continue;
+
+ SpellRankEntry entry;
+ SpellRankValue value;
+ entry.SkillId=AbilityInfo->skillId;
+ entry.SpellName=SpellInfo->SpellName[sWorld.GetDefaultDbcLocale()];
+ entry.DurationIndex=SpellInfo->DurationIndex;
+ entry.RangeIndex=SpellInfo->rangeIndex;
+ entry.ProcFlags=SpellInfo->procFlags;
+ entry.SpellFamilyFlags=SpellInfo->SpellFamilyFlags;
+ entry.TargetAuraState=SpellInfo->TargetAuraState;
+ entry.SpellVisual=SpellInfo->SpellVisual[0];
+ entry.ManaCost=SpellInfo->manaCost;
+ entry.CastingTimeIndex=0;
+ entry.TalentID=0;
+ for (;;)
+ {
+ AbilityInfo=mSkillLineAbilityMap.lower_bound(spell_id)->second;
+ value.Id=spell_id;
+ value.Rank=SpellInfo->Rank[sWorld.GetDefaultDbcLocale()];
+ value.strict=false;
+ RankMap.insert(std::pair<SpellRankEntry, SpellRankValue>(entry,value));
+ spell_id=AbilityInfo->forward_spellid;
+ SpellInfo=sSpellStore.LookupEntry(spell_id);
+ if (!SpellInfo)
+ break;
+ }
+ }
+
+ barGoLink bar(RankMap.size());
+
+ uint32 count=0;
+
+ for (std::multimap<SpellRankEntry, SpellRankValue>::iterator itr = RankMap.begin();itr!=RankMap.end();)
+ {
+ SpellRankEntry entry=itr->first;
+ //trac errors in extracted data
+ std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue>::iterator> RankErrorMap;
+ for (std::multimap<SpellRankEntry, SpellRankValue>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++)
+ {
+ bar.step();
+ RankErrorMap.insert(std::pair<char const *, std::multimap<SpellRankEntry, SpellRankValue>::iterator>(itr2->second.Rank,itr2));
+ }
+
+ bool error=false;
+ //if strict == true strict check is not needed
+ if (!itr->second.strict)
+ //check for rank duplicates, if there are any do strict check
+ for (std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue>::iterator>::iterator itr2 = RankErrorMap.begin();itr2!=RankErrorMap.end();)
+ {
+ char const * err_entry=itr2->first;
+ uint32 rank_count=RankErrorMap.count(itr2->first);
+ if (rank_count>1)
+ {
+ error=true;
+ break;
+ }
+ else
+ itr2++;
+ }
+ bool allHaveTalents=true;
+ if (error)
+ {
+ std::list<uint32> ConflictedSpells;
+ for (std::multimap<SpellRankEntry, SpellRankValue>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2=RankMap.lower_bound(entry))
+ {
+ ConflictedSpells.push_back(itr2->second.Id);
+ if (!GetTalentSpellPos(itr2->second.Id))
+ allHaveTalents=false;
+ RankMap.erase(itr2);
+ }
+ SpellRankEntry nextEntry, currEntry;
+ for (;!ConflictedSpells.empty();ConflictedSpells.pop_front())
+ {
+ SpellEntry const *SpellInfo=sSpellStore.LookupEntry(ConflictedSpells.front());
+ currEntry.SkillId=entry.SkillId;
+ currEntry.SpellName=SpellInfo->SpellName[sWorld.GetDefaultDbcLocale()];
+ currEntry.DurationIndex=SpellInfo->DurationIndex;
+ currEntry.RangeIndex=SpellInfo->rangeIndex;
+ currEntry.ProcFlags=SpellInfo->procFlags;
+ currEntry.SpellFamilyFlags=SpellInfo->SpellFamilyFlags;
+ //compare talents only when all spells from chain have entry
+ //to prevent wrong results with spells which have first rank talented and other not
+ if (allHaveTalents)
+ currEntry.TalentID=GetTalentSpellPos(ConflictedSpells.front())->talent_id;
+ else
+ currEntry.TalentID=0;
+ currEntry.TargetAuraState=SpellInfo->TargetAuraState;
+ currEntry.SpellVisual=SpellInfo->SpellVisual[0];
+ currEntry.ManaCost=SpellInfo->manaCost;
+
+ //compare effects and casting time
+ currEntry.CastingTimeIndex=SpellInfo->CastingTimeIndex;
+ currEntry.Effect[0]=SpellInfo->Effect[0];
+ currEntry.Effect[1]=SpellInfo->Effect[1];
+ currEntry.Effect[2]=SpellInfo->Effect[2];
+
+ currEntry.Aura[0]=SpellInfo->EffectApplyAuraName[0];
+ currEntry.Aura[1]=SpellInfo->EffectApplyAuraName[1];
+ currEntry.Aura[2]=SpellInfo->EffectApplyAuraName[2];
+
+ SpellRankValue currValue;
+ currValue.Id=ConflictedSpells.front();
+ currValue.Rank=SpellInfo->Rank[sWorld.GetDefaultDbcLocale()];
+ currValue.strict=true;
+ RankMap.insert(std::pair<SpellRankEntry, SpellRankValue>(currEntry,currValue));
+ }
+ itr=RankMap.begin();
+ continue;
+ }
+ else
+ for (std::multimap<char const *, std::multimap<SpellRankEntry, SpellRankValue>::iterator>::iterator itr2 = RankErrorMap.begin();itr2!=RankErrorMap.end();)
+ {
+ char const * err_entry=itr2->first;
+ uint32 rank_count=RankErrorMap.count(itr2->first);
+ if (rank_count>1)
+ for (itr2 = RankErrorMap.lower_bound(err_entry);itr2!=RankErrorMap.upper_bound(err_entry);itr2++)
+ {
+ sLog.outDebug("There is a duplicate rank entry (%s) for spell: %u",itr2->first,itr2->second->second.Id);
+ if (!(itr2->second->second.Id==52375 || itr2->second->second.Id==45902))
+ {
+ sLog.outDebug("Spell %u removed from chain data.",itr2->second->second.Id);
+ RankMap.erase(itr2->second);
+ }
+ }
+ else
+ itr2++;
+ }
+
+ //order spells by spellLevel
+ std::list<uint32> RankedSpells;
+ uint32 min_spell_lvl=0;
+ std::multimap<SpellRankEntry, SpellRankValue>::iterator min_itr;
+ for (;RankMap.count(entry);)
+ {
+ for (std::multimap<SpellRankEntry, SpellRankValue>::iterator itr2 = RankMap.lower_bound(entry);itr2!=RankMap.upper_bound(entry);itr2++)
+ {
+ SpellEntry const *SpellInfo=sSpellStore.LookupEntry(itr2->second.Id);
+ if (SpellInfo->spellLevel<min_spell_lvl || itr2==RankMap.lower_bound(entry))
+ {
+ min_spell_lvl=SpellInfo->spellLevel;
+ min_itr=itr2;
+ }
+ }
+ RankedSpells.push_back(min_itr->second.Id);
+ RankMap.erase(min_itr);
+ }
+
+ //use data from talent.dbc
+ uint16 talent_id=0;
+ for(std::list<uint32>::iterator itr2 = RankedSpells.begin();itr2!=RankedSpells.end();)
+ {
+ if (TalentSpellPos const* TalentPos=GetTalentSpellPos(*itr2))
+ {
+ talent_id=TalentPos->talent_id;
+ RankedSpells.erase(itr2);
+ itr2 = RankedSpells.begin();
+ }
+ else
+ itr2++;
+ }
+ if (talent_id)
+ {
+ TalentEntry const *TalentInfo = sTalentStore.LookupEntry(talent_id);
+ for (uint8 rank=5;rank;rank--)
+ {
+ if (TalentInfo->RankID[rank-1])
+ RankedSpells.push_front(TalentInfo->RankID[rank-1]);
+ }
+ }
+
+ //do not proceed for spells with less than 2 ranks
+ itr=RankMap.begin();
+ if (RankedSpells.size()<2)
+ continue;
+
+ count++;
+
+ uint32 spell_rank=1;
+ for(std::list<uint32>::iterator itr2 = RankedSpells.begin();itr2!=RankedSpells.end();spell_rank++)
+ {
+ uint32 spell_id=*itr2;
+ mSpellChains[spell_id].rank=spell_rank;
+ mSpellChains[spell_id].first=RankedSpells.front();
+ mSpellChains[spell_id].last=RankedSpells.back();
+
+ itr2++;
+ if (spell_rank<2)
+ mSpellChains[spell_id].prev=0;
+
+ if (spell_id==RankedSpells.back())
+ mSpellChains[spell_id].next=0;
+ else
+ {
+ mSpellChains[*itr2].prev=spell_id;
+ mSpellChains[spell_id].next=*itr2;
+ }
+ }
+ }
+
+//uncomment these two lines to print yourself list of spell_chains on startup
+ //for (UNORDERED_MAP<uint32, SpellChainNode>::iterator itr=mSpellChains.begin();itr!=mSpellChains.end();itr++)
+ //sLog.outString( "Id: %u, Rank: %d , %s, %u, %u, %u, %u",itr->first,itr->second.rank, sSpellStore.LookupEntry(itr->first)->Rank[sWorld.GetDefaultDbcLocale()], itr->second.first, itr->second.last,itr->second.next ,itr->second.prev);
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u spell chains",count);
+}
+
+// set data in core for now
+void SpellMgr::LoadSpellCustomAttr()
+{
+ mSpellCustomAttr.resize(GetSpellStore()->GetNumRows());
+
+ SpellEntry *spellInfo;
+ for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i)
+ {
+ mSpellCustomAttr[i] = 0;
+ spellInfo = (SpellEntry*)GetSpellStore()->LookupEntry(i);
+ if(!spellInfo)
+ continue;
+
+ bool auraSpell = true;
+ for(uint32 j = 0; j < 3; ++j)
+ {
+ if(spellInfo->Effect[j])
+ if(spellInfo->Effect[j] != SPELL_EFFECT_APPLY_AURA
+ || SpellTargetType[spellInfo->EffectImplicitTargetA[j]] != TARGET_TYPE_UNIT_TARGET)
+ //ignore target party for now
+ {
+ auraSpell = false;
+ break;
+ }
+ }
+ if(auraSpell)
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_SPELL;
+
+ for(uint32 j = 0; j < 3; ++j)
+ {
+ switch(spellInfo->EffectApplyAuraName[j])
+ {
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
+ case SPELL_AURA_PERIODIC_LEECH:
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_DOT;
+ break;
+ case SPELL_AURA_PERIODIC_HEAL:
+ case SPELL_AURA_OBS_MOD_HEALTH:
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_HOT;
+ break;
+ case SPELL_AURA_MOD_ROOT:
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_CC;
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_MOVEMENT_IMPAIR;
+ break;
+ case SPELL_AURA_MOD_DECREASE_SPEED:
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_MOVEMENT_IMPAIR;
+ break;
+ default:
+ break;
+ }
+
+ switch(spellInfo->Effect[j])
+ {
+ case SPELL_EFFECT_SCHOOL_DAMAGE:
+ case SPELL_EFFECT_WEAPON_DAMAGE:
+ case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
+ case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
+ case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
+ case SPELL_EFFECT_HEAL:
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_DIRECT_DAMAGE;
+ break;
+ case SPELL_EFFECT_CHARGE:
+ case SPELL_EFFECT_JUMP:
+ case SPELL_EFFECT_JUMP2:
+ case SPELL_EFFECT_138:
+ if(!spellInfo->speed && !spellInfo->SpellFamilyName)
+ spellInfo->speed = SPEED_CHARGE;
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_CHARGE;
+ break;
+ case SPELL_EFFECT_TRIGGER_SPELL:
+ if (SpellTargetType[spellInfo->EffectImplicitTargetA[j]]== TARGET_TYPE_DEST_CASTER ||
+ SpellTargetType[spellInfo->EffectImplicitTargetA[j]]== TARGET_TYPE_DEST_TARGET ||
+ SpellTargetType[spellInfo->EffectImplicitTargetA[j]]== TARGET_TYPE_DEST_DEST ||
+ spellInfo->Targets & (TARGET_FLAG_SOURCE_LOCATION|TARGET_FLAG_DEST_LOCATION))
+ spellInfo->Effect[j] = SPELL_EFFECT_TRIGGER_MISSILE;
+ break;
+ }
+
+ switch(SpellTargetType[spellInfo->EffectImplicitTargetA[j]])
+ {
+ case TARGET_TYPE_UNIT_TARGET:
+ case TARGET_TYPE_DEST_TARGET:
+ spellInfo->Targets |= TARGET_FLAG_UNIT;
+ break;
+ //case TARGET_TYPE_AREA_DST:
+ //case TARGET_TYPE_DEST_DEST:
+ // spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION;
+ // break;
+ }
+ }
+
+ for(uint32 j = 0; j < 3; ++j)
+ {
+ switch(spellInfo->EffectApplyAuraName[j])
+ {
+ case SPELL_AURA_MOD_POSSESS:
+ case SPELL_AURA_MOD_CONFUSE:
+ case SPELL_AURA_MOD_CHARM:
+ case SPELL_AURA_MOD_FEAR:
+ case SPELL_AURA_MOD_STUN:
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_AURA_CC;
+ mSpellCustomAttr[i] &= ~SPELL_ATTR_CU_MOVEMENT_IMPAIR;
+ break;
+ }
+ }
+
+ if(spellInfo->SpellVisual[0] == 3879)
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_BACK;
+
+ switch(i)
+ {
+ case 26029: // dark glare
+ case 37433: // spout
+ case 43140: case 43215: // flame breath
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_LINE;
+ break;
+ case 24340: case 26558: case 28884: // Meteor
+ case 36837: case 38903: case 41276: // Meteor
+ case 57467: // Meteor
+ case 26789: // Shard of the Fallen Star
+ case 31436: // Malevolent Cleave
+ case 35181: // Dive Bomb
+ case 40810: case 43267: case 43268: // Saber Lash
+ case 42384: // Brutal Swipe
+ case 45150: // Meteor Slash
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_SHARE_DAMAGE;
+ break;
+ case 27820: // Mana Detonation
+ //case 28062: case 39090: // Positive/Negative Charge
+ //case 28085: case 39093:
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_EXCLUDE_SELF;
+ break;
+ case 44978: case 45001: case 45002: // Wild Magic
+ case 45004: case 45006: case 45010: // Wild Magic
+ case 31347: // Doom
+ case 41635: // Prayer of Mending
+ case 44869: // Spectral Blast
+ case 45027: // Revitalize
+ case 45976: // Muru Portal Channel
+ case 39365: // Thundering Storm
+ case 41071: // Raise Dead (HACK)
+ spellInfo->MaxAffectedTargets = 1;
+ break;
+ case 41376: // Spite
+ case 39992: // Needle Spine
+ case 29576: // Multi-Shot
+ case 40816: // Saber Lash
+ case 37790: // Spread Shot
+ case 46771: // Flame Sear
+ case 45248: // Shadow Blades
+ case 41303: // Soul Drain
+ case 54172: // Divine Storm (heal)
+ case 29213: // Curse of the Plaguebringer - Noth
+ case 28542: // Life Drain - Sapphiron
+ spellInfo->MaxAffectedTargets = 3;
+ break;
+ case 38310: //Multi-Shot
+ spellInfo->MaxAffectedTargets = 4;
+ break;
+ case 42005: // Bloodboil
+ case 38296: // Spitfire Totem
+ case 37676: // Insidious Whisper
+ case 46009: // Negative Energy
+ case 45641: // Fire Bloom
+ case 55665: // Life Drain - Sapphiron (H)
+ case 28796: // Poison Bolt Volly - Faerlina
+ spellInfo->MaxAffectedTargets = 5;
+ break;
+ case 40827: // Sinful Beam
+ case 40859: // Sinister Beam
+ case 40860: // Vile Beam
+ case 40861: // Wicked Beam
+ case 54835: // Curse of the Plaguebringer - Noth (H)
+ case 54098: // Poison Bolt Volly - Faerlina (H)
+ spellInfo->MaxAffectedTargets = 10;
+ break;
+ case 8122: case 8124: case 10888: case 10890: // Psychic Scream
+ case 12494: // Frostbite
+ spellInfo->Attributes |= SPELL_ATTR_BREAKABLE_BY_DAMAGE;
+ break;
+ case 38794: case 33711: //Murmur's Touch
+ spellInfo->MaxAffectedTargets = 1;
+ spellInfo->EffectTriggerSpell[0] = 33760;
+ break;
+ case 17941: // Shadow Trance
+ case 22008: // Netherwind Focus
+ case 31834: // Light's Grace
+ case 34754: // Clearcasting
+ case 34936: // Backlash
+ case 48108: // Hot Streak
+ case 51124: // Killing Machine
+ case 54741: // Firestarter
+ case 57761: // Fireball!
+ case 39805: // Lightning Overload
+ case 52437: // Sudden Death
+ spellInfo->procCharges=1;
+ break;
+ case 44544: // Fingers of Frost
+ spellInfo->procCharges=2;
+ break;
+ case 28200: // Ascendance (Talisman of Ascendance trinket)
+ spellInfo->procCharges=6;
+ break;
+ default:
+ break;
+ }
+
+ switch(spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_DRUID:
+ // Starfall Target Selection
+ if(spellInfo->SpellFamilyFlags[2] & 0x100)
+ spellInfo->MaxAffectedTargets = 2;
+ // Starfall AOE Damage
+ else if(spellInfo->SpellFamilyFlags[2] & 0x800000)
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_EXCLUDE_SELF;
+ break;
+ }
+ }
+
+ SummonPropertiesEntry *properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(121));
+ properties->Type = SUMMON_TYPE_TOTEM;
+
+ CreatureAI::FillAISpellInfo();
+}
+
+// Fill custom data about enchancments
+void SpellMgr::LoadEnchantCustomAttr()
+{
+ uint32 size = sSpellItemEnchantmentStore.GetNumRows();
+ mEnchantCustomAttr.resize(size);
+
+ for (uint32 i = 0;i<size; ++i)
+ mEnchantCustomAttr[i] = 0;
+
+ for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i)
+ {
+ SpellEntry * spellInfo = (SpellEntry*)GetSpellStore()->LookupEntry(i);
+ if(!spellInfo)
+ continue;
+
+ // TODO: find a better check
+ if (!(spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK13) || !(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT))
+ continue;
+
+ for(uint32 j = 0; j < 3; ++j)
+ {
+ if(spellInfo->Effect[j] == SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY)
+ {
+ uint32 enchId = spellInfo->EffectMiscValue[j];
+ SpellItemEnchantmentEntry const *ench = sSpellItemEnchantmentStore.LookupEntry(enchId);
+ if (!enchId)
+ continue;
+ mEnchantCustomAttr[enchId] = true;
+ break;
+ }
+ }
+ }
+}
+
+bool SpellMgr::IsSkillTypeSpell(uint32 spellId, SkillType type) const
+{
+ SkillLineAbilityMap::const_iterator lower = GetBeginSkillLineAbilityMap(spellId);
+ SkillLineAbilityMap::const_iterator upper = GetEndSkillLineAbilityMap(spellId);
+ for (;lower!=upper;++lower)
+ {
+ if (lower->second->skillId==type)
+ return true;
+ }
+ return false;
+}
+
+void SpellMgr::LoadSpellLinked()
+{
+ mSpellLinkedMap.clear(); // need for reload case
+ uint32 count = 0;
+
+ // 0 1 2
+ QueryResult *result = WorldDatabase.Query("SELECT spell_trigger, spell_effect, type FROM spell_linked_spell");
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+ sLog.outString();
+ sLog.outString( ">> Loaded %u linked spells", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ int32 trigger = fields[0].GetInt32();
+ int32 effect = fields[1].GetInt32();
+ int32 type = fields[2].GetInt32();
+
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(abs(trigger));
+ if (!spellInfo)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_linked_spell` does not exist", abs(trigger));
+ continue;
+ }
+ spellInfo = sSpellStore.LookupEntry(abs(effect));
+ if (!spellInfo)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_linked_spell` does not exist", abs(effect));
+ continue;
+ }
+
+ if(trigger > 0)
+ {
+ switch(type)
+ {
+ case 0: mSpellCustomAttr[trigger] |= SPELL_ATTR_CU_LINK_CAST; break;
+ case 1: mSpellCustomAttr[trigger] |= SPELL_ATTR_CU_LINK_HIT; break;
+ case 2: mSpellCustomAttr[trigger] |= SPELL_ATTR_CU_LINK_AURA; break;
+ }
+ }
+ else
+ {
+ mSpellCustomAttr[-trigger] |= SPELL_ATTR_CU_LINK_REMOVE;
+ }
+
+ if(type) //we will find a better way when more types are needed
+ {
+ if(trigger > 0)
+ trigger += SPELL_LINKED_MAX_SPELLS * type;
+ else
+ trigger -= SPELL_LINKED_MAX_SPELLS * type;
+ }
+ mSpellLinkedMap[trigger].push_back(effect);
+
+ ++count;
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u linked spells", count );
+}
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index 62c46ccf990..13973e25120 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,12 +10,12 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SPELLMGR_H
@@ -25,10 +25,13 @@
// For more high level function for sSpellStore data
#include "SharedDefines.h"
-#include "Database/DBCStructure.h"
+#include "DBCStructure.h"
#include "Database/SQLStorage.h"
#include "Utilities/UnorderedMap.h"
+
+#include "Player.h"
+
#include <map>
class Player;
@@ -36,177 +39,11 @@ class Spell;
extern SQLStorage sSpellThreatStore;
-enum SpellFailedReason
+// only used in code
+enum SpellCategories
{
- SPELL_FAILED_AFFECTING_COMBAT = 0x00,
- SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 0x01,
- SPELL_FAILED_ALREADY_AT_FULL_MANA = 0x02,
- SPELL_FAILED_ALREADY_AT_FULL_POWER = 0x03,
- SPELL_FAILED_ALREADY_BEING_TAMED = 0x04,
- SPELL_FAILED_ALREADY_HAVE_CHARM = 0x05,
- SPELL_FAILED_ALREADY_HAVE_SUMMON = 0x06,
- SPELL_FAILED_ALREADY_OPEN = 0x07,
- SPELL_FAILED_AURA_BOUNCED = 0x08,
- SPELL_FAILED_AUTOTRACK_INTERRUPTED = 0x09,
- SPELL_FAILED_BAD_IMPLICIT_TARGETS = 0x0A,
- SPELL_FAILED_BAD_TARGETS = 0x0B,
- SPELL_FAILED_CANT_BE_CHARMED = 0x0C,
- SPELL_FAILED_CANT_BE_DISENCHANTED = 0x0D,
- SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 0x0E,
- SPELL_FAILED_CANT_BE_PROSPECTED = 0x0F,
- SPELL_FAILED_CANT_CAST_ON_TAPPED = 0x10,
- SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 0x11,
- SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 0x12,
- SPELL_FAILED_CANT_STEALTH = 0x13,
- SPELL_FAILED_CASTER_AURASTATE = 0x14,
- SPELL_FAILED_CASTER_DEAD = 0x15,
- SPELL_FAILED_CHARMED = 0x16,
- SPELL_FAILED_CHEST_IN_USE = 0x17,
- SPELL_FAILED_CONFUSED = 0x18,
- SPELL_FAILED_DONT_REPORT = 0x19,
- SPELL_FAILED_EQUIPPED_ITEM = 0x1A,
- SPELL_FAILED_EQUIPPED_ITEM_CLASS = 0x1B,
- SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 0x1C,
- SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 0x1D,
- SPELL_FAILED_ERROR = 0x1E,
- SPELL_FAILED_FIZZLE = 0x1F,
- SPELL_FAILED_FLEEING = 0x20,
- SPELL_FAILED_FOOD_LOWLEVEL = 0x21,
- SPELL_FAILED_HIGHLEVEL = 0x22,
- SPELL_FAILED_HUNGER_SATIATED = 0x23,
- SPELL_FAILED_IMMUNE = 0x24,
- SPELL_FAILED_INTERRUPTED = 0x25,
- SPELL_FAILED_INTERRUPTED_COMBAT = 0x26,
- SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 0x27,
- SPELL_FAILED_ITEM_GONE = 0x28,
- SPELL_FAILED_ITEM_NOT_FOUND = 0x29,
- SPELL_FAILED_ITEM_NOT_READY = 0x2A,
- SPELL_FAILED_LEVEL_REQUIREMENT = 0x2B,
- SPELL_FAILED_LINE_OF_SIGHT = 0x2C,
- SPELL_FAILED_LOWLEVEL = 0x2D,
- SPELL_FAILED_LOW_CASTLEVEL = 0x2E,
- SPELL_FAILED_MAINHAND_EMPTY = 0x2F,
- SPELL_FAILED_MOVING = 0x30,
- SPELL_FAILED_NEED_AMMO = 0x31,
- SPELL_FAILED_NEED_AMMO_POUCH = 0x32,
- SPELL_FAILED_NEED_EXOTIC_AMMO = 0x33,
- SPELL_FAILED_NOPATH = 0x34,
- SPELL_FAILED_NOT_BEHIND = 0x35,
- SPELL_FAILED_NOT_FISHABLE = 0x36,
- SPELL_FAILED_NOT_FLYING = 0x37,
- SPELL_FAILED_NOT_HERE = 0x38,
- SPELL_FAILED_NOT_INFRONT = 0x39,
- SPELL_FAILED_NOT_IN_CONTROL = 0x3A,
- SPELL_FAILED_NOT_KNOWN = 0x3B,
- SPELL_FAILED_NOT_MOUNTED = 0x3C,
- SPELL_FAILED_NOT_ON_TAXI = 0x3D,
- SPELL_FAILED_NOT_ON_TRANSPORT = 0x3E,
- SPELL_FAILED_NOT_READY = 0x3F,
- SPELL_FAILED_NOT_SHAPESHIFT = 0x40,
- SPELL_FAILED_NOT_STANDING = 0x41,
- SPELL_FAILED_NOT_TRADEABLE = 0x42,
- SPELL_FAILED_NOT_TRADING = 0x43,
- SPELL_FAILED_NOT_UNSHEATHED = 0x44,
- SPELL_FAILED_NOT_WHILE_GHOST = 0x45,
- SPELL_FAILED_NO_AMMO = 0x46,
- SPELL_FAILED_NO_CHARGES_REMAIN = 0x47,
- SPELL_FAILED_NO_CHAMPION = 0x48,
- SPELL_FAILED_NO_COMBO_POINTS = 0x49,
- SPELL_FAILED_NO_DUELING = 0x4A,
- SPELL_FAILED_NO_ENDURANCE = 0x4B,
- SPELL_FAILED_NO_FISH = 0x4C,
- SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 0x4D,
- SPELL_FAILED_NO_MOUNTS_ALLOWED = 0x4E,
- SPELL_FAILED_NO_PET = 0x4F,
- SPELL_FAILED_NO_POWER = 0x50,
- SPELL_FAILED_NOTHING_TO_DISPEL = 0x51,
- SPELL_FAILED_NOTHING_TO_STEAL = 0x52,
- SPELL_FAILED_ONLY_ABOVEWATER = 0x53,
- SPELL_FAILED_ONLY_DAYTIME = 0x54,
- SPELL_FAILED_ONLY_INDOORS = 0x55,
- SPELL_FAILED_ONLY_MOUNTED = 0x56,
- SPELL_FAILED_ONLY_NIGHTTIME = 0x57,
- SPELL_FAILED_ONLY_OUTDOORS = 0x58,
- SPELL_FAILED_ONLY_SHAPESHIFT = 0x59,
- SPELL_FAILED_ONLY_STEALTHED = 0x5A,
- SPELL_FAILED_ONLY_UNDERWATER = 0x5B,
- SPELL_FAILED_OUT_OF_RANGE = 0x5C,
- SPELL_FAILED_PACIFIED = 0x5D,
- SPELL_FAILED_POSSESSED = 0x5E,
- SPELL_FAILED_REAGENTS = 0x5F,
- SPELL_FAILED_REQUIRES_AREA = 0x60,
- SPELL_FAILED_REQUIRES_SPELL_FOCUS = 0x61,
- SPELL_FAILED_ROOTED = 0x62,
- SPELL_FAILED_SILENCED = 0x63,
- SPELL_FAILED_SPELL_IN_PROGRESS = 0x64,
- SPELL_FAILED_SPELL_LEARNED = 0x65,
- SPELL_FAILED_SPELL_UNAVAILABLE = 0x66,
- SPELL_FAILED_STUNNED = 0x67,
- SPELL_FAILED_TARGETS_DEAD = 0x68,
- SPELL_FAILED_TARGET_AFFECTING_COMBAT = 0x69,
- SPELL_FAILED_TARGET_AURASTATE = 0x6A,
- SPELL_FAILED_TARGET_DUELING = 0x6B,
- SPELL_FAILED_TARGET_ENEMY = 0x6C,
- SPELL_FAILED_TARGET_ENRAGED = 0x6D,
- SPELL_FAILED_TARGET_FRIENDLY = 0x6E,
- SPELL_FAILED_TARGET_IN_COMBAT = 0x6F,
- SPELL_FAILED_TARGET_IS_PLAYER = 0x70,
- SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 0x71,
- SPELL_FAILED_TARGET_NOT_DEAD = 0x72,
- SPELL_FAILED_TARGET_NOT_IN_PARTY = 0x73,
- SPELL_FAILED_TARGET_NOT_LOOTED = 0x74,
- SPELL_FAILED_TARGET_NOT_PLAYER = 0x75,
- SPELL_FAILED_TARGET_NO_POCKETS = 0x76,
- SPELL_FAILED_TARGET_NO_WEAPONS = 0x77,
- SPELL_FAILED_TARGET_UNSKINNABLE = 0x78,
- SPELL_FAILED_THIRST_SATIATED = 0x79,
- SPELL_FAILED_TOO_CLOSE = 0x7A,
- SPELL_FAILED_TOO_MANY_OF_ITEM = 0x7B,
- SPELL_FAILED_TOTEM_CATEGORY = 0x7C,
- SPELL_FAILED_TOTEMS = 0x7D,
- SPELL_FAILED_TRAINING_POINTS = 0x7E,
- SPELL_FAILED_TRY_AGAIN = 0x7F,
- SPELL_FAILED_UNIT_NOT_BEHIND = 0x80,
- SPELL_FAILED_UNIT_NOT_INFRONT = 0x81,
- SPELL_FAILED_WRONG_PET_FOOD = 0x82,
- SPELL_FAILED_NOT_WHILE_FATIGUED = 0x83,
- SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 0x84,
- SPELL_FAILED_NOT_WHILE_TRADING = 0x85,
- SPELL_FAILED_TARGET_NOT_IN_RAID = 0x86,
- SPELL_FAILED_DISENCHANT_WHILE_LOOTING = 0x87,
- SPELL_FAILED_PROSPECT_WHILE_LOOTING = 0x88,
- SPELL_FAILED_PROSPECT_NEED_MORE = 0x89,
- SPELL_FAILED_TARGET_FREEFORALL = 0x8A,
- SPELL_FAILED_NO_EDIBLE_CORPSES = 0x8B,
- SPELL_FAILED_ONLY_BATTLEGROUNDS = 0x8C,
- SPELL_FAILED_TARGET_NOT_GHOST = 0x8D,
- SPELL_FAILED_TOO_MANY_SKILLS = 0x8E,
- SPELL_FAILED_TRANSFORM_UNUSABLE = 0x8F,
- SPELL_FAILED_WRONG_WEATHER = 0x90,
- SPELL_FAILED_DAMAGE_IMMUNE = 0x91,
- SPELL_FAILED_PREVENTED_BY_MECHANIC = 0x92,
- SPELL_FAILED_PLAY_TIME = 0x93,
- SPELL_FAILED_REPUTATION = 0x94,
- SPELL_FAILED_MIN_SKILL = 0x95,
- SPELL_FAILED_NOT_IN_ARENA = 0x96,
- SPELL_FAILED_NOT_ON_SHAPESHIFT = 0x97,
- SPELL_FAILED_NOT_ON_STEALTHED = 0x98,
- SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 0x99,
- SPELL_FAILED_NOT_ON_MOUNTED = 0x9A,
- SPELL_FAILED_TOO_SHALLOW = 0x9B,
- SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 0x9C,
- SPELL_FAILED_TARGET_IS_TRIVIAL = 0x9D,
- SPELL_FAILED_BM_OR_INVISGOD = 0x9E,
- SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 0x9F,
- SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 0xA0,
- SPELL_FAILED_NOT_IDLE = 0xA1,
- SPELL_FAILED_NOT_INACTIVE = 0xA2,
- SPELL_FAILED_PARTIAL_PLAYTIME = 0xA3,
- SPELL_FAILED_NO_PLAYTIME = 0xA4,
- SPELL_FAILED_NOT_IN_BATTLEGROUND = 0xA5,
- SPELL_FAILED_ONLY_IN_ARENA = 0xA6,
- SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 0xA7,
- SPELL_FAILED_UNKNOWN = 0xA8,
+ SPELLCATEGORY_HEALTH_MANA_POTIONS = 4,
+ SPELLCATEGORY_DEVOUR_MAGIC = 12
};
enum SpellFamilyNames
@@ -223,8 +60,12 @@ enum SpellFamilyNames
SPELLFAMILY_HUNTER = 9,
SPELLFAMILY_PALADIN = 10,
SPELLFAMILY_SHAMAN = 11,
- SPELLFAMILY_UNK2 = 12,
- SPELLFAMILY_POTION = 13
+ SPELLFAMILY_UNK2 = 12, // 2 spells (silence resistance)
+ SPELLFAMILY_POTION = 13,
+ // 14 - unused
+ SPELLFAMILY_DEATHKNIGHT = 15,
+ // 16 - unused
+ SPELLFAMILY_PET = 17
};
enum SpellDisableTypes
@@ -241,6 +82,7 @@ enum SpellEffectTargetTypes
SPELL_REQUIRE_DEST,
SPELL_REQUIRE_ITEM,
SPELL_REQUIRE_CASTER,
+ SPELL_REQUIRE_GOBJECT,
};
enum SpellSelectTargetTypes
@@ -260,15 +102,15 @@ enum SpellSelectTargetTypes
};
//Some SpellFamilyFlags
-#define SPELLFAMILYFLAG_ROGUE_VANISH 0x000000800LL
-#define SPELLFAMILYFLAG_ROGUE_STEALTH 0x000400000LL
-#define SPELLFAMILYFLAG_ROGUE_BACKSTAB 0x000800004LL
-#define SPELLFAMILYFLAG_ROGUE_SAP 0x000000080LL
-#define SPELLFAMILYFLAG_ROGUE_FEINT 0x008000000LL
-#define SPELLFAMILYFLAG_ROGUE_KIDNEYSHOT 0x000200000LL
-#define SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE 0x9003E0000LL
-#define SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR 0x000004000LL
-#define SPELLFAMILYFLAG_SHAMAN_FROST_SHOCK 0x080000000LL
+#define SPELLFAMILYFLAG_ROGUE_VANISH 0x00000800
+#define SPELLFAMILYFLAG_ROGUE_STEALTH 0x00400000
+#define SPELLFAMILYFLAG_ROGUE_BACKSTAB 0x00800004
+#define SPELLFAMILYFLAG_ROGUE_SAP 0x00000080
+#define SPELLFAMILYFLAG_ROGUE_FEINT 0x08000000
+#define SPELLFAMILYFLAG_ROGUE_KIDNEYSHOT 0x00200000
+//#define SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE 0x9003E0000LL
+#define SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR 0x00004000
+#define SPELLFAMILYFLAG_SHAMAN_FROST_SHOCK 0x80000000
// Spell clasification
enum SpellSpecific
@@ -294,8 +136,11 @@ enum SpellSpecific
SPELL_WELL_FED = 18,
SPELL_DRINK = 19,
SPELL_FOOD = 20,
- SPELL_CHARM = 21,
- SPELL_WARRIOR_ENRAGE = 22,
+ SPELL_PRESENCE = 21,
+ SPELL_CHARM = 22,
+ SPELL_SCROLL = 23,
+ SPELL_MAGE_ARCANE_BRILLANCE = 24,
+ SPELL_WARRIOR_ENRAGE = 25,
};
#define SPELL_LINKED_MAX_SPELLS 200000
@@ -311,19 +156,60 @@ enum SpellLinkedType
SpellSpecific GetSpellSpecific(uint32 spellId);
// Different spell properties
-inline float GetSpellRadius(SpellRadiusEntry const *radius) { return (radius ? radius->Radius : 0); }
+inline float GetSpellRadiusForHostile(SpellRadiusEntry const *radius) { return (radius ? radius->radiusHostile : 0); }
+inline float GetSpellRadiusForFriend(SpellRadiusEntry const *radius) { return (radius ? radius->radiusFriend : 0); }
uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell = NULL);
-inline float GetSpellMinRange(SpellRangeEntry const *range) { return (range ? range->minRange : 0); }
-inline float GetSpellMaxRange(SpellRangeEntry const *range) { return (range ? range->maxRange : 0); }
+bool GetDispelChance(Unit* caster, uint32 spellId);
+inline float GetSpellMinRangeForHostile(SpellRangeEntry const *range) { return (range ? range->minRangeHostile : 0); }
+inline float GetSpellMaxRangeForHostile(SpellRangeEntry const *range) { return (range ? range->maxRangeHostile : 0); }
+inline float GetSpellMinRangeForFriend(SpellRangeEntry const *range) { return (range ? range->minRangeFriend : 0); }
+inline float GetSpellMaxRangeForFriend(SpellRangeEntry const *range) { return (range ? range->maxRangeFriend : 0); }
inline uint32 GetSpellRangeType(SpellRangeEntry const *range) { return (range ? range->type : 0); }
inline uint32 GetSpellRecoveryTime(SpellEntry const *spellInfo) { return spellInfo->RecoveryTime > spellInfo->CategoryRecoveryTime ? spellInfo->RecoveryTime : spellInfo->CategoryRecoveryTime; }
int32 GetSpellDuration(SpellEntry const *spellInfo);
int32 GetSpellMaxDuration(SpellEntry const *spellInfo);
+inline float GetSpellRadius(SpellEntry const *spellInfo, uint32 effectIdx, bool positive)
+{
+ return positive
+ ? GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(spellInfo->EffectRadiusIndex[effectIdx]))
+ : GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(spellInfo->EffectRadiusIndex[effectIdx]));
+}
+inline float GetSpellMaxRange(SpellEntry const *spellInfo, bool positive)
+{
+ return positive
+ ? GetSpellMaxRangeForFriend(sSpellRangeStore.LookupEntry(spellInfo->rangeIndex))
+ : GetSpellMaxRangeForHostile(sSpellRangeStore.LookupEntry(spellInfo->rangeIndex));
+}
+inline float GetSpellMinRange(SpellEntry const *spellInfo, bool positive)
+{
+ return positive
+ ? GetSpellMinRangeForFriend(sSpellRangeStore.LookupEntry(spellInfo->rangeIndex))
+ : GetSpellMinRangeForHostile(sSpellRangeStore.LookupEntry(spellInfo->rangeIndex));
+}
+inline float GetSpellMaxRange(uint32 id, bool positive)
+{
+ SpellEntry const *spellInfo = GetSpellStore()->LookupEntry(id);
+ if(!spellInfo) return 0;
+ return GetSpellMaxRange(spellInfo, positive);
+}
+
+/*struct DispelEntry
+{
+ uint64 casterGuid;
+ uint32 spellId;
+ Unit * caster;
+ uint8 stackAmount;
+
+ bool operator < (const DispelEntry & _Right) const
+ {
+ return (spellId != _Right.spellId ? spellId < _Right.spellId : casterGuid < _Right.casterGuid);
+ }
+};*/
inline bool IsSpellHaveEffect(SpellEntry const *spellInfo, SpellEffects effect)
{
for(int i= 0; i < 3; ++i)
- if(spellInfo->Effect[i]==effect)
+ if(SpellEffects(spellInfo->Effect[i])==effect)
return true;
return false;
}
@@ -334,30 +220,48 @@ inline bool IsSealSpell(SpellEntry const *spellInfo)
{
//Collection of all the seal family flags. No other paladin spell has any of those.
return spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN &&
- ( spellInfo->SpellFamilyFlags & 0x4000A000200LL );
+ ( spellInfo->SpellFamilyFlags[1] & 0x26000C00
+ || spellInfo->SpellFamilyFlags[0] & 0x0A000000 );
}
inline bool IsElementalShield(SpellEntry const *spellInfo)
{
// family flags 10 (Lightning), 42 (Earth), 37 (Water), proc shield from T2 8 pieces bonus
- return (spellInfo->SpellFamilyFlags & 0x42000000400LL) || spellInfo->Id == 23552;
+ return (spellInfo->SpellFamilyFlags[1] & 0x420
+ || spellInfo->SpellFamilyFlags[0] & 0x00000400)
+ || spellInfo->Id == 23552;
}
-int32 CompareAuraRanks(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2);
+inline bool IsExplicitDiscoverySpell(SpellEntry const *spellInfo)
+{
+ return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_ITEM_2 && spellInfo->Effect[1]==SPELL_EFFECT_SCRIPT_EFFECT;
+}
+
+inline bool IsLootCraftingSpell(SpellEntry const *spellInfo)
+{
+ return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_ITEM_2 && (
+ spellInfo->Effect[1]==SPELL_EFFECT_SCRIPT_EFFECT || // see IsExplicitDiscoverySpell
+ !spellInfo->EffectItemType[0] || // result item not provided
+ spellInfo->TotemCategory[0] == 121); // different random cards from Inscription (121==Virtuoso Inking Set category)
+}
+
+bool IsHigherHankOfSpell(uint32 spellId_1,uint32 spellId_2);
bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1, uint32 spellSpec2);
bool IsSingleFromSpellSpecificPerTarget(uint32 spellSpec1, uint32 spellSpec2);
bool IsPassiveSpell(uint32 spellId);
+bool IsAutocastableSpell(uint32 spellId);
-inline bool IsDeathPersistentSpell(SpellEntry const *spellInfo)
+inline bool IsPassiveSpellStackableWithRanks(SpellEntry const* spellProto)
{
- switch(spellInfo->Id)
- {
- case 40214: // Dragonmaw Illusion
- case 35480: case 35481: case 35482: // Human Illusion
- case 35483: case 39824: // Human Illusion
- return true;
- }
+ if(!IsPassiveSpell(spellProto->Id))
+ return false;
+ return !IsSpellHaveEffect(spellProto,SPELL_EFFECT_APPLY_AURA);
+}
+
+
+inline bool IsDeathPersistentSpell(SpellEntry const *spellInfo)
+{
return spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DEATH_PERSISTENT;
}
@@ -366,18 +270,18 @@ inline bool IsNonCombatSpell(SpellEntry const *spellInfo)
return (spellInfo->Attributes & SPELL_ATTR_CANT_USED_IN_COMBAT) != 0;
}
-bool IsPositiveSpell(uint32 spellId);
-bool IsPositiveEffect(uint32 spellId, uint32 effIndex);
+bool IsPositiveSpell(uint32 spellId, bool deep = false);
+bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep = false);
bool IsPositiveTarget(uint32 targetA, uint32 targetB);
+bool IsDispelableBySpell(SpellEntry const * dispelSpell, uint32 spellId, bool def = false);
bool IsSingleTargetSpell(SpellEntry const *spellInfo);
bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2);
bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId);
-bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id);
-
extern bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS];
+
inline bool IsAreaOfEffectSpell(SpellEntry const *spellInfo)
{
if(IsAreaEffectTarget[spellInfo->EffectImplicitTargetA[0]] || IsAreaEffectTarget[spellInfo->EffectImplicitTargetB[0]])
@@ -392,6 +296,7 @@ inline bool IsAreaOfEffectSpell(SpellEntry const *spellInfo)
inline bool IsAreaAuraEffect(uint32 effect)
{
if( effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY ||
+ effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID ||
effect == SPELL_EFFECT_APPLY_AREA_AURA_FRIEND ||
effect == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY ||
effect == SPELL_EFFECT_APPLY_AREA_AURA_PET ||
@@ -408,6 +313,7 @@ inline bool IsDispel(SpellEntry const *spellInfo)
return true;
return false;
}
+
inline bool IsDispelSpell(SpellEntry const *spellInfo)
{
//spellsteal is also dispel
@@ -424,7 +330,19 @@ inline bool isSpellBreakStealth(SpellEntry const* spellInfo)
return !(spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH);
}
-uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form);
+inline bool IsAutoRepeatRangedSpell(SpellEntry const* spellInfo)
+{
+ return spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG;
+}
+
+inline bool IsRangedWeaponSpell(SpellEntry const* spellInfo)
+{
+ //spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED should be checked outside
+ return (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER) // for 53352, cannot find better way
+ || (spellInfo->EquippedItemSubClassMask & ITEM_SUBCLASS_MASK_WEAPON_RANGED);
+}
+
+SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form);
inline bool IsChanneledSpell(SpellEntry const* spellInfo)
{
@@ -451,6 +369,17 @@ inline uint32 GetSpellMechanicMask(SpellEntry const* spellInfo, int32 effect)
return mask;
}
+inline uint32 GetAllSpellMechanicMask(SpellEntry const* spellInfo)
+{
+ uint32 mask = 0;
+ if (spellInfo->Mechanic)
+ mask |= 1<<spellInfo->Mechanic;
+ for (int i=0; i< 3; ++i)
+ if (spellInfo->EffectMechanic[i])
+ mask |= 1<<spellInfo->EffectMechanic[i];
+ return mask;
+}
+
inline Mechanics GetEffectMechanic(SpellEntry const* spellInfo, int32 effect)
{
if (spellInfo->EffectMechanic[effect])
@@ -475,7 +404,7 @@ bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group);
DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group);
// Spell affects related declarations (accessed using SpellMgr functions)
-typedef std::map<uint32, uint64> SpellAffectMap;
+typedef UNORDERED_MAP<uint32, flag96> SpellAffectMap;
// Spell proc event related declarations (accessed using SpellMgr functions)
enum ProcFlags
@@ -483,16 +412,16 @@ enum ProcFlags
PROC_FLAG_NONE = 0x00000000,
PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor
- PROC_FLAG_KILL_AND_GET_XP = 0x00000002, // 01 Kill that yields experience or honor
+ PROC_FLAG_KILL = 0x00000002, // 01 Kill target (in most cases need XP/Honor reward)
- PROC_FLAG_SUCCESSFUL_MILEE_HIT = 0x00000004, // 02 Successful melee attack
- PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee strike hit
+ PROC_FLAG_SUCCESSFUL_MILEE_HIT = 0x00000004, // 02 Successful melee auto attack
+ PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee auto attack hit
PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT = 0x00000010, // 04 Successful attack by Spell that use melee weapon
PROC_FLAG_TAKEN_MELEE_SPELL_HIT = 0x00000020, // 05 Taken damage by Spell that use melee weapon
- PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged attack (all ranged attack deal as spell so newer set :( )
- PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged attack (all ranged attack deal as spell so newer set :( )
+ PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged auto attack
+ PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged auto attack
PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT = 0x00000100, // 08 Successful Ranged attack by Spell that use ranged weapon
PROC_FLAG_TAKEN_RANGED_SPELL_HIT = 0x00000200, // 09 Taken damage by Spell that use ranged weapon
@@ -517,6 +446,7 @@ enum ProcFlags
PROC_FLAG_TAKEN_OFFHAND_HIT = 0x00400000, // 22 Taken off-hand melee attacks(not used)
PROC_FLAG_SUCCESSFUL_OFFHAND_HIT = 0x00800000 // 23 Successful off-hand melee attacks
+// PROC_FLAG_DEATH = 0x01000000
};
#define MELEE_BASED_TRIGGER_MASK (PROC_FLAG_SUCCESSFUL_MILEE_HIT | \
@@ -543,21 +473,31 @@ enum ProcFlagsEx
PROC_EX_DEFLECT = 0x0000200,
PROC_EX_ABSORB = 0x0000400,
PROC_EX_REFLECT = 0x0000800,
- PROC_EX_INTERRUPT = 0x0001000, // Melle hit result can be Interrupt (not used)
- PROC_EX_RESERVED1 = 0x0002000,
- PROC_EX_RESERVED2 = 0x0004000,
- PROC_EX_RESERVED3 = 0x0008000,
+ PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used)
+ PROC_EX_AURA_REMOVE_DESTROY = 0x0002000, // aura absorb destroy or dispel
+ PROC_EX_AURA_REMOVE_EXPIRE = 0x0004000, // aura remove by default and by cancel
PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always ( no matter another flags) used for drop charges
- PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time
- PROC_EX_INTERNAL_HOT = 0x1000000, // Only for internal use
- PROC_EX_INTERNAL_DOT = 0x2000000 // Only for internal use
+ PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not used)
+ PROC_EX_INTERNAL_CANT_PROC = 0x0800000,
+ PROC_EX_INTERNAL_DOT = 0x1000000, // Only for internal use
+ PROC_EX_INTERNAL_HOT = 0x2000000, // Only for internal use
+ PROC_EX_INTERNAL_TRIGGERED = 0x4000000, // Only for internal use
+ PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000 // Only for internal use
};
+#define AURA_REMOVE_PROC_EX_MASK \
+ (PROC_EX_AURA_REMOVE_DESTROY | PROC_EX_AURA_REMOVE_EXPIRE)
+
+#define AURA_SPELL_PROC_EX_MASK \
+ (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT | PROC_EX_MISS | \
+ PROC_EX_RESIST | PROC_EX_DODGE | PROC_EX_PARRY | PROC_EX_BLOCK | \
+ PROC_EX_EVADE | PROC_EX_IMMUNE | PROC_EX_DEFLECT | \
+ PROC_EX_ABSORB | PROC_EX_REFLECT | PROC_EX_INTERRUPT)
struct SpellProcEventEntry
{
uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value
- uint64 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
+ flag96 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
uint32 procFlags; // bitmask for matching proc event
uint32 procEx; // proc Extend info (see ProcFlagsEx)
float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc
@@ -565,6 +505,13 @@ struct SpellProcEventEntry
uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_
};
+struct SpellBonusEntry
+{
+ float direct_damage;
+ float dot_damage;
+ float ap_bonus;
+};
+
typedef UNORDERED_MAP<uint32, SpellProcEventEntry> SpellProcEventMap;
struct SpellEnchantProcEntry
@@ -575,6 +522,7 @@ struct SpellEnchantProcEntry
};
typedef UNORDERED_MAP<uint32, SpellEnchantProcEntry> SpellEnchantProcEventMap;
+typedef UNORDERED_MAP<uint32, SpellBonusEntry> SpellBonusMap;
#define ELIXIR_BATTLE_MASK 0x1
#define ELIXIR_GUARDIAN_MASK 0x2
@@ -637,9 +585,9 @@ class PetAura
return itr->second;
else
{
- std::map<uint16, uint16>::const_iterator itr = auras.find(0);
- if(itr != auras.end())
- return itr->second;
+ std::map<uint16, uint16>::const_iterator itr2 = auras.find(0);
+ if(itr2 != auras.end())
+ return itr2->second;
else
return 0;
}
@@ -667,6 +615,32 @@ class PetAura
};
typedef std::map<uint16, PetAura> SpellPetAuraMap;
+struct SpellArea
+{
+ uint32 spellId;
+ uint32 areaId; // zone/subzone/or 0 is not limited to zone
+ uint32 questStart; // quest start (quest must be active or rewarded for spell apply)
+ uint32 questEnd; // quest end (quest don't must be rewarded for spell apply)
+ int32 auraSpell; // spell aura must be applied for spell apply )if possitive) and it don't must be applied in other case
+ uint32 raceMask; // can be applied only to races
+ Gender gender; // can be applied only to gender
+ bool questStartCanActive; // if true then quest start can be active (not only rewarded)
+ bool autocast; // if true then auto applied at area enter, in other case just allowed to cast
+
+ // helpers
+ bool IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const;
+};
+
+typedef std::multimap<uint32,SpellArea> SpellAreaMap;
+typedef std::multimap<uint32,SpellArea const*> SpellAreaForQuestMap;
+typedef std::multimap<uint32,SpellArea const*> SpellAreaForAuraMap;
+typedef std::multimap<uint32,SpellArea const*> SpellAreaForAreaMap;
+typedef std::pair<SpellAreaMap::const_iterator,SpellAreaMap::const_iterator> SpellAreaMapBounds;
+typedef std::pair<SpellAreaForQuestMap::const_iterator,SpellAreaForQuestMap::const_iterator> SpellAreaForQuestMapBounds;
+typedef std::pair<SpellAreaForAuraMap::const_iterator, SpellAreaForAuraMap::const_iterator> SpellAreaForAuraMapBounds;
+typedef std::pair<SpellAreaForAreaMap::const_iterator, SpellAreaForAreaMap::const_iterator> SpellAreaForAreaMapBounds;
+
+
// Spell rank chain (accessed using SpellMgr functions)
struct SpellChainNode
{
@@ -697,6 +671,7 @@ typedef std::map<uint32, SpellLearnSkillNode> SpellLearnSkillMap;
struct SpellLearnSpellNode
{
uint32 spell;
+ bool active; // show in spellbook or not
bool autoLearned;
};
@@ -704,6 +679,18 @@ typedef std::multimap<uint32, SpellLearnSpellNode> SpellLearnSpellMap;
typedef std::multimap<uint32, SkillLineAbilityEntry const*> SkillLineAbilityMap;
+typedef std::multimap<uint32, uint32> PetLevelupSpellSet;
+typedef std::map<uint32, PetLevelupSpellSet> PetLevelupSpellMap;
+
+struct PetDefaultSpellsEntry
+{
+ uint32 spellid[MAX_CREATURE_SPELL_DATA_SLOT];
+};
+
+// < 0 for petspelldata id, > 0 for creature_id
+typedef std::map<int32, PetDefaultSpellsEntry> PetDefaultSpellsMap;
+
+
inline bool IsPrimaryProfessionSkill(uint32 skill)
{
SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(skill);
@@ -736,12 +723,19 @@ inline bool IsProfessionSkill(uint32 skill)
#define SPELL_ATTR_CU_LINK_AURA 0x00001000
#define SPELL_ATTR_CU_LINK_REMOVE 0x00002000
#define SPELL_ATTR_CU_MOVEMENT_IMPAIR 0x00004000
+#define SPELL_ATTR_CU_EXCLUDE_SELF 0x00008000
typedef std::vector<uint32> SpellCustomAttribute;
+typedef std::vector<bool> EnchantCustomAttribute;
typedef std::map<int32, std::vector<int32> > SpellLinkedMap;
+inline bool IsProfessionOrRidingSkill(uint32 skill)
+{
+ return IsProfessionSkill(skill) || skill == SKILL_RIDING;
+}
+
class SpellMgr
{
// Constructors
@@ -749,18 +743,18 @@ class SpellMgr
SpellMgr();
~SpellMgr();
- // Accessors (const or static functions)
+ // Accessors (const or static functions)
public:
// Spell affects
- uint64 GetSpellAffectMask(uint16 spellId, uint8 effectId) const
+ flag96 const*GetSpellAffect(uint16 spellId, uint8 effectId) const
{
SpellAffectMap::const_iterator itr = mSpellAffectMap.find((spellId<<8) + effectId);
if( itr != mSpellAffectMap.end( ) )
- return itr->second;
+ return &itr->second;
return 0;
}
- bool IsAffectedBySpell(SpellEntry const *spellInfo, uint32 spellId, uint8 effectId, uint64 familyFlags) const;
+ bool IsAffectedByMod(SpellEntry const *spellInfo, SpellModifier *mod) const;
SpellElixirMap const& GetSpellElixirMap() const { return mSpellElixirs; }
@@ -795,7 +789,7 @@ class SpellMgr
return NULL;
}
- static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active);
+ bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active);
SpellEnchantProcEntry const* GetSpellEnchantProcEvent(uint32 enchId) const
{
@@ -805,6 +799,23 @@ class SpellMgr
return NULL;
}
+ // Spell bonus data
+ SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const
+ {
+ // Lookup data
+ SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId);
+ if( itr != mSpellBonusMap.end( ) )
+ return &itr->second;
+ // Not found, try lookup for 1 spell rank if exist
+ if (uint32 rank_1 = GetFirstSpellInChain(spellId))
+ {
+ SpellBonusMap::const_iterator itr2 = mSpellBonusMap.find(rank_1);
+ if( itr2 != mSpellBonusMap.end( ) )
+ return &itr2->second;
+ }
+ return NULL;
+ }
+
// Spell target coordinates
SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id) const
{
@@ -849,6 +860,14 @@ class SpellMgr
return 0;
}
+ uint32 GetNextSpellInChain(uint32 spell_id) const
+ {
+ if(SpellChainNode const* node = GetSpellChainNode(spell_id))
+ return node->next;
+
+ return 0;
+ }
+
SpellsRequiringSpellMap const& GetSpellsRequiringSpell() const { return mSpellsReqSpell; }
// Note: not use rank for compare to spell ranks: spell chains isn't linear order
@@ -869,6 +888,11 @@ class SpellMgr
return spell_id;
}
+ uint32 IsArenaAllowedEnchancment(uint32 ench_id) const
+ {
+ return mEnchantCustomAttr[ench_id];
+ }
+
uint8 IsHighRankOfSpell(uint32 spell1,uint32 spell2) const
{
SpellChainMap::const_iterator itr = mSpellChains.find(spell1);
@@ -905,7 +929,7 @@ class SpellMgr
bool IsSpellLearnSpell(uint32 spell_id) const
{
- return mSpellLearnSpells.count(spell_id)!=0;
+ return mSpellLearnSpells.find(spell_id) != mSpellLearnSpells.end();
}
SpellLearnSpellMap::const_iterator GetBeginSpellLearnSpell(uint32 spell_id) const
@@ -928,10 +952,15 @@ class SpellMgr
return false;
}
+ static bool IsProfessionOrRidingSpell(uint32 spellId);
static bool IsProfessionSpell(uint32 spellId);
static bool IsPrimaryProfessionSpell(uint32 spellId);
bool IsPrimaryProfessionFirstRankSpell(uint32 spellId) const;
+ bool IsSkillBonusSpell(uint32 spellId) const;
+ bool IsSkillTypeSpell(uint32 spellId, SkillType type) const;
+
+
// Spell script targets
SpellScriptTarget::const_iterator GetBeginSpellScriptTarget(uint32 spell_id) const
{
@@ -965,17 +994,21 @@ class SpellMgr
return NULL;
}
+ PetLevelupSpellSet const* GetPetLevelupSpellList(uint32 petFamily) const
+ {
+ PetLevelupSpellMap::const_iterator itr = mPetLevelupSpellMap.find(petFamily);
+ if(itr != mPetLevelupSpellMap.end())
+ return &itr->second;
+ else
+ return NULL;
+ }
+
uint32 GetSpellCustomAttr(uint32 spell_id) const
{
if(spell_id >= mSpellCustomAttr.size())
return 0;
else
return mSpellCustomAttr[spell_id];
- /*SpellCustomAttrMap::const_iterator itr = mSpellCustomAttrMap.find(spell_id);
- if(itr != mSpellCustomAttrMap.end())
- return itr->second;
- else
- return 0;*/
}
const std::vector<int32> *GetSpellLinked(int32 spell_id) const
@@ -987,7 +1020,46 @@ class SpellMgr
SpellEffectTargetTypes EffectTargetType[TOTAL_SPELL_EFFECTS];
SpellSelectTargetTypes SpellTargetType[TOTAL_SPELL_TARGETS];
- // Modifiers
+ // < 0 for petspelldata id, > 0 for creature_id
+ PetDefaultSpellsEntry const* GetPetDefaultSpellsEntry(int32 id) const
+ {
+ PetDefaultSpellsMap::const_iterator itr = mPetDefaultSpellsMap.find(id);
+ if(itr != mPetDefaultSpellsMap.end())
+ return &itr->second;
+ return NULL;
+ }
+
+ SpellCastResult GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL);
+
+ SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const
+ {
+ return SpellAreaMapBounds(mSpellAreaMap.lower_bound(spell_id),mSpellAreaMap.upper_bound(spell_id));
+ }
+
+ SpellAreaForQuestMapBounds GetSpellAreaForQuestMapBounds(uint32 quest_id, bool active) const
+ {
+ if(active)
+ return SpellAreaForQuestMapBounds(mSpellAreaForActiveQuestMap.lower_bound(quest_id),mSpellAreaForActiveQuestMap.upper_bound(quest_id));
+ else
+ return SpellAreaForQuestMapBounds(mSpellAreaForQuestMap.lower_bound(quest_id),mSpellAreaForQuestMap.upper_bound(quest_id));
+ }
+
+ SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const
+ {
+ return SpellAreaForQuestMapBounds(mSpellAreaForQuestEndMap.lower_bound(quest_id),mSpellAreaForQuestEndMap.upper_bound(quest_id));
+ }
+
+ SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const
+ {
+ return SpellAreaForAuraMapBounds(mSpellAreaForAuraMap.lower_bound(spell_id),mSpellAreaForAuraMap.upper_bound(spell_id));
+ }
+
+ SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const
+ {
+ return SpellAreaForAreaMapBounds(mSpellAreaForAreaMap.lower_bound(area_id),mSpellAreaForAreaMap.upper_bound(area_id));
+ }
+
+ // Modifiers
public:
static SpellMgr& Instance();
@@ -1000,13 +1072,18 @@ class SpellMgr
void LoadSpellAffects();
void LoadSpellElixirs();
void LoadSpellProcEvents();
+ void LoadSpellBonusess();
void LoadSpellTargetPositions();
void LoadSpellThreats();
void LoadSkillLineAbilityMap();
void LoadSpellPetAuras();
void LoadSpellCustomAttr();
- void LoadSpellLinked();
+ void LoadEnchantCustomAttr();
void LoadSpellEnchantProcData();
+ void LoadSpellLinked();
+ void LoadPetLevelupSpellMap();
+ void LoadPetDefaultSpells();
+ void LoadSpellAreas();
private:
SpellScriptTarget mSpellScriptTarget;
@@ -1019,11 +1096,21 @@ class SpellMgr
SpellAffectMap mSpellAffectMap;
SpellElixirMap mSpellElixirs;
SpellProcEventMap mSpellProcEventMap;
+ SpellBonusMap mSpellBonusMap;
SkillLineAbilityMap mSkillLineAbilityMap;
SpellPetAuraMap mSpellPetAuraMap;
SpellCustomAttribute mSpellCustomAttr;
SpellLinkedMap mSpellLinkedMap;
SpellEnchantProcEventMap mSpellEnchantProcEventMap;
+ EnchantCustomAttribute mEnchantCustomAttr;
+ PetLevelupSpellMap mPetLevelupSpellMap;
+ PetDefaultSpellsMap mPetDefaultSpellsMap; // only spells not listed in related mPetLevelupSpellMap entry
+ SpellAreaMap mSpellAreaMap;
+ SpellAreaForQuestMap mSpellAreaForQuestMap;
+ SpellAreaForQuestMap mSpellAreaForActiveQuestMap;
+ SpellAreaForQuestMap mSpellAreaForQuestEndMap;
+ SpellAreaForAuraMap mSpellAreaForAuraMap;
+ SpellAreaForAreaMap mSpellAreaForAreaMap;
};
#define spellmgr SpellMgr::Instance()
diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp
index ae96953e337..4cf93760957 100644
--- a/src/game/StatSystem.cpp
+++ b/src/game/StatSystem.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -51,24 +51,17 @@ bool Player::UpdateStats(Stats stat)
switch(stat)
{
case STAT_STRENGTH:
- UpdateAttackPowerAndDamage();
UpdateShieldBlockValue();
break;
case STAT_AGILITY:
UpdateArmor();
- UpdateAttackPowerAndDamage(true);
- if(getClass() == CLASS_ROGUE || getClass() == CLASS_HUNTER || getClass() == CLASS_DRUID && m_form==FORM_CAT)
- UpdateAttackPowerAndDamage();
-
UpdateAllCritPercentages();
UpdateDodgePercentage();
break;
-
case STAT_STAMINA: UpdateMaxHealth(); break;
case STAT_INTELLECT:
UpdateMaxPower(POWER_MANA);
UpdateAllSpellCritChances();
- UpdateAttackPowerAndDamage(true); //SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, only intellect currently
UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently
break;
@@ -78,11 +71,60 @@ bool Player::UpdateStats(Stats stat)
default:
break;
}
+
+ if (stat == STAT_STRENGTH)
+ {
+ UpdateAttackPowerAndDamage(false);
+ if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, stat))
+ UpdateAttackPowerAndDamage(true);
+ }
+ else if (stat == STAT_AGILITY)
+ {
+ UpdateAttackPowerAndDamage(false);
+ UpdateAttackPowerAndDamage(true);
+ }
+ else
+ {
+ // Need update (exist AP from stat auras)
+ if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT, stat))
+ UpdateAttackPowerAndDamage(false);
+ if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, stat))
+ UpdateAttackPowerAndDamage(true);
+ }
+
UpdateSpellDamageAndHealingBonus();
UpdateManaRegen();
+
+ // Update ratings in exist SPELL_AURA_MOD_RATING_FROM_STAT and only depends from stat
+ uint32 mask = 0;
+ AuraEffectList const& modRatingFromStat = GetAurasByType(SPELL_AURA_MOD_RATING_FROM_STAT);
+ for(AuraEffectList::const_iterator i = modRatingFromStat.begin();i != modRatingFromStat.end(); ++i)
+ if (Stats((*i)->GetMiscBValue()) == stat)
+ mask |= (*i)->GetMiscValue();
+ if (mask)
+ {
+ for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ if (mask & (1 << rating))
+ ApplyRatingMod(CombatRating(rating), 0, true);
+ }
return true;
}
+void Player::ApplySpellDamageBonus(int32 amount, bool apply)
+{
+ m_baseSpellDamage+=apply?amount:-amount;
+ // For speed just update for client
+ for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
+ ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, amount, apply);
+}
+
+void Player::ApplySpellHealingBonus(int32 amount, bool apply)
+{
+ m_baseSpellHealing+=apply?amount:-amount;
+ // For speed just update for client
+ ApplyModUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, amount, apply);
+}
+
void Player::UpdateSpellDamageAndHealingBonus()
{
// Magic damage modifiers implemented in Unit::SpellDamageBonus
@@ -90,13 +132,13 @@ void Player::UpdateSpellDamageAndHealingBonus()
// Get healing bonus for all schools
SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL));
// Get damage bonus for all schools
- for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
+ for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i)));
}
bool Player::UpdateAllStats()
{
- for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
+ for (int i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
float value = GetTotalStatValue(Stats(i));
SetStat(Stats(i), (int32)value);
@@ -107,7 +149,7 @@ bool Player::UpdateAllStats()
UpdateArmor();
UpdateMaxHealth();
- for(int i = POWER_MANA; i < MAX_POWERS; i++)
+ for(int i = POWER_MANA; i < MAX_POWERS; ++i)
UpdateMaxPower(Powers(i));
UpdateAllCritPercentages();
@@ -118,7 +160,7 @@ bool Player::UpdateAllStats()
UpdateManaRegen();
UpdateExpertise(BASE_ATTACK);
UpdateExpertise(OFF_ATTACK);
- for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
+ for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
UpdateResistances(i);
return true;
@@ -150,12 +192,11 @@ void Player::UpdateArmor()
value += GetModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
- AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
- for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i)
+ AuraEffectList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
+ for(AuraEffectList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
- value += int32(GetStat(Stats((*i)->GetMiscBValue())) * (*i)->GetModifierValue() / 100.0f);
+ if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
+ value += int32(GetStat(Stats((*i)->GetMiscBValue())) * (*i)->GetAmount() / 100.0f);
}
value *= GetModifierValue(unitMod, TOTAL_PCT);
@@ -213,6 +254,12 @@ void Player::UpdateMaxPower(Powers power)
SetMaxPower(power, uint32(value));
}
+void Player::ApplyFeralAPBonus(int32 amount, bool apply)
+{
+ m_baseFeralAP+= apply ? amount:-amount;
+ UpdateAttackPowerAndDamage();
+}
+
void Player::UpdateAttackPowerAndDamage(bool ranged )
{
float val2 = 0.0f;
@@ -253,11 +300,12 @@ void Player::UpdateAttackPowerAndDamage(bool ranged )
{
switch(getClass())
{
- case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
- case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
- case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
- case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
- case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ case CLASS_DEATH_KNIGHT: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
+ case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
+ case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break;
case CLASS_DRUID:
{
//Check if Predatory Strikes is skilled
@@ -269,13 +317,13 @@ void Player::UpdateAttackPowerAndDamage(bool ranged )
case FORM_DIREBEAR:
case FORM_MOONKIN:
{
- Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
+ Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
{
// Predatory Strikes
if ((*itr)->GetSpellProto()->SpellIconID == 1563)
{
- mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f;
+ mLevelMult = (*itr)->GetAmount() / 100.0f;
break;
}
}
@@ -286,12 +334,12 @@ void Player::UpdateAttackPowerAndDamage(bool ranged )
switch(m_form)
{
case FORM_CAT:
- val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break;
+ val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f + m_baseFeralAP; break;
case FORM_BEAR:
case FORM_DIREBEAR:
- val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f + m_baseFeralAP; break;
case FORM_MOONKIN:
- val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
+ val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f + m_baseFeralAP; break;
default:
val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break;
}
@@ -309,17 +357,26 @@ void Player::UpdateAttackPowerAndDamage(bool ranged )
float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
- if( ranged && (getClassMask() & CLASSMASK_WAND_USERS)==0)
+ if( ranged )
{
- AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
- for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i)
- attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifierValue() / 100.0f);
+ if ((getClassMask() & CLASSMASK_WAND_USERS)==0)
+ {
+ AuraEffectList const& mRAPbyStat = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
+ for(AuraEffectList::const_iterator i = mRAPbyStat.begin();i != mRAPbyStat.end(); ++i)
+ attPowerMod += int32(GetStat(Stats((*i)->GetMiscValue())) * (*i)->GetAmount() / 100.0f);
+ }
+ }
+ else
+ {
+ AuraEffectList const& mAPbyStat = GetAurasByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT);
+ for(AuraEffectList::const_iterator i = mAPbyStat.begin();i != mAPbyStat.end(); ++i)
+ attPowerMod += int32(GetStat(Stats((*i)->GetMiscValue())) * (*i)->GetAmount() / 100.0f);
}
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
- SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
- SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
+ SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
+ SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
//automatically update weapon damage after attack power modification
@@ -386,8 +443,15 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, fl
weapon_mindamage = lvl*0.85*att_speed;
weapon_maxdamage = lvl*1.25*att_speed;
}
- else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc)
+ else if(!CanUseAttackType(attType)) //check if player not in form but still can't use (disarm case)
{
+ //cannot use ranged/off attack, set values to 0
+ if (attType != BASE_ATTACK)
+ {
+ min_damage=0;
+ max_damage=0;
+ return;
+ }
weapon_mindamage = BASE_MINDAMAGE;
weapon_maxdamage = BASE_MAXDAMAGE;
}
@@ -554,9 +618,27 @@ void Player::UpdateSpellCritChance(uint32 school)
SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit);
}
+void Player::UpdateMeleeHitChances()
+{
+ m_modMeleeHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
+ m_modMeleeHitChance+= GetRatingBonusValue(CR_HIT_MELEE);
+}
+
+void Player::UpdateRangedHitChances()
+{
+ m_modRangedHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_HIT_CHANCE);
+ m_modRangedHitChance+= GetRatingBonusValue(CR_HIT_RANGED);
+}
+
+void Player::UpdateSpellHitChances()
+{
+ m_modSpellHitChance = GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
+ m_modSpellHitChance+= GetRatingBonusValue(CR_HIT_SPELL);
+}
+
void Player::UpdateAllSpellCritChances()
{
- for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
+ for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
UpdateSpellCritChance(i);
}
@@ -569,15 +651,15 @@ void Player::UpdateExpertise(WeaponAttackType attack)
Item *weapon = GetWeaponForAttack(attack);
- AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE);
- for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
+ AuraEffectList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE);
+ for(AuraEffectList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
{
// item neutral spell
if((*itr)->GetSpellProto()->EquippedItemClass == -1)
- expertise += (*itr)->GetModifierValue();
+ expertise += (*itr)->GetAmount();
// item dependent spell
else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
- expertise += (*itr)->GetModifierValue();
+ expertise += (*itr)->GetAmount();
}
if(expertise < 0)
@@ -591,6 +673,12 @@ void Player::UpdateExpertise(WeaponAttackType attack)
}
}
+void Player::ApplyManaRegenBonus(int32 amount, bool apply)
+{
+ m_baseManaRegen+= apply ? amount : -amount;
+ UpdateManaRegen();
+}
+
void Player::UpdateManaRegen()
{
float Intellect = GetStat(STAT_INTELLECT);
@@ -600,33 +688,22 @@ void Player::UpdateManaRegen()
power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA);
// Mana regen from SPELL_AURA_MOD_POWER_REGEN aura
- float power_regen_mp5 = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f;
+ float power_regen_mp5 = (GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) + m_baseManaRegen) / 5.0f;
// Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura
- AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT);
- for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
+ AuraEffectList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT);
+ for(AuraEffectList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * (*i)->GetModifierValue() / 500.0f;
+ power_regen_mp5 += GetStat(Stats((*i)->GetMiscValue())) * (*i)->GetAmount() / 500.0f;
}
- // Bonus from some dummy auras
- AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_PERIODIC_DUMMY);
- for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
- if((*i)->GetId() == 34074) // Aspect of the Viper
- {
- power_regen_mp5 += (*i)->GetModifier()->m_amount * Intellect / 500.0f;
- // Add regen bonus from level in this dummy
- power_regen_mp5 += getLevel() * 35 / 100;
- }
-
// Set regen rate in cast state apply only on spirit based regen
int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
if (modManaRegenInterrupt > 100)
modManaRegenInterrupt = 100;
- SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
+ SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f);
- SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN, power_regen_mp5 + power_regen);
+ SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, power_regen_mp5 + power_regen);
}
void Player::_ApplyAllStatBonuses()
@@ -712,6 +789,27 @@ void Creature::UpdateMaxPower(Powers power)
void Creature::UpdateAttackPowerAndDamage(bool ranged)
{
+ UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
+
+ uint16 index = UNIT_FIELD_ATTACK_POWER;
+ uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
+ uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
+
+ if(ranged)
+ {
+ index = UNIT_FIELD_RANGED_ATTACK_POWER;
+ index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
+ index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
+ }
+
+ float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
+ float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
+ float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
+
+ SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
+ SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
+ SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
+
//automatically update weapon damage after attack power modification
if(ranged)
UpdateDamagePhysical(RANGED_ATTACK);
@@ -755,7 +853,7 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType)
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
- if(attType == BASE_ATTACK && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED))
+ if(!CanUseAttackType(attType))
{
weapon_mindamage = 0;
weapon_maxdamage = 0;
@@ -827,13 +925,13 @@ bool Pet::UpdateStats(Stats stat)
bool Pet::UpdateAllStats()
{
- for (int i = STAT_STRENGTH; i < MAX_STATS; i++)
+ for (int i = STAT_STRENGTH; i < MAX_STATS; ++i)
UpdateStats(Stats(i));
- for(int i = POWER_MANA; i < MAX_POWERS; i++)
+ for(int i = POWER_MANA; i < MAX_POWERS; ++i)
UpdateMaxPower(Powers(i));
- for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
+ for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
UpdateResistances(i);
return true;
@@ -923,7 +1021,7 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged)
if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power
{
bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f;
- SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.125f));
+ SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f));
}
//demons benefit from warlocks shadow or fire damage
else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
@@ -954,9 +1052,9 @@ void Pet::UpdateAttackPowerAndDamage(bool ranged)
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
//UNIT_FIELD_(RANGED)_ATTACK_POWER field
- SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower);
+ SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower);
//UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
- SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod);
+ SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)attPowerMod);
//UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier);
diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp
index 86cbab6e8ad..a7757aaeaaf 100644
--- a/src/game/TargetedMovementGenerator.cpp
+++ b/src/game/TargetedMovementGenerator.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
#include "TargetedMovementGenerator.h"
#include "Errors.h"
#include "Creature.h"
-#include "MapManager.h"
#include "DestinationHolderImp.h"
#include "World.h"
@@ -52,16 +51,30 @@ TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) )
return;
+ float x, y, z;
+ Traveller<T> traveller(owner);
// prevent redundant micro-movement for pets, other followers.
- //if(i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset))
- // return;
+ if(i_offset ? i_target->IsWithinDistInMap(&owner, i_offset + 1.0f) : i_target->IsWithinMeleeRange(&owner))
+ {
+ owner.GetPosition(x, y, z);
+ i_destinationHolder.SetDestination(traveller, x, y, z, false);
+ return;
+ }
+
+ // chaser is on the way, and target did not move much
+ if(GetDestination(x, y, z) && i_target->IsWithinDist3d(x, y, z, 0.3f))
+ return;
- float x, y, z;
if(!i_offset)
{
// to nearest random contact position
i_target->GetRandomContactPoint( &owner, x, y, z, 0, MELEE_RANGE - 0.5f );
}
+ else if(!i_angle && !owner.hasUnitState(UNIT_STAT_FOLLOW))
+ {
+ // caster chase
+ i_target->GetContactPoint(&owner, x, y, z, i_offset * urand(80, 100) * 0.01f);
+ }
else
{
// to at i_offset distance from target and i_angle from target facing
@@ -84,24 +97,24 @@ TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize )
return;
*/
- Traveller<T> traveller(owner);
i_destinationHolder.SetDestination(traveller, x, y, z);
owner.addUnitState(UNIT_STAT_CHASE);
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
owner.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
+ i_destinationHolder.StartTravel(traveller);
}
template<class T>
void
TargetedMovementGenerator<T>::Initialize(T &owner)
{
- if(!&owner)
- return;
- owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->HasSearchedAssistance())
+ owner.AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ else
+ owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
owner.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
-
_setTargetLocation(owner);
}
@@ -133,7 +146,7 @@ TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
return true;
// prevent movement while casting spells with cast time or channel time
- if ( owner.IsNonMeleeSpellCasted(false, false, true))
+ if(owner.hasUnitState(UNIT_STAT_CASTING))
{
if (!owner.IsStopped())
owner.StopMoving();
@@ -148,7 +161,7 @@ TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
if( !i_destinationHolder.HasDestination() )
_setTargetLocation(owner);
- if( owner.IsStopped() && !i_destinationHolder.HasArrived() )
+ else if( owner.IsStopped() && !i_destinationHolder.HasArrived() )
{
owner.addUnitState(UNIT_STAT_CHASE);
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
@@ -170,8 +183,7 @@ TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
// try to counter precision differences
//if( i_destinationHolder.GetDistance2dFromDestSq(*i_target.getTarget()) >= dist * dist)
- if(i_offset ? !i_target->IsWithinDistInMap(&owner,2*i_offset)
- : !i_target->IsWithinMeleeRange(&owner))
+ if(i_offset ? !i_target->IsWithinDistInMap(&owner, i_offset + 1.0f) : !i_target->IsWithinMeleeRange(&owner))
{
owner.SetInFront(i_target.getTarget()); // Set new Angle For Map::
_setTargetLocation(owner); //Calculate New Dest and Send data To Player
diff --git a/src/game/TargetedMovementGenerator.h b/src/game/TargetedMovementGenerator.h
index 609e517078c..e3b262ac746 100644
--- a/src/game/TargetedMovementGenerator.h
+++ b/src/game/TargetedMovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,7 +57,7 @@ class TRINITY_DLL_SPEC TargetedMovementGenerator
bool GetDestination(float &x, float &y, float &z) const
{
- if(i_destinationHolder.HasArrived()) return false;
+ if(i_destinationHolder.HasArrived() || !i_destinationHolder.HasDestination()) return false;
i_destinationHolder.GetDestination(x,y,z);
return true;
}
diff --git a/src/game/TaxiHandler.cpp b/src/game/TaxiHandler.cpp
index c65a4214892..fe1255e51a1 100644
--- a/src/game/TaxiHandler.cpp
+++ b/src/game/TaxiHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
-#include "World.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "UpdateMask.h"
@@ -49,14 +48,14 @@ void WorldSession::HandleTaxiNodeStatusQueryOpcode( WorldPacket & recv_data )
void WorldSession::SendTaxiStatus( uint64 guid )
{
// cheating checks
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
+ Creature *unit = GetPlayer()->GetMap()->GetCreature(guid);
if (!unit)
{
sLog.outDebug( "WorldSession::SendTaxiStatus - Unit (GUID: %u) not found.", uint32(GUID_LOPART(guid)) );
return;
}
- uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId());
+ uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer( )->GetTeam());
// not found nearest
if(curloc == 0)
@@ -71,7 +70,7 @@ void WorldSession::SendTaxiStatus( uint64 guid )
sLog.outDebug( "WORLD: Sent SMSG_TAXINODE_STATUS" );
}
-void WorldSession::HandleTaxiQueryAvailableNodesOpcode( WorldPacket & recv_data )
+void WorldSession::HandleTaxiQueryAvailableNodes( WorldPacket & recv_data )
{
CHECK_PACKET_SIZE(recv_data,8);
@@ -81,7 +80,7 @@ void WorldSession::HandleTaxiQueryAvailableNodesOpcode( WorldPacket & recv_data
recv_data >> guid;
// cheating checks
- Creature *unit = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_FLIGHTMASTER);
+ Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
if (!unit)
{
sLog.outDebug( "WORLD: HandleTaxiQueryAvailableNodes - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
@@ -90,7 +89,7 @@ void WorldSession::HandleTaxiQueryAvailableNodesOpcode( WorldPacket & recv_data
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
// unknown taxi node case
if( SendLearnNewTaxiNode(unit) )
@@ -103,7 +102,7 @@ void WorldSession::HandleTaxiQueryAvailableNodesOpcode( WorldPacket & recv_data
void WorldSession::SendTaxiMenu( Creature* unit )
{
// find current node
- uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId());
+ uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer( )->GetTeam());
if ( curloc == 0 )
return;
@@ -124,19 +123,20 @@ void WorldSession::SendDoFlight( uint16 MountId, uint32 path, uint32 pathNode )
{
// remove fake death
if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+ GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
while(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()==FLIGHT_MOTION_TYPE)
GetPlayer()->GetMotionMaster()->MovementExpired(false);
- GetPlayer()->Mount( MountId );
+ if (MountId)
+ GetPlayer()->Mount( MountId );
GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path,pathNode);
}
bool WorldSession::SendLearnNewTaxiNode( Creature* unit )
{
// find current node
- uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId());
+ uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer( )->GetTeam());
if ( curloc == 0 )
return true; // `true` send to avoid WorldSession::SendTaxiMenu call with one more curlock seartch with same false result.
@@ -168,7 +168,7 @@ void WorldSession::HandleActivateTaxiFarOpcode ( WorldPacket & recv_data )
recv_data >> guid >> _totalcost >> node_count;
- Creature *npc = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_FLIGHTMASTER);
+ Creature *npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
if (!npc)
{
sLog.outDebug( "WORLD: HandleActivateTaxiFarOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid)) );
@@ -191,7 +191,7 @@ void WorldSession::HandleActivateTaxiFarOpcode ( WorldPacket & recv_data )
sLog.outDebug( "WORLD: Received CMSG_ACTIVATETAXIEXPRESS from %d to %d" ,nodes.front(),nodes.back());
- GetPlayer()->ActivateTaxiPathTo(nodes, 0, npc);
+ GetPlayer()->ActivateTaxiPathTo(nodes, npc);
}
void WorldSession::HandleTaxiNextDestinationOpcode(WorldPacket& /*recv_data*/)
@@ -249,12 +249,19 @@ void WorldSession::HandleTaxiNextDestinationOpcode(WorldPacket& /*recv_data*/)
objmgr.GetTaxiPath( sourcenode, destinationnode, path, cost);
if(path && MountId)
+ {
SendDoFlight( MountId, path, 1 ); // skip start fly node
- else
- GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next
+ return;
+ }
}
- else
- GetPlayer()->m_taxi.ClearTaxiDestinations(); // not destinations, clear source node
+
+ GetPlayer()->m_taxi.ClearTaxiDestinations(); // not destinations, clear source node
+ GetPlayer()->Unmount();
+ GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ());
+ GetPlayer()->getHostilRefManager().setOnlineOfflineState(true);
+ if(GetPlayer()->pvpInfo.inHostileArea)
+ GetPlayer()->CastSpell(GetPlayer(), 2479, true);
}
void WorldSession::HandleActivateTaxiOpcode( WorldPacket & recv_data )
@@ -269,13 +276,13 @@ void WorldSession::HandleActivateTaxiOpcode( WorldPacket & recv_data )
recv_data >> guid >> nodes[0] >> nodes[1];
sLog.outDebug( "WORLD: Received CMSG_ACTIVATETAXI from %d to %d" ,nodes[0],nodes[1]);
- Creature *npc = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_FLIGHTMASTER);
+ Creature *npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
if (!npc)
{
sLog.outDebug( "WORLD: HandleActivateTaxiOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid)) );
return;
}
- GetPlayer()->ActivateTaxiPathTo(nodes, 0, npc);
+ GetPlayer()->ActivateTaxiPathTo(nodes, npc);
}
diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp
index bbe8fa9c104..993ece988a0 100644
--- a/src/game/TemporarySummon.cpp
+++ b/src/game/TemporarySummon.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,19 +18,26 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "TemporarySummon.h"
-#include "WorldPacket.h"
-#include "MapManager.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "CreatureAI.h"
+#include "ObjectMgr.h"
+#include "TemporarySummon.h"
+
+TempSummon::TempSummon(SummonPropertiesEntry const *properties, Unit *owner) :
+Creature(), m_type(TEMPSUMMON_MANUAL_DESPAWN), m_timer(0), m_lifetime(0)
+, m_Properties(properties)
+{
+ m_summonerGUID = owner ? owner->GetGUID() : 0;
+ m_summonMask |= SUMMON_MASK_SUMMON;
+}
-TemporarySummon::TemporarySummon( uint64 summoner ) :
-Creature(), m_type(TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN), m_timer(0), m_lifetime(0), m_summoner(summoner)
+Unit* TempSummon::GetSummoner() const
{
+ return m_summonerGUID ? ObjectAccessor::GetUnit(*this, m_summonerGUID) : NULL;
}
-void TemporarySummon::Update( uint32 diff )
+void TempSummon::Update( uint32 diff )
{
if (m_deathState == DEAD)
{
@@ -159,30 +166,151 @@ void TemporarySummon::Update( uint32 diff )
Creature::Update( diff );
}
-void TemporarySummon::Summon(TempSummonType type, uint32 lifetime)
+void TempSummon::InitStats(uint32 duration)
{
- m_type = type;
- m_timer = lifetime;
- m_lifetime = lifetime;
+ assert(!isPet());
+
+ m_timer = duration;
+ m_lifetime = duration;
- MapManager::Instance().GetMap(GetMapId(), this)->Add((Creature*)this);
+ if(m_type == TEMPSUMMON_MANUAL_DESPAWN)
+ m_type = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
+
+ if(!m_Properties)
+ return;
- AIM_Initialize();
+ if(uint32 slot = m_Properties->Slot)
+ {
+ if(Unit *owner = GetSummoner())
+ {
+ if(owner->m_SummonSlot[slot] && owner->m_SummonSlot[slot] != GetGUID())
+ {
+ Creature *oldSummon = GetMap()->GetCreature(owner->m_SummonSlot[slot]);
+ if(oldSummon && oldSummon->isSummon())
+ ((TempSummon*)oldSummon)->UnSummon();
+ }
+ owner->m_SummonSlot[slot] = GetGUID();
+ }
+ }
+
+ if(m_Properties->Faction)
+ setFaction(m_Properties->Faction);
}
-void TemporarySummon::UnSummon()
+void TempSummon::InitSummon()
{
+ Unit* owner = GetSummoner();
+ if(owner)
+ {
+ if(owner->GetTypeId()==TYPEID_UNIT && ((Creature*)owner)->IsAIEnabled)
+ ((Creature*)owner)->AI()->JustSummoned(this);
+
+ if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && m_spells[0])
+ {
+ setFaction(owner->getFaction());
+ SetLevel(owner->getLevel());
+ CastSpell(this, m_spells[0], false, 0, 0, m_summonerGUID);
+ }
+ }
+}
+
+void TempSummon::SetTempSummonType(TempSummonType type)
+{
+ m_type = type;
+}
+
+void TempSummon::UnSummon()
+{
+ assert(!isPet());
+
+ Unit* owner = GetSummoner();
+ if(owner && owner->GetTypeId() == TYPEID_UNIT && ((Creature*)owner)->IsAIEnabled)
+ ((Creature*)owner)->AI()->SummonedCreatureDespawn(this);
+
CleanupsBeforeDelete();
AddObjectToRemoveList();
+}
+
+void TempSummon::RemoveFromWorld()
+{
+ if(!IsInWorld())
+ return;
- Unit* sum = m_summoner ? ObjectAccessor::GetUnit(*this, m_summoner) : NULL;
- if (sum && sum->GetTypeId() == TYPEID_UNIT && ((Creature*)sum)->IsAIEnabled)
+ if(m_Properties)
{
- ((Creature*)sum)->AI()->SummonedCreatureDespawn(this);
+ if(uint32 slot = m_Properties->Slot)
+ {
+ if(Unit* owner = GetSummoner())
+ {
+ if(owner->m_SummonSlot[slot] = GetGUID())
+ owner->m_SummonSlot[slot] = 0;
+ }
+ }
}
+
+ //if(GetOwnerGUID())
+ // sLog.outError("Unit %u has owner guid when removed from world", GetEntry());
+
+ Creature::RemoveFromWorld();
}
-void TemporarySummon::SaveToDB()
+void TempSummon::SaveToDB()
{
}
+Minion::Minion(SummonPropertiesEntry const *properties, Unit *owner) : TempSummon(properties, owner)
+, m_owner(owner)
+{
+ assert(m_owner);
+ m_summonMask |= SUMMON_MASK_MINION;
+}
+
+void Minion::InitStats(uint32 duration)
+{
+ TempSummon::InitStats(duration);
+
+ SetReactState(REACT_PASSIVE);
+
+ SetCreatorGUID(m_owner->GetGUID());
+ setFaction(m_owner->getFaction());
+
+ m_owner->SetMinion(this, true);
+}
+
+void Minion::InitSummon()
+{
+ TempSummon::InitSummon();
+
+ if(m_owner->GetTypeId() == TYPEID_PLAYER
+ && m_owner->GetMinionGUID() == GetGUID()
+ && !m_owner->GetCharmGUID())
+ ((Player*)m_owner)->CharmSpellInitialize();
+}
+
+void Minion::RemoveFromWorld()
+{
+ if(!IsInWorld())
+ return;
+
+ m_owner->SetMinion(this, false);
+ TempSummon::RemoveFromWorld();
+}
+
+Guardian::Guardian(SummonPropertiesEntry const *properties, Unit *owner) : Minion(properties, owner)
+, m_bonusdamage(0)
+{
+ m_summonMask |= SUMMON_MASK_GUARDIAN;
+ InitCharmInfo();
+}
+
+void Guardian::InitStats(uint32 duration)
+{
+ Minion::InitStats(duration);
+
+ InitStatsForLevel(m_owner->getLevel());
+
+ if(m_owner->GetTypeId() == TYPEID_PLAYER)
+ m_charmInfo->InitCharmCreateSpells();
+
+ SetReactState(REACT_AGGRESSIVE);
+}
diff --git a/src/game/TemporarySummon.h b/src/game/TemporarySummon.h
index fe9763f5301..e089c77c96e 100644
--- a/src/game/TemporarySummon.h
+++ b/src/game/TemporarySummon.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,23 +22,54 @@
#define TRINITYCORE_TEMPSUMMON_H
#include "Creature.h"
-#include "ObjectAccessor.h"
-class TemporarySummon : public Creature
+class TRINITY_DLL_SPEC TempSummon : public Creature
{
public:
- explicit TemporarySummon(uint64 summoner = 0);
- virtual ~TemporarySummon(){};
+ explicit TempSummon(SummonPropertiesEntry const *properties, Unit *owner);
+ virtual ~TempSummon(){};
void Update(uint32 time);
- void Summon(TempSummonType type, uint32 lifetime);
+ virtual void InitStats(uint32 lifetime);
+ virtual void InitSummon();
void UnSummon();
+ void RemoveFromWorld();
+ void SetTempSummonType(TempSummonType type);
void SaveToDB();
- Unit* GetSummoner() const { return m_summoner ? ObjectAccessor::GetUnit(*this, m_summoner) : NULL; }
+ Unit* GetSummoner() const;
+ uint64 const& GetSummonerGUID() { return m_summonerGUID; }
+
+ SummonPropertiesEntry const *m_Properties;
private:
TempSummonType m_type;
uint32 m_timer;
uint32 m_lifetime;
- uint64 m_summoner;
+ uint64 m_summonerGUID;
+};
+
+class Minion : public TempSummon
+{
+ public:
+ Minion(SummonPropertiesEntry const *properties, Unit *owner);
+ void InitStats(uint32 duration);
+ void InitSummon();
+ void RemoveFromWorld();
+ Unit *GetOwner() { return m_owner; }
+ protected:
+ Unit * const m_owner;
};
+
+class Guardian : public Minion
+{
+ public:
+ Guardian(SummonPropertiesEntry const *properties, Unit *owner);
+ void InitStats(uint32 duration);
+ bool InitStatsForLevel(uint32 level);
+
+ int32 GetBonusDamage() { return m_bonusdamage; }
+ void SetBonusDamage(int32 damage) { m_bonusdamage = damage; }
+ protected:
+ int32 m_bonusdamage;
+};
+
#endif
diff --git a/src/game/ThreatManager.cpp b/src/game/ThreatManager.cpp
index ac124da6951..33ca708a79f 100644
--- a/src/game/ThreatManager.cpp
+++ b/src/game/ThreatManager.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@
#include "Creature.h"
#include "CreatureAI.h"
#include "Map.h"
-#include "MapManager.h"
#include "Player.h"
#include "ObjectAccessor.h"
#include "UnitEvents.h"
@@ -84,7 +83,7 @@ void HostilReference::sourceObjectDestroyLink()
//============================================================
// Inform the source, that the status of the reference changed
-void HostilReference::fireStatusChanged(const ThreatRefStatusChangeEvent& pThreatRefStatusChangeEvent)
+void HostilReference::fireStatusChanged(ThreatRefStatusChangeEvent& pThreatRefStatusChangeEvent)
{
if(getSource())
getSource()->processThreatEvent(&pThreatRefStatusChangeEvent);
@@ -100,7 +99,11 @@ void HostilReference::addThreat(float pMod)
if(!isOnline())
updateOnlineStatus();
if(pMod != 0.0f)
- fireStatusChanged(ThreatRefStatusChangeEvent(UEV_THREAT_REF_THREAT_CHANGE, this, pMod));
+ {
+ ThreatRefStatusChangeEvent event(UEV_THREAT_REF_THREAT_CHANGE, this, pMod);
+ fireStatusChanged(event);
+ }
+
if(isValid() && pMod >= 0)
{
Unit* victim_owner = getTarget()->GetCharmerOrOwner();
@@ -155,8 +158,10 @@ void HostilReference::setOnlineOfflineState(bool pIsOnline)
{
iOnline = pIsOnline;
if(!iOnline)
- setAccessibleState(false); // if not online that not accessible as well
- fireStatusChanged(ThreatRefStatusChangeEvent(UEV_THREAT_REF_ONLINE_STATUS, this));
+ setAccessibleState(false); // if not online that not accessable as well
+
+ ThreatRefStatusChangeEvent event(UEV_THREAT_REF_ONLINE_STATUS, this);
+ fireStatusChanged(event);
}
}
@@ -167,7 +172,9 @@ void HostilReference::setAccessibleState(bool pIsAccessible)
if(iAccessible != pIsAccessible)
{
iAccessible = pIsAccessible;
- fireStatusChanged(ThreatRefStatusChangeEvent(UEV_THREAT_REF_ASSECCIBLE_STATUS, this));
+
+ ThreatRefStatusChangeEvent event(UEV_THREAT_REF_ASSECCIBLE_STATUS, this);
+ fireStatusChanged(event);
}
}
@@ -178,7 +185,9 @@ void HostilReference::setAccessibleState(bool pIsAccessible)
void HostilReference::removeReference()
{
invalidate();
- fireStatusChanged(ThreatRefStatusChangeEvent(UEV_THREAT_REF_REMOVE_FROM_LIST, this));
+
+ ThreatRefStatusChangeEvent event(UEV_THREAT_REF_REMOVE_FROM_LIST, this);
+ fireStatusChanged(event);
}
//============================================================
@@ -194,7 +203,7 @@ Unit* HostilReference::getSourceUnit()
void ThreatContainer::clearReferences()
{
- for(std::list<HostilReference*>::iterator i = iThreatList.begin(); i != iThreatList.end(); ++i)
+ for(std::list<HostilReference*>::const_iterator i = iThreatList.begin(); i != iThreatList.end(); ++i)
{
(*i)->unlink();
delete (*i);
@@ -208,7 +217,7 @@ HostilReference* ThreatContainer::getReferenceByTarget(Unit* pVictim)
{
HostilReference* result = NULL;
uint64 guid = pVictim->GetGUID();
- for(std::list<HostilReference*>::iterator i = iThreatList.begin(); i != iThreatList.end(); ++i)
+ for(std::list<HostilReference*>::const_iterator i = iThreatList.begin(); i != iThreatList.end(); ++i)
{
if((*i)->getUnitGuid() == guid)
{
@@ -267,26 +276,36 @@ HostilReference* ThreatContainer::selectNextVictim(Creature* pAttacker, HostilRe
{
HostilReference* currentRef = NULL;
bool found = false;
+ bool noPriorityTargetFound = false;
- std::list<HostilReference*>::iterator lastRef = iThreatList.end();
+ std::list<HostilReference*>::const_iterator lastRef = iThreatList.end();
lastRef--;
- for(std::list<HostilReference*>::iterator iter = iThreatList.begin(); iter != iThreatList.end() && !found; ++iter)
+ for(std::list<HostilReference*>::const_iterator iter = iThreatList.begin(); iter != iThreatList.end() && !found;)
{
currentRef = (*iter);
Unit* target = currentRef->getTarget();
assert(target); // if the ref has status online the target must be there !
- // some units are preferred in comparison to others
- if(iter != lastRef && (target->IsImmunedToDamage(pAttacker->GetMeleeDamageSchoolMask(), false) ||
- target->hasUnitState(UNIT_STAT_CONFUSED)
- ) )
+ // some units are prefered in comparison to others
+ if(!noPriorityTargetFound && (target->IsImmunedToDamage(pAttacker->GetMeleeDamageSchoolMask()) || target->hasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_DAMAGE)) )
{
- // current victim is a second choice target, so don't compare threat with it below
- if(currentRef == pCurrentVictim)
- pCurrentVictim = NULL;
- continue;
+ if(iter != lastRef)
+ {
+ // current victim is a second choice target, so don't compare threat with it below
+ if(currentRef == pCurrentVictim)
+ pCurrentVictim = NULL;
+ ++iter;
+ continue;
+ }
+ else
+ {
+ // if we reached to this point, everyone in the threatlist is a second choice target. In such a situation the target with the highest threat should be attacked.
+ noPriorityTargetFound = true;
+ iter = iThreatList.begin();
+ continue;
+ }
}
if(!pAttacker->IsOutOfThreatArea(target)) // skip non attackable currently targets
@@ -301,8 +320,9 @@ HostilReference* ThreatContainer::selectNextVictim(Creature* pAttacker, HostilRe
break;
}
- if( currentRef->getThreat() > 1.3f * pCurrentVictim->getThreat() ||
- currentRef->getThreat() > 1.1f * pCurrentVictim->getThreat() && pAttacker->IsWithinMeleeRange(target) )
+ if (currentRef->getThreat() > 1.3f * pCurrentVictim->getThreat() ||
+ currentRef->getThreat() > 1.1f * pCurrentVictim->getThreat() &&
+ pAttacker->IsWithinMeleeRange(target))
{ //implement 110% threat rule for targets in melee range
found = true; //and 130% rule for targets in ranged distances
break; //for selecting alive targets
@@ -314,6 +334,7 @@ HostilReference* ThreatContainer::selectNextVictim(Creature* pAttacker, HostilRe
break;
}
}
+ ++iter;
}
if(!found)
currentRef = NULL;
@@ -347,12 +368,18 @@ void ThreatManager::addThreat(Unit* pVictim, float pThreat, SpellSchoolMask scho
//players and pets have only InHateListOf
//HateOfflineList is used co contain unattackable victims (in-flight, in-water, GM etc.)
- if (pVictim == getOwner()) // only for same creatures :)
+ // not to self
+ if (pVictim == getOwner())
return;
+ // not to GM
if(!pVictim || (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->isGameMaster()) )
return;
+ // not to dead and not for dead
+ if(!pVictim->isAlive() || !getOwner()->isAlive() )
+ return;
+
assert(getOwner()->GetTypeId()== TYPEID_UNIT);
float threat = ThreatCalcHelper::calcThreat(pVictim, iOwner, pThreat, schoolMask, pThreatSpell);
@@ -450,18 +477,13 @@ void ThreatManager::setCurrentVictim(HostilReference* pHostilReference)
// The hated unit is gone, dead or deleted
// return true, if the event is consumed
-bool ThreatManager::processThreatEvent(const UnitBaseEvent* pUnitBaseEvent)
+void ThreatManager::processThreatEvent(ThreatRefStatusChangeEvent* threatRefStatusChangeEvent)
{
- bool consumed = false;
-
- ThreatRefStatusChangeEvent* threatRefStatusChangeEvent;
- HostilReference* hostilReference;
-
- threatRefStatusChangeEvent = (ThreatRefStatusChangeEvent*) pUnitBaseEvent;
threatRefStatusChangeEvent->setThreatManager(this); // now we can set the threat manager
- hostilReference = threatRefStatusChangeEvent->getReference();
- switch(pUnitBaseEvent->getType())
+ HostilReference* hostilReference = threatRefStatusChangeEvent->getReference();
+
+ switch(threatRefStatusChangeEvent->getType())
{
case UEV_THREAT_REF_THREAT_CHANGE:
if((getCurrentVictim() == hostilReference && threatRefStatusChangeEvent->getFValue()<0.0f) ||
@@ -499,6 +521,5 @@ bool ThreatManager::processThreatEvent(const UnitBaseEvent* pUnitBaseEvent)
iThreatOfflineContainer.remove(hostilReference);
break;
}
- return consumed;
}
diff --git a/src/game/ThreatManager.h b/src/game/ThreatManager.h
index 56281b9f8f3..aa84cb7d52c 100644
--- a/src/game/ThreatManager.h
+++ b/src/game/ThreatManager.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,20 +45,8 @@ class ThreatCalcHelper
};
//==============================================================
-
class TRINITY_DLL_SPEC HostilReference : public Reference<Unit, ThreatManager>
{
- private:
- float iThreat;
- float iTempThreatModifyer; // used for taunt
- uint64 iUnitGuid;
- bool iOnline;
- bool iAccessible;
- private:
- // Inform the source, that the status of that reference was changed
- void fireStatusChanged(const ThreatRefStatusChangeEvent& pThreatRefStatusChangeEvent);
-
- Unit* getSourceUnit();
public:
HostilReference(Unit* pUnit, ThreatManager *pThreatManager, float pThreat);
@@ -125,6 +113,17 @@ class TRINITY_DLL_SPEC HostilReference : public Reference<Unit, ThreatManager>
// Tell our refFrom (source) object, that the link is cut (Target destroyed)
void sourceObjectDestroyLink();
+ private:
+ // Inform the source, that the status of that reference was changed
+ void fireStatusChanged(ThreatRefStatusChangeEvent& pThreatRefStatusChangeEvent);
+
+ Unit* getSourceUnit();
+ private:
+ float iThreat;
+ float iTempThreatModifyer; // used for taunt
+ uint64 iUnitGuid;
+ bool iOnline;
+ bool iAccessible;
};
//==============================================================
@@ -170,14 +169,9 @@ class TRINITY_DLL_SPEC ThreatContainer
class TRINITY_DLL_SPEC ThreatManager
{
- private:
- HostilReference* iCurrentVictim;
- Unit* iOwner;
- ThreatContainer iThreatContainer;
- ThreatContainer iThreatOfflineContainer;
-
- void _addThreat(Unit* target, float threat);
public:
+ friend class HostilReference;
+
explicit ThreatManager(Unit *pOwner);
~ThreatManager() { clearReferences(); }
@@ -191,7 +185,7 @@ class TRINITY_DLL_SPEC ThreatManager
bool isThreatListEmpty() { return iThreatContainer.empty();}
- bool processThreatEvent(const UnitBaseEvent* pUnitBaseEvent);
+ void processThreatEvent(ThreatRefStatusChangeEvent* threatRefStatusChangeEvent);
HostilReference* getCurrentVictim() { return iCurrentVictim; }
@@ -208,10 +202,17 @@ class TRINITY_DLL_SPEC ThreatManager
// methods to access the lists from the outside to do sume dirty manipulation (scriping and such)
// I hope they are used as little as possible.
- inline std::list<HostilReference*>& getThreatList() { return iThreatContainer.getThreatList(); }
- inline std::list<HostilReference*>& getOfflieThreatList() { return iThreatOfflineContainer.getThreatList(); }
- inline ThreatContainer& getOnlineContainer() { return iThreatContainer; }
- inline ThreatContainer& getOfflineContainer() { return iThreatOfflineContainer; }
+ std::list<HostilReference*>& getThreatList() { return iThreatContainer.getThreatList(); }
+ std::list<HostilReference*>& getOfflieThreatList() { return iThreatOfflineContainer.getThreatList(); }
+ ThreatContainer& getOnlineContainer() { return iThreatContainer; }
+ ThreatContainer& getOfflineContainer() { return iThreatOfflineContainer; }
+ private:
+ void _addThreat(Unit *pVictim, float threat);
+
+ HostilReference* iCurrentVictim;
+ Unit* iOwner;
+ ThreatContainer iThreatContainer;
+ ThreatContainer iThreatOfflineContainer;
};
//=================================================
diff --git a/src/game/TicketHandler.cpp b/src/game/TicketHandler.cpp
index 640faacc155..f4af95bb169 100644
--- a/src/game/TicketHandler.cpp
+++ b/src/game/TicketHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS
+ * Copyright (C) 2005-2009 MaNGOS
*
- * Copyright (C) 2008 Trinity
+ * Copyright (C) 2008-2009 Trinity
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/TicketMgr.cpp b/src/game/TicketMgr.cpp
index ff26d3ba0f4..52cf1ff0db6 100644
--- a/src/game/TicketMgr.cpp
+++ b/src/game/TicketMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS
+ * Copyright (C) 2005-2009 MaNGOS
*
- * Copyright (C) 2008 Trinity
+ * Copyright (C) 2008-2009 Trinity
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/TicketMgr.h b/src/game/TicketMgr.h
index 4cf1b46d97e..491e6657f40 100644
--- a/src/game/TicketMgr.h
+++ b/src/game/TicketMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS
+ * Copyright (C) 2005-2009 MaNGOS
*
- * Copyright (C) 2008 Trinity
+ * Copyright (C) 2008-2009 Trinity
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Tools.cpp b/src/game/Tools.cpp
index e553b86f8e9..d1728c78c9e 100644
--- a/src/game/Tools.cpp
+++ b/src/game/Tools.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Tools.h b/src/game/Tools.h
index 2a71121129b..bdb3ad8e762 100644
--- a/src/game/Tools.h
+++ b/src/game/Tools.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/Totem.cpp b/src/game/Totem.cpp
index de58a7ef15f..3cdc8050d53 100644
--- a/src/game/Totem.cpp
+++ b/src/game/Totem.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,24 +20,22 @@
#include "Totem.h"
#include "WorldPacket.h"
-#include "MapManager.h"
#include "Log.h"
#include "Group.h"
#include "Player.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
-Totem::Totem() : Creature()
+Totem::Totem(SummonPropertiesEntry const *properties, Unit *owner) : Minion(properties, owner)
{
- m_isTotem = true;
+ m_summonMask |= SUMMON_MASK_TOTEM;
m_duration = 0;
m_type = TOTEM_PASSIVE;
}
void Totem::Update( uint32 time )
{
- Unit *owner = GetOwner();
- if (!owner || !owner->isAlive() || !this->isAlive())
+ if (!m_owner->isAlive() || !isAlive())
{
UnSummon(); // remove self
return;
@@ -54,13 +52,15 @@ void Totem::Update( uint32 time )
Creature::Update( time );
}
-void Totem::Summon(Unit* owner)
+void Totem::InitStats(uint32 duration)
{
+ Minion::InitStats(duration);
+
CreatureInfo const *cinfo = GetCreatureInfo();
- if (owner->GetTypeId()==TYPEID_PLAYER && cinfo)
+ if (m_owner->GetTypeId()==TYPEID_PLAYER && cinfo)
{
uint32 modelid = 0;
- if(((Player*)owner)->GetTeam() == HORDE)
+ if(((Player*)m_owner)->GetTeam() == HORDE)
{
if(cinfo->Modelid_H1)
modelid = cinfo->Modelid_H1;
@@ -77,29 +77,34 @@ void Totem::Summon(Unit* owner)
if (modelid)
SetDisplayId(modelid);
else
- sLog.outErrorDb("Totem::Summon: Missing modelid information for entry %u, team %u, totem will use default values.",GetEntry(),((Player*)owner)->GetTeam());
+ sLog.outErrorDb("Totem::Summon: Missing modelid information for entry %u, team %u, totem will use default values.",GetEntry(),((Player*)m_owner)->GetTeam());
}
- // Only add if a display exists.
- sLog.outDebug("AddObject at Totem.cpp line 49");
- SetInstanceId(owner->GetInstanceId());
- owner->GetMap()->Add((Creature*)this);
-
- WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
- data << GetGUID();
- SendMessageToSet(&data,true);
-
- AIM_Initialize();
-
- switch(m_type)
+ // Get spell casted by totem
+ SpellEntry const * totemSpell = sSpellStore.LookupEntry(GetSpell());
+ if (totemSpell)
{
- case TOTEM_PASSIVE: CastSpell(this, GetSpell(), true); break;
- case TOTEM_STATUE: CastSpell(GetOwner(), GetSpell(), true); break;
- default: break;
+ // If spell have cast time -> so its active totem
+ if (GetSpellCastTime(totemSpell))
+ m_type = TOTEM_ACTIVE;
}
if(GetEntry() == SENTRY_TOTEM_ENTRY)
SetReactState(REACT_AGGRESSIVE);
+
+ m_duration = duration;
+
+ SetLevel(m_owner->getLevel());
+}
+
+void Totem::InitSummon()
+{
+ WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
+ data << GetGUID();
+ SendMessageToSet(&data, true);
+
+ if(m_type == TOTEM_PASSIVE)
+ CastSpell(this, GetSpell(), true);
}
void Totem::UnSummon()
@@ -108,35 +113,32 @@ void Totem::UnSummon()
CombatStop();
RemoveAurasDueToSpell(GetSpell());
- Unit *owner = this->GetOwner();
- if (owner)
+
+ // clear owenr's totem slot
+ for(int i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
{
- // clear owenr's totem slot
- for(int i = 0; i < MAX_TOTEM; ++i)
+ if(m_owner->m_SummonSlot[i]==GetGUID())
{
- if(owner->m_TotemSlot[i]==GetGUID())
- {
- owner->m_TotemSlot[i] = 0;
- break;
- }
+ m_owner->m_SummonSlot[i] = 0;
+ break;
}
+ }
- owner->RemoveAurasDueToSpell(GetSpell());
+ m_owner->RemoveAurasDueToSpell(GetSpell());
- //remove aura all party members too
- Group *pGroup = NULL;
- if (owner->GetTypeId() == TYPEID_PLAYER)
+ //remove aura all party members too
+ Group *pGroup = NULL;
+ if (m_owner->GetTypeId() == TYPEID_PLAYER)
+ {
+ // Not only the player can summon the totem (scripted AI)
+ pGroup = ((Player*)m_owner)->GetGroup();
+ if (pGroup)
{
- // Not only the player can summon the totem (scripted AI)
- pGroup = ((Player*)owner)->GetGroup();
- if (pGroup)
+ for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
{
- for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player* Target = itr->getSource();
- if(Target && pGroup->SameSubGroup((Player*)owner, Target))
- Target->RemoveAurasDueToSpell(GetSpell());
- }
+ Player* Target = itr->getSource();
+ if(Target && pGroup->SameSubGroup((Player*)m_owner, Target))
+ Target->RemoveAurasDueToSpell(GetSpell());
}
}
}
@@ -145,52 +147,19 @@ void Totem::UnSummon()
AddObjectToRemoveList();
}
-void Totem::SetOwner(uint64 guid)
+bool Totem::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
{
- SetCreatorGUID(guid);
- SetOwnerGUID(guid);
- if (Unit *owner = GetOwner())
- {
- this->setFaction(owner->getFaction());
- this->SetLevel(owner->getLevel());
- }
-}
-
-Unit *Totem::GetOwner()
-{
- uint64 ownerid = GetOwnerGUID();
- if(!ownerid)
- return NULL;
- return ObjectAccessor::GetUnit(*this, ownerid);
-}
-
-void Totem::SetTypeBySummonSpell(SpellEntry const * spellProto)
-{
- // Get spell casted by totem
- SpellEntry const * totemSpell = sSpellStore.LookupEntry(GetSpell());
- if (totemSpell)
+ // TODO: possibly all negative auras immuned?
+ switch(spellInfo->EffectApplyAuraName[index])
{
- // If spell have cast time -> so its active totem
- if (GetSpellCastTime(totemSpell))
- m_type = TOTEM_ACTIVE;
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_PERIODIC_LEECH:
+ case SPELL_AURA_MOD_FEAR:
+ case SPELL_AURA_TRANSFORM:
+ return true;
+ default:
+ break;
}
- if(spellProto->SpellIconID==2056)
- m_type = TOTEM_STATUE; //Jewelery statue
-}
-
-bool Totem::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
-{
-/* for (int i=0;i<3;i++)
- {
- switch(spellInfo->EffectApplyAuraName[i])
- {
- case SPELL_AURA_PERIODIC_DAMAGE:
- case SPELL_AURA_PERIODIC_LEECH:
- return true;
- default:
- continue;
- }
- }*/
- return Creature::IsImmunedToSpell(spellInfo, useCharges);
+ return Creature::IsImmunedToSpellEffect(spellInfo, index);
}
diff --git a/src/game/Totem.h b/src/game/Totem.h
index 82b183d5d62..134ca6d6d3f 100644
--- a/src/game/Totem.h
+++ b/src/game/Totem.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,32 +21,28 @@
#ifndef TRINITYCORE_TOTEM_H
#define TRINITYCORE_TOTEM_H
-#include "Creature.h"
+#include "TemporarySummon.h"
enum TotemType
{
TOTEM_PASSIVE = 0,
TOTEM_ACTIVE = 1,
- TOTEM_STATUE = 2
};
#define SENTRY_TOTEM_ENTRY 3968
-class Totem : public Creature
+class Totem : public Minion
{
public:
- explicit Totem();
+ explicit Totem(SummonPropertiesEntry const *properties, Unit *owner);
virtual ~Totem(){};
void Update( uint32 time );
- void Summon(Unit* owner);
+ void InitStats(uint32 duration);
+ void InitSummon();
void UnSummon();
uint32 GetSpell() const { return m_spells[0]; }
uint32 GetTotemDuration() const { return m_duration; }
- Unit *GetOwner();
TotemType GetTotemType() const { return m_type; }
- void SetTypeBySummonSpell(SpellEntry const * spellProto);
- void SetDuration(uint32 dur) { m_duration = dur; }
- void SetOwner(uint64 guid);
bool UpdateStats(Stats /*stat*/) { return true; }
bool UpdateAllStats() { return true; }
@@ -57,7 +53,7 @@ class Totem : public Creature
void UpdateAttackPowerAndDamage(bool /*ranged*/ ) {}
void UpdateDamagePhysical(WeaponAttackType /*attType*/) {}
- bool IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges = false);
+ bool IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const;
protected:
TotemType m_type;
diff --git a/src/game/TotemAI.cpp b/src/game/TotemAI.cpp
index 3593f8396a1..08c70308d1c 100644
--- a/src/game/TotemAI.cpp
+++ b/src/game/TotemAI.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,9 +21,7 @@
#include "TotemAI.h"
#include "Totem.h"
#include "Creature.h"
-#include "Player.h"
-#include "Database/DBCStores.h"
-#include "MapManager.h"
+#include "DBCStores.h"
#include "ObjectAccessor.h"
#include "SpellMgr.h"
@@ -40,8 +38,9 @@ TotemAI::Permissible(const Creature *creature)
return PERMIT_BASE_NO;
}
-TotemAI::TotemAI(Creature *c) : CreatureAI(c), i_totem(static_cast<Totem&>(*c)), i_victimGuid(0)
+TotemAI::TotemAI(Creature *c) : CreatureAI(c), i_victimGuid(0)
{
+ assert(c->isTotem());
}
void
@@ -51,52 +50,41 @@ TotemAI::MoveInLineOfSight(Unit *)
void TotemAI::EnterEvadeMode()
{
- i_totem.CombatStop();
+ m_creature->CombatStop(true);
}
void
TotemAI::UpdateAI(const uint32 /*diff*/)
{
- if (i_totem.GetTotemType() != TOTEM_ACTIVE)
+ if (((Totem*)m_creature)->GetTotemType() != TOTEM_ACTIVE)
return;
- if (!i_totem.isAlive() || i_totem.IsNonMeleeSpellCasted(false))
+ if (!m_creature->isAlive() || m_creature->IsNonMeleeSpellCasted(false))
return;
// Search spell
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_totem.GetSpell());
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(((Totem*)m_creature)->GetSpell());
if (!spellInfo)
return;
- // Get spell rangy
+ // Get spell range
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
- float max_range = GetSpellMaxRange(srange);
+ float max_range = GetSpellMaxRangeForHostile(srange);
// SPELLMOD_RANGE not applied in this place just because not existence range mods for attacking totems
// pointer to appropriate target if found any
- Unit* victim = i_victimGuid ? ObjectAccessor::GetUnit(i_totem, i_victimGuid) : NULL;
+ Unit* victim = i_victimGuid ? ObjectAccessor::GetUnit(*m_creature, i_victimGuid) : NULL;
// Search victim if no, not attackable, or out of range, or friendly (possible in case duel end)
if( !victim ||
- !victim->isTargetableForAttack() || !i_totem.IsWithinDistInMap(victim, max_range) ||
- i_totem.IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(&i_totem,false) )
+ !victim->isTargetableForAttack() || !m_creature->IsWithinDistInMap(victim, max_range) ||
+ m_creature->IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(m_creature,false) )
{
- CellPair p(Trinity::ComputeCellPair(i_totem.GetPositionX(),i_totem.GetPositionY()));
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
-
victim = NULL;
-
- Trinity::NearestAttackableUnitInObjectRangeCheck u_check(&i_totem, &i_totem, max_range);
- Trinity::UnitLastSearcher<Trinity::NearestAttackableUnitInObjectRangeCheck> checker(victim, u_check);
-
- TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestAttackableUnitInObjectRangeCheck>, GridTypeMapContainer > grid_object_checker(checker);
- TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestAttackableUnitInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker);
-
- CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(i_totem.GetMapId(), &i_totem));
- cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(i_totem.GetMapId(), &i_totem));
+ Trinity::NearestAttackableUnitInObjectRangeCheck u_check(m_creature, m_creature, max_range);
+ Trinity::UnitLastSearcher<Trinity::NearestAttackableUnitInObjectRangeCheck> checker(m_creature, victim, u_check);
+ m_creature->VisitNearbyObject(max_range, checker);
}
// If have target
@@ -106,30 +94,23 @@ TotemAI::UpdateAI(const uint32 /*diff*/)
i_victimGuid = victim->GetGUID();
// attack
- i_totem.SetInFront(victim); // client change orientation by self
- i_totem.CastSpell(victim, i_totem.GetSpell(), false);
+ m_creature->SetInFront(victim); // client change orientation by self
+ m_creature->CastSpell(victim, ((Totem*)m_creature)->GetSpell(), false);
}
else
i_victimGuid = 0;
}
-bool
-TotemAI::IsVisible(Unit *) const
-{
- return false;
-}
-
void
TotemAI::AttackStart(Unit *)
{
// Sentry totem sends ping on attack
- if (i_totem.GetEntry() == SENTRY_TOTEM_ENTRY && i_totem.GetOwner()->GetTypeId() == TYPEID_PLAYER)
+ if (m_creature->GetEntry() == SENTRY_TOTEM_ENTRY && m_creature->GetOwner()->GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(MSG_MINIMAP_PING, (8+4+4));
- data << i_totem.GetGUID();
- data << i_totem.GetPositionX();
- data << i_totem.GetPositionY();
- ((Player*)i_totem.GetOwner())->GetSession()->SendPacket(&data);
+ data << m_creature->GetGUID();
+ data << m_creature->GetPositionX();
+ data << m_creature->GetPositionY();
+ ((Player*)m_creature->GetOwner())->GetSession()->SendPacket(&data);
}
}
-
diff --git a/src/game/TotemAI.h b/src/game/TotemAI.h
index 50ea764abfd..003f5d5ca13 100644
--- a/src/game/TotemAI.h
+++ b/src/game/TotemAI.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,18 +31,16 @@ class TRINITY_DLL_DECL TotemAI : public CreatureAI
{
public:
- TotemAI(Creature *c);
+ explicit TotemAI(Creature *c);
void MoveInLineOfSight(Unit *);
void AttackStart(Unit *);
void EnterEvadeMode();
- bool IsVisible(Unit *) const;
void UpdateAI(const uint32);
static int Permissible(const Creature *);
private:
- Totem &i_totem;
uint64 i_victimGuid;
};
#endif
diff --git a/src/game/TradeHandler.cpp b/src/game/TradeHandler.cpp
index 278bb37c81c..3cead4551c1 100644
--- a/src/game/TradeHandler.cpp
+++ b/src/game/TradeHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -134,7 +134,7 @@ void WorldSession::SendUpdateTrade()
data << (uint32) _player->pTrader->tradeGold; // trader gold
data << (uint32) 0; // spell casted on lowest slot item
- for(uint8 i = 0; i < TRADE_SLOT_COUNT; i++)
+ for(uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
{
item = (_player->pTrader->tradeItems[i] != NULL_SLOT ? _player->pTrader->GetItemByPos( _player->pTrader->tradeItems[i] ) : NULL);
@@ -179,7 +179,7 @@ void WorldSession::SendUpdateTrade()
void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
{
- for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
+ for(int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
{
ItemPosCountVec traderDst;
ItemPosCountVec playerDst;
@@ -278,7 +278,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
}
// not accept if some items now can't be trade (cheating)
- for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
+ for(int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
{
if(_player->tradeItems[i] != NULL_SLOT )
{
@@ -311,7 +311,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
_player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT);
// store items in local list and set 'in-trade' flag
- for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
+ for(int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
{
if(_player->tradeItems[i] != NULL_SLOT )
{
@@ -336,7 +336,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
myCanCompleteTrade = (_player->CanStoreItems( hisItems,TRADE_SLOT_TRADED_COUNT ) == EQUIP_ERR_OK);
// clear 'in-trade' flag
- for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
+ for(int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
{
if(myItems[i]) myItems[i]->SetInTrade(false);
if(hisItems[i]) hisItems[i]->SetInTrade(false);
@@ -361,7 +361,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
}
// execute trade: 1. remove
- for(int i=0; i<TRADE_SLOT_TRADED_COUNT; i++)
+ for(int i=0; i<TRADE_SLOT_TRADED_COUNT; ++i)
{
if(myItems[i])
{
@@ -461,30 +461,30 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,8);
- if( GetPlayer()->pTrader )
+ if (GetPlayer()->pTrader)
return;
uint64 ID;
- if( !GetPlayer()->isAlive() )
+ if (!GetPlayer()->isAlive())
{
SendTradeStatus(TRADE_STATUS_YOU_DEAD);
return;
}
- if( GetPlayer()->hasUnitState(UNIT_STAT_STUNNED) )
+ if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED))
{
SendTradeStatus(TRADE_STATUS_YOU_STUNNED);
return;
}
- if( isLogingOut() )
+ if (isLogingOut())
{
SendTradeStatus(TRADE_STATUS_YOU_LOGOUT);
return;
}
- if( GetPlayer()->isInFlight() )
+ if (GetPlayer()->isInFlight())
{
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
return;
@@ -494,43 +494,43 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
Player* pOther = ObjectAccessor::FindPlayer( ID );
- if( !pOther )
+ if (!pOther)
{
SendTradeStatus(TRADE_STATUS_NO_TARGET);
return;
}
- if( pOther == GetPlayer() || pOther->pTrader )
+ if (pOther == GetPlayer() || pOther->pTrader)
{
SendTradeStatus(TRADE_STATUS_BUSY);
return;
}
- if( !pOther->isAlive() )
+ if (!pOther->isAlive())
{
SendTradeStatus(TRADE_STATUS_TARGET_DEAD);
return;
}
- if( pOther->isInFlight() )
+ if (pOther->isInFlight())
{
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
return;
}
- if( pOther->hasUnitState(UNIT_STAT_STUNNED) )
+ if (pOther->hasUnitState(UNIT_STAT_STUNNED))
{
SendTradeStatus(TRADE_STATUS_TARGET_STUNNED);
return;
}
- if( pOther->GetSession()->isLogingOut() )
+ if (pOther->GetSession()->isLogingOut())
{
SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT);
return;
}
- if( pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()) )
+ if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
{
SendTradeStatus(TRADE_STATUS_IGNORE_YOU);
return;
@@ -542,7 +542,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
return;
}
- if( pOther->GetDistance2d( _player ) > 10.0f )
+ if (!pOther->IsWithinDistInMap(_player,10.0f,false))
{
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
return;
diff --git a/src/game/Transports.cpp b/src/game/Transports.cpp
index df2ad178550..c0006ba2d52 100644
--- a/src/game/Transports.cpp
+++ b/src/game/Transports.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@
#include "Path.h"
#include "WorldPacket.h"
-#include "Database/DBCStores.h"
+#include "DBCStores.h"
#include "ProgressBar.h"
#include "World.h"
@@ -89,8 +89,6 @@ void MapManager::LoadTransports()
continue;
}
- t->m_name = goinfo->name;
-
float x, y, z, o;
uint32 mapid;
x = t->m_WayPoints[0].x; y = t->m_WayPoints[0].y; z = t->m_WayPoints[0].z; mapid = t->m_WayPoints[0].mapid; o = 1;
@@ -104,7 +102,7 @@ void MapManager::LoadTransports()
m_Transports.insert(t);
- for (std::set<uint32>::iterator i = mapsUsed.begin(); i != mapsUsed.end(); ++i)
+ for (std::set<uint32>::const_iterator i = mapsUsed.begin(); i != mapsUsed.end(); ++i)
m_TransportsByMap[*i].insert(t);
//If we someday decide to use the grid to track transports, here:
@@ -139,7 +137,7 @@ void MapManager::LoadTransports()
Transport::Transport() : GameObject()
{
// 2.3.2 - 0x5A
- m_updateFlag = (UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION);
+ m_updateFlag = (UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION);
}
bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags)
@@ -147,10 +145,11 @@ bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z,
Relocate(x,y,z,ang);
SetMapId(mapid);
+ // instance id and phaseMask isn't set to values different from std.
if(!IsPositionValid())
{
- sLog.outError("ERROR: Transport (GUID: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
+ sLog.outError("Transport (GUID: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
guidlow,x,y);
return false;
}
@@ -170,18 +169,21 @@ bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z,
SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size);
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
- SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
-
- SetUInt32Value(OBJECT_FIELD_ENTRY, goinfo->id);
+ //SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
+ SetUInt32Value(GAMEOBJECT_FLAGS, MAKE_PAIR32(0x28, 0x64));
+ SetUInt32Value(GAMEOBJECT_LEVEL, m_period);
+ SetEntry(goinfo->id);
SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId);
- SetGoState(1);
+ SetGoState(GO_STATE_READY);
SetGoType(GameobjectTypes(goinfo->type));
SetGoAnimProgress(animprogress);
if(dynflags)
- SetUInt32Value(GAMEOBJECT_DYN_FLAGS, dynflags);
+ SetUInt32Value(GAMEOBJECT_DYNAMIC, MAKE_PAIR32(0, dynflags));
+
+ SetName(goinfo->name);
return true;
}
@@ -217,7 +219,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
std::vector<keyFrame> keyFrames;
int mapChange = 0;
mapids.clear();
- for (size_t i = 1; i < path.Size() - 1; i++)
+ for (size_t i = 1; i < path.Size() - 1; ++i)
{
if (mapChange == 0)
{
@@ -249,7 +251,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
}
// find the rest of the distances between key points
- for (size_t i = 1; i < keyFrames.size(); i++)
+ for (size_t i = 1; i < keyFrames.size(); ++i)
{
if ((keyFrames[i].actionflag == 1) || (keyFrames[i].mapid != keyFrames[i-1].mapid))
{
@@ -272,7 +274,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
}
float tmpDist = 0;
- for (size_t i = 0; i < keyFrames.size(); i++)
+ for (size_t i = 0; i < keyFrames.size(); ++i)
{
int j = (i + lastStop) % keyFrames.size();
if (keyFrames[j].actionflag == 2)
@@ -291,7 +293,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
tmpDist = 0;
}
- for (size_t i = 0; i < keyFrames.size(); i++)
+ for (size_t i = 0; i < keyFrames.size(); ++i)
{
if (keyFrames[i].distSinceStop < (30 * 30 * 0.5f))
keyFrames[i].tFrom = sqrt(2 * keyFrames[i].distSinceStop);
@@ -307,7 +309,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
keyFrames[i].tTo *= 1000;
}
- // for (int i = 0; i < keyFrames.size(); i++) {
+ // for (int i = 0; i < keyFrames.size(); ++i) {
// sLog.outString("%f, %f, %f, %f, %f, %f, %f", keyFrames[i].x, keyFrames[i].y, keyFrames[i].distUntilStop, keyFrames[i].distSinceStop, keyFrames[i].distFromPrev, keyFrames[i].tFrom, keyFrames[i].tTo);
// }
@@ -323,7 +325,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
t += keyFrames[0].delay * 1000;
uint32 cM = keyFrames[0].mapid;
- for (size_t i = 0; i < keyFrames.size() - 1; i++)
+ for (size_t i = 0; i < keyFrames.size() - 1; ++i)
{
float d = 0;
float tFrom = keyFrames[i].tFrom;
@@ -414,7 +416,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
uint32 timer = t;
- // sLog.outDetail(" Generated %d waypoints, total time %u.", m_WayPoints.size(), timer);
+ // sLog.outDetail(" Generated %lu waypoints, total time %u.", (unsigned long)m_WayPoints.size(), timer);
m_curr = m_WayPoints.begin();
m_curr = GetNextWayPoint();
@@ -426,9 +428,9 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
return true;
}
-Transport::WayPointMap::iterator Transport::GetNextWayPoint()
+Transport::WayPointMap::const_iterator Transport::GetNextWayPoint()
{
- WayPointMap::iterator iter = m_curr;
+ WayPointMap::const_iterator iter = m_curr;
++iter;
if (iter == m_WayPoints.end())
iter = m_WayPoints.begin();
@@ -437,24 +439,15 @@ Transport::WayPointMap::iterator Transport::GetNextWayPoint()
void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
{
- //MapManager::Instance().GetMap(oldMapid)->Remove((GameObject *)this, false);
+ Map const* oldMap = GetMap();
SetMapId(newMapid);
- //MapManager::Instance().LoadGrid(newMapid,x,y,true);
Relocate(x, y, z);
- //MapManager::Instance().GetMap(newMapid)->Add<GameObject>((GameObject *)this);
- for(PlayerSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();)
+ for(PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();)
{
- PlayerSet::iterator it2 = itr;
+ Player *plr = *itr;
++itr;
- Player *plr = *it2;
- if(!plr)
- {
- m_passengers.erase(it2);
- continue;
- }
-
if (plr->isDead() && !plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
{
plr->ResurrectPlayer(1.0);
@@ -465,25 +458,27 @@ void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
//data << uint32(0);
//plr->GetSession()->SendPacket(&data);
}
+
+ Map const* newMap = GetMap();
+
+ if(oldMap != newMap)
+ {
+ UpdateForMap(oldMap);
+ UpdateForMap(newMap);
+ }
}
bool Transport::AddPassenger(Player* passenger)
{
- if (m_passengers.find(passenger) == m_passengers.end())
- {
- sLog.outDetail("Player %s boarded transport %s.", passenger->GetName(), this->m_name.c_str());
- m_passengers.insert(passenger);
- }
+ if(m_passengers.insert(passenger).second)
+ sLog.outDetail("Player %s boarded transport %s.", passenger->GetName(), GetName());
return true;
}
bool Transport::RemovePassenger(Player* passenger)
{
- if (m_passengers.find(passenger) != m_passengers.end())
- {
- sLog.outDetail("Player %s removed from transport %s.", passenger->GetName(), this->m_name.c_str());
- m_passengers.erase(passenger);
- }
+ if (m_passengers.erase(passenger))
+ sLog.outDetail("Player %s removed from transport %s.", passenger->GetName(), GetName());
return true;
}
@@ -512,7 +507,6 @@ void Transport::Update(uint32 /*p_time*/)
}
else
{
- //MapManager::Instance().GetMap(m_curr->second.mapid)->GameobjectRelocation((GameObject *)this, m_curr->second.x, m_curr->second.y, m_curr->second.z, this->m_orientation);
Relocate(m_curr->second.x, m_curr->second.y, m_curr->second.z);
}
/*
@@ -537,9 +531,9 @@ void Transport::Update(uint32 /*p_time*/)
}
*/
/*
- for(PlayerSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();)
+ for(PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();)
{
- PlayerSet::iterator it2 = itr;
+ PlayerSet::const_iterator it2 = itr;
++itr;
//(*it2)->SetPosition( m_curr->second.x + (*it2)->GetTransOffsetX(), m_curr->second.y + (*it2)->GetTransOffsetY(), m_curr->second.z + (*it2)->GetTransOffsetZ(), (*it2)->GetTransOffsetO() );
}
@@ -550,10 +544,6 @@ void Transport::Update(uint32 /*p_time*/)
if (m_curr == m_WayPoints.begin() && (sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES)==0)
sLog.outDetail(" ************ BEGIN ************** %s", this->m_name.c_str());
- // MapManager::Instance().GetMap(m_curr->second.mapid)->Add(&this); // -> // ->Add(t);
- //MapManager::Instance().GetMap(m_curr->second.mapid)->Remove((GameObject *)this, false); // -> // ->Add(t);
- //MapManager::Instance().GetMap(m_curr->second.mapid)->Add((GameObject *)this); // -> // ->Add(t);
-
if ((sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES)==0)
sLog.outDetail("%s moved to %d %f %f %f %d", this->m_name.c_str(), m_curr->second.id, m_curr->second.x, m_curr->second.y, m_curr->second.z, m_curr->second.mapid);
@@ -562,3 +552,36 @@ void Transport::Update(uint32 /*p_time*/)
}
}
+void Transport::UpdateForMap(Map const* targetMap)
+{
+ Map::PlayerList const& pl = targetMap->GetPlayers();
+ if(pl.isEmpty())
+ return;
+
+ if(GetMapId()==targetMap->GetId())
+ {
+ for(Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
+ {
+ if(this != itr->getSource()->GetTransport())
+ {
+ UpdateData transData;
+ BuildCreateUpdateBlockForPlayer(&transData, itr->getSource());
+ WorldPacket packet;
+ transData.BuildPacket(&packet, true);
+ itr->getSource()->SendDirectMessage(&packet);
+ }
+ }
+ }
+ else
+ {
+ UpdateData transData;
+ BuildOutOfRangeUpdateBlock(&transData);
+ WorldPacket out_packet;
+ transData.BuildPacket(&out_packet, true);
+
+ for(Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
+ if(this != itr->getSource()->GetTransport())
+ itr->getSource()->SendDirectMessage(&out_packet);
+ }
+}
+
diff --git a/src/game/Transports.h b/src/game/Transports.h
index a814a0f70b9..2df39f401e7 100644
--- a/src/game/Transports.h
+++ b/src/game/Transports.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,16 +38,16 @@ class TransportPath
uint32 delay;
};
- inline void SetLength(const unsigned int sz)
+ void SetLength(const unsigned int sz)
{
i_nodes.resize( sz );
}
- inline unsigned int Size(void) const { return i_nodes.size(); }
- inline bool Empty(void) const { return i_nodes.empty(); }
- inline void Resize(unsigned int sz) { i_nodes.resize(sz); }
- inline void Clear(void) { i_nodes.clear(); }
- inline PathNode* GetNodes(void) { return static_cast<PathNode *>(&i_nodes[0]); }
+ unsigned int Size(void) const { return i_nodes.size(); }
+ bool Empty(void) const { return i_nodes.empty(); }
+ void Resize(unsigned int sz) { i_nodes.resize(sz); }
+ void Clear(void) { i_nodes.clear(); }
+ PathNode* GetNodes(void) { return static_cast<PathNode *>(&i_nodes[0]); }
PathNode& operator[](const unsigned int idx) { return i_nodes[idx]; }
const PathNode& operator()(const unsigned int idx) const { return i_nodes[idx]; }
@@ -56,7 +56,7 @@ class TransportPath
std::vector<PathNode> i_nodes;
};
-class Transport : private GameObject
+class Transport : protected GameObject
{
public:
explicit Transport();
@@ -83,7 +83,6 @@ class Transport : private GameObject
typedef std::set<Player*> PlayerSet;
PlayerSet const& GetPassengers() const { return m_passengers; }
- std::string m_name;
private:
struct WayPoint
{
@@ -100,8 +99,8 @@ class Transport : private GameObject
typedef std::map<uint32, WayPoint> WayPointMap;
- WayPointMap::iterator m_curr;
- WayPointMap::iterator m_next;
+ WayPointMap::const_iterator m_curr;
+ WayPointMap::const_iterator m_next;
uint32 m_pathTime;
uint32 m_timer;
@@ -114,7 +113,8 @@ class Transport : private GameObject
private:
void TeleportTransport(uint32 newMapid, float x, float y, float z);
- WayPointMap::iterator GetNextWayPoint();
+ void UpdateForMap(Map const* map);
+ WayPointMap::const_iterator GetNextWayPoint();
};
#endif
diff --git a/src/game/Traveller.h b/src/game/Traveller.h
index ee2ec55833f..702cc6413b0 100644
--- a/src/game/Traveller.h
+++ b/src/game/Traveller.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,11 +21,9 @@
#ifndef TRINITY_TRAVELLER_H
#define TRINITY_TRAVELLER_H
-#include "MapManager.h"
#include "Creature.h"
#include "Player.h"
#include <cassert>
-#include "CreatureGroups.h"
/** Traveller is a wrapper for units (creatures or players) that
* travel from point A to point B using the destination holder.
@@ -47,22 +45,39 @@ struct TRINITY_DLL_DECL Traveller
operator T&(void) { return i_traveller; }
operator const T&(void) { return i_traveller; }
- inline float GetPositionX() const { return i_traveller.GetPositionX(); }
- inline float GetPositionY() const { return i_traveller.GetPositionY(); }
- inline float GetPositionZ() const { return i_traveller.GetPositionZ(); }
- inline T& GetTraveller(void) { return i_traveller; }
+ float GetPositionX() const { return i_traveller.GetPositionX(); }
+ float GetPositionY() const { return i_traveller.GetPositionY(); }
+ float GetPositionZ() const { return i_traveller.GetPositionZ(); }
+ T& GetTraveller(void) { return i_traveller; }
float Speed(void) { assert(false); return 0.0f; }
+ float GetMoveDestinationTo(float x, float y, float z);
+ uint32 GetTotalTrevelTimeTo(float x, float y, float z);
+
void Relocation(float x, float y, float z, float orientation) {}
void Relocation(float x, float y, float z) { Relocation(x, y, z, i_traveller.GetOrientation()); }
void MoveTo(float x, float y, float z, uint32 t) {}
};
+template<class T>
+inline uint32 Traveller<T>::GetTotalTrevelTimeTo(float x, float y, float z)
+{
+ float dist = GetMoveDestinationTo(x,y,z);
+ float speed = 0.001f;
+ if (Speed() <= 0.0f)
+ return 0xfffffffe; // almost infinity-unit should stop
+ else
+ speed *= Speed(); // speed is in seconds so convert from second to millisecond
+ return static_cast<uint32>(dist/speed);
+}
+
// specialization for creatures
template<>
inline float Traveller<Creature>::Speed()
{
- if(i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE))
+ if(i_traveller.hasUnitState(UNIT_STAT_CHARGING))
+ return i_traveller.m_TempSpeed;
+ else if(i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE))
return i_traveller.GetSpeed(MOVE_WALK);
else if(i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_FLYING2))
return i_traveller.GetSpeed(MOVE_FLIGHT);
@@ -73,29 +88,59 @@ inline float Traveller<Creature>::Speed()
template<>
inline void Traveller<Creature>::Relocation(float x, float y, float z, float orientation)
{
- MapManager::Instance().GetMap(i_traveller.GetMapId(), &i_traveller)->CreatureRelocation(&i_traveller, x, y, z, orientation);
+ i_traveller.GetMap()->CreatureRelocation(&i_traveller, x, y, z, orientation);
+}
+
+template<>
+inline float Traveller<Creature>::GetMoveDestinationTo(float x, float y, float z)
+{
+ float dx = x - GetPositionX();
+ float dy = y - GetPositionY();
+ float dz = z - GetPositionZ();
+
+ if(i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_FLYING2))
+ return sqrt((dx*dx) + (dy*dy) + (dz*dz));
+ else //Walking on the ground
+ return sqrt((dx*dx) + (dy*dy));
}
+
template<>
inline void Traveller<Creature>::MoveTo(float x, float y, float z, uint32 t)
{
- i_traveller.AI_SendMoveToPacket(x, y, z, t, i_traveller.GetUnitMovementFlags(), 0);
+ //i_traveller.AI_SendMoveToPacket(x, y, z, t, i_traveller.GetUnitMovementFlags(), 0);
+ i_traveller.SendMonsterMove(x, y, z, t);
}
// specialization for players
template<>
inline float Traveller<Player>::Speed()
{
- if (i_traveller.isInFlight())
+ if(i_traveller.hasUnitState(UNIT_STAT_CHARGING))
+ return i_traveller.m_TempSpeed;
+ else if(i_traveller.isInFlight())
return PLAYER_FLIGHT_SPEED;
else
return i_traveller.GetSpeed(i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN);
}
template<>
+inline float Traveller<Player>::GetMoveDestinationTo(float x, float y, float z)
+{
+ float dx = x - GetPositionX();
+ float dy = y - GetPositionY();
+ float dz = z - GetPositionZ();
+
+ if (i_traveller.isInFlight())
+ return sqrt((dx*dx) + (dy*dy) + (dz*dz));
+ else //Walking on the ground
+ return sqrt((dx*dx) + (dy*dy));
+}
+
+template<>
inline void Traveller<Player>::Relocation(float x, float y, float z, float orientation)
{
- MapManager::Instance().GetMap(i_traveller.GetMapId(), &i_traveller)->PlayerRelocation(&i_traveller, x, y, z, orientation);
+ i_traveller.GetMap()->PlayerRelocation(&i_traveller, x, y, z, orientation);
}
template<>
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index e6aee7de708..18fe23728ca 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -49,6 +49,10 @@
#include "CreatureGroups.h"
#include "PetAI.h"
#include "NullCreatureAI.h"
+#include "Traveller.h"
+#include "TemporarySummon.h"
+#include "Vehicle.h"
+#include "Transports.h"
#include <math.h>
@@ -62,102 +66,28 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
3.141594f, // MOVE_TURN_RATE
7.0f, // MOVE_FLIGHT
4.5f, // MOVE_FLIGHT_BACK
+ 3.14f // MOVE_PITCH_RATE
};
-void InitTriggerAuraData();
-
-// auraTypes contains attacker auras capable of proc'ing cast auras
-static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes()
-{
- static Unit::AuraTypeSet auraTypes;
- auraTypes.insert(SPELL_AURA_DUMMY);
- auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
- auraTypes.insert(SPELL_AURA_MOD_HASTE);
- auraTypes.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- return auraTypes;
-}
-
-// auraTypes contains victim auras capable of proc'ing cast auras
-static Unit::AuraTypeSet GenerateVictimProcCastAuraTypes()
-{
- static Unit::AuraTypeSet auraTypes;
- auraTypes.insert(SPELL_AURA_DUMMY);
- auraTypes.insert(SPELL_AURA_PRAYER_OF_MENDING);
- auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL);
- return auraTypes;
-}
-
-// auraTypes contains auras capable of proc effect/damage (but not cast) for attacker
-static Unit::AuraTypeSet GenerateAttakerProcEffectAuraTypes()
-{
- static Unit::AuraTypeSet auraTypes;
- auraTypes.insert(SPELL_AURA_MOD_DAMAGE_DONE);
- auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
- auraTypes.insert(SPELL_AURA_MOD_CASTING_SPEED);
- auraTypes.insert(SPELL_AURA_MOD_RATING);
- return auraTypes;
-}
-
-// auraTypes contains auras capable of proc effect/damage (but not cast) for victim
-static Unit::AuraTypeSet GenerateVictimProcEffectAuraTypes()
-{
- static Unit::AuraTypeSet auraTypes;
- auraTypes.insert(SPELL_AURA_MOD_RESISTANCE);
- auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE);
- auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT);
- auraTypes.insert(SPELL_AURA_MOD_BLOCK_PERCENT);
- auraTypes.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
- return auraTypes;
-}
-
-static Unit::AuraTypeSet attackerProcCastAuraTypes = GenerateAttakerProcCastAuraTypes();
-static Unit::AuraTypeSet attackerProcEffectAuraTypes = GenerateAttakerProcEffectAuraTypes();
-
-static Unit::AuraTypeSet victimProcCastAuraTypes = GenerateVictimProcCastAuraTypes();
-static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectAuraTypes();
-
-// auraTypes contains auras capable of proc'ing for attacker and victim
-static Unit::AuraTypeSet GenerateProcAuraTypes()
-{
- InitTriggerAuraData();
-
- Unit::AuraTypeSet auraTypes;
- auraTypes.insert(attackerProcCastAuraTypes.begin(),attackerProcCastAuraTypes.end());
- auraTypes.insert(attackerProcEffectAuraTypes.begin(),attackerProcEffectAuraTypes.end());
- auraTypes.insert(victimProcCastAuraTypes.begin(),victimProcCastAuraTypes.end());
- auraTypes.insert(victimProcEffectAuraTypes.begin(),victimProcEffectAuraTypes.end());
- return auraTypes;
-}
-
-static Unit::AuraTypeSet procAuraTypes = GenerateProcAuraTypes();
-
-bool IsPassiveStackableSpell( uint32 spellId )
-{
- if(!IsPassiveSpell(spellId))
- return false;
-
- SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
- if(!spellProto)
- return false;
-
- for(int j = 0; j < 3; ++j)
- {
- if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end())
- return false;
- }
-
- return true;
-}
+// Used for prepare can/can`t triggr aura
+static bool InitTriggerAuraData();
+// Define can trigger auras
+static bool isTriggerAura[TOTAL_AURAS];
+// Define can`t trigger auras (need for disable second trigger)
+static bool isNonTriggerAura[TOTAL_AURAS];
+// Prepare lists
+static bool procPrepared = InitTriggerAuraData();
Unit::Unit()
: WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
, m_IsInNotifyList(false), m_Notified(false), IsAIEnabled(false), NeedChangeAI(false)
-, i_AI(NULL), i_disabledAI(NULL), m_procDeep(0)
+, i_AI(NULL), i_disabledAI(NULL), m_removedAurasCount(0), m_Vehicle(NULL), m_transport(NULL)
+, m_ControlledByPlayer(false), m_procDeep(0)
{
m_objectType |= TYPEMASK_UNIT;
m_objectTypeId = TYPEID_UNIT;
// 2.3.2 - 0x70
- m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HASPOSITION);
+ m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION);
m_attackTimer[BASE_ATTACK] = 0;
m_attackTimer[OFF_ATTACK] = 0;
@@ -178,15 +108,14 @@ Unit::Unit()
m_addDmgOnce = 0;
- for(int i = 0; i < MAX_TOTEM; ++i)
- m_TotemSlot[i] = 0;
+ for(int i = 0; i < MAX_SUMMON_SLOT; ++i)
+ m_SummonSlot[i] = 0;
m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
//m_Aura = NULL;
//m_AurasCheck = 2000;
//m_removeAuraTimer = 4;
//tmpAura = NULL;
- waterbreath = false;
m_Visibility = VISIBILITY_ON;
@@ -209,7 +138,7 @@ Unit::Unit()
// implement 50% base damage from offhand
m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < MAX_ATTACK; ++i)
{
m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
@@ -233,7 +162,6 @@ Unit::Unit()
for (int i = 0; i < MAX_MOVE_TYPE; ++i)
m_speed_rate[i] = 1.0f;
- m_removedAuras = 0;
m_charmInfo = NULL;
m_unit_movement_flags = 0;
m_reducedThreatPercent = 0;
@@ -258,12 +186,14 @@ Unit::~Unit()
RemoveAllGameObjects();
RemoveAllDynObjects();
+ _DeleteAuras();
if(m_charmInfo) delete m_charmInfo;
assert(!m_attacking);
assert(m_attackers.empty());
assert(m_sharedVision.empty());
+ assert(m_Controlled.empty());
}
void Unit::Update( uint32 p_time )
@@ -313,6 +243,7 @@ void Unit::Update( uint32 p_time )
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth()*0.20f);
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth()*0.35f);
+ ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth()*0.75f);
i_motionMaster.UpdateMotion(p_time);
}
@@ -329,28 +260,23 @@ void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player)
{
float x, y, z;
if(GetMotionMaster()->GetDestination(x, y, z))
- SendMonsterMoveWithSpeed(x, y, z, GetUnitMovementFlags(), 0, player);
+ SendMonsterMoveWithSpeed(x, y, z, 0, player);
}
-void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime, Player* player)
+void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player)
{
if (!transitTime)
{
- float dx = x - GetPositionX();
- float dy = y - GetPositionY();
- float dz = z - GetPositionZ();
-
- float dist = ((dx*dx) + (dy*dy) + (dz*dz));
- if(dist<0)
- dist = 0;
+ if(GetTypeId()==TYPEID_PLAYER)
+ {
+ Traveller<Player> traveller(*(Player*)this);
+ transitTime = traveller.GetTotalTrevelTimeTo(x,y,z);
+ }
else
- dist = sqrt(dist);
-
- double speed = GetSpeed((MovementFlags & MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN);
- if(speed<=0)
- speed = 2.5f;
- speed *= 0.001f;
- transitTime = static_cast<uint32>(dist / speed + 0.5);
+ {
+ Traveller<Creature> traveller(*(Creature*)this);
+ transitTime = traveller.GetTotalTrevelTimeTo(x,y,z);
+ }
}
//float orientation = (float)atan2((double)dy, (double)dx);
SendMonsterMove(x, y, z, transitTime, player);
@@ -370,7 +296,7 @@ void Unit::SendMonsterStop()
void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player)
{
- WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) );
+ WorldPacket data( SMSG_MONSTER_MOVE, 12+4+1+4+4+4+12+GetPackGUID().size());
data.append(GetPackGUID());
data << GetPositionX() << GetPositionY() << GetPositionZ();
@@ -391,38 +317,66 @@ void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 T
addUnitState(UNIT_STAT_MOVE);
}
+void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player *player)
+{
+ WorldPacket data( SMSG_MONSTER_MOVE, 12+4+1+4+4+4+12+GetPackGUID().size());
+ data.append(GetPackGUID());
+
+ data << GetPositionX() << GetPositionY() << GetPositionZ();
+ data << getMSTime();
+
+ data << uint8(0);
+ data << MoveFlags;
+
+ if(MoveFlags & MOVEFLAG_JUMP)
+ {
+ data << time;
+ data << speedZ;
+ data << (uint32)0; // walk time after jump
+ }
+ else
+ data << time;
+
+ data << uint32(1); // 1 single waypoint
+ data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
+
+ if(player)
+ player->GetSession()->SendPacket(&data);
+ else
+ SendMessageToSet( &data, true );
+}
+
/*void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player)
{
WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) );
data.append(GetPackGUID());
- // Point A, starting location
data << GetPositionX() << GetPositionY() << GetPositionZ();
- // unknown field - unrelated to orientation
- // seems to increment about 1000 for every 1.7 seconds
- // for now, we'll just use mstime
- data << getMSTime();
+ data << uint32(getMSTime());
data << uint8(type); // unknown
switch(type)
{
case 0: // normal packet
break;
- case 1: // stop packet
+ case 1: // stop packet (raw pos?)
SendMessageToSet( &data, true );
return;
+ case 2: // facing spot, not used currently
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ break;
case 3: // not used currently
- data << uint64(0); // probably target guid
+ data << uint64(0); // probably target guid (facing target?)
break;
case 4: // not used currently
- data << float(0); // probably orientation
+ data << float(0); // facing angle
break;
}
- //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim)
- data << uint32((MovementFlags & MOVEMENTFLAG_LEVITATING) ? MOVEFLAG_FLY : MOVEFLAG_WALK);
-
- data << Time; // Time in between points
+ data << uint32(MovementFlags);
+ data << uint32(Time); // Time in between points
data << uint32(1); // 1 single waypoint
data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
@@ -443,16 +397,12 @@ void Unit::SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end)
data << GetPositionX();
data << GetPositionY();
data << GetPositionZ();
-
data << getMSTime();
-
data << uint8( 0 );
data << uint32(((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) || isInFlight())? (MOVEFLAG_FLY|MOVEFLAG_WALK) : MOVEFLAG_WALK);
data << uint32( traveltime );
data << uint32( pathSize );
data.append( (char*)path.GetNodes(start), pathSize * 4 * 3 );
-
- //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 );
SendMessageToSet(&data, true);
addUnitState(UNIT_STAT_MOVE);
@@ -463,7 +413,7 @@ void Unit::resetAttackTimer(WeaponAttackType type)
m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
}
-bool Unit::IsWithinCombatRange(Unit *obj, float dist2compare) const
+bool Unit::IsWithinCombatRange(const Unit *obj, float dist2compare) const
{
if (!obj || !IsInMap(obj)) return false;
@@ -478,7 +428,7 @@ bool Unit::IsWithinCombatRange(Unit *obj, float dist2compare) const
return distsq < maxdist * maxdist;
}
-bool Unit::IsWithinMeleeRange(Unit *obj, float dist) const
+bool Unit::IsWithinMeleeRange(const Unit *obj, float dist) const
{
if (!obj || !IsInMap(obj)) return false;
@@ -520,71 +470,22 @@ void Unit::RemoveMovementImpairingAuras()
}
}
-void Unit::RemoveSpellsCausingAura(AuraType auraType)
-{
- if (auraType >= TOTAL_AURAS) return;
- AuraList::iterator iter, next;
- for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
- {
- next = iter;
- ++next;
-
- if (*iter)
- {
- RemoveAurasDueToSpell((*iter)->GetId());
- if (!m_modAuras[auraType].empty())
- next = m_modAuras[auraType].begin();
- else
- return;
- }
- }
-}
-
-void Unit::RemoveAuraTypeByCaster(AuraType auraType, uint64 casterGUID)
-{
- if (auraType >= TOTAL_AURAS) return;
- AuraList::iterator iter, next;
- for(iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
- {
- next = iter;
- ++next;
-
- if (*iter)
- {
- RemoveAurasByCasterSpell((*iter)->GetId(), casterGUID);
- if (!m_modAuras[auraType].empty())
- next = m_modAuras[auraType].begin();
- else
- return;
- }
- }
-}
-
void Unit::RemoveAurasWithInterruptFlags(uint32 flag, uint32 except)
{
if(!(m_interruptMask & flag))
return;
// interrupt auras
- AuraList::iterator iter, next;
- for (iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); iter = next)
+ for (AuraList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
{
- next = iter;
- ++next;
-
- //sLog.outDetail("auraflag:%u flag:%u = %u",(*iter)->GetSpellProto()->AuraInterruptFlags,flag,(*iter)->GetSpellProto()->AuraInterruptFlags & flag);
- if(*iter && ((*iter)->GetSpellProto()->AuraInterruptFlags & flag))
+ Aura * aur = *iter;
+ ++iter;
+ if ((aur->GetSpellProto()->AuraInterruptFlags & flag) && (!except || aur->GetId() != except))
{
- if((*iter)->IsInUse())
- sLog.outError("Aura %u is trying to remove itself! Flag %u. May cause crash!", (*iter)->GetId(), flag);
- else if(!except || (*iter)->GetId() != except)
- {
- RemoveAurasDueToSpell((*iter)->GetId());
- if (!m_interruptableAuras.empty())
- next = m_interruptableAuras.begin();
- else
- break;
- }
+ uint32 removedAuras = m_removedAurasCount;
+ RemoveAura(aur, AURA_REMOVE_BY_ENEMY_SPELL);
+ if (removedAuras+1 < m_removedAurasCount)
+ iter=m_interruptableAuras.begin();
}
}
@@ -611,11 +512,6 @@ void Unit::UpdateInterruptMask()
m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
}
-bool Unit::HasAuraType(AuraType auraType) const
-{
- return (!m_modAuras[auraType].empty());
-}
-
/* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
void Unit::RemoveSpellbyDamageTaken(uint32 damage, uint32 spell)
{
@@ -623,27 +519,31 @@ void Unit::RemoveSpellbyDamageTaken(uint32 damage, uint32 spell)
uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
float chance = float(damage) / max_dmg * 100.0f;
- AuraList::iterator i, next;
- for(i = m_ccAuras.begin(); i != m_ccAuras.end(); i = next)
+ std::queue < std::pair < uint32, uint64 > > remove_list;
+
+ for (AuraList::iterator iter = m_ccAuras.begin(); iter != m_ccAuras.end();++iter)
{
- next = i;
- ++next;
+ if((!spell || (*iter)->GetId() != spell) && roll_chance_f(chance))
+ {
+ remove_list.push(std::make_pair((*iter)->GetId(), (*iter)->GetCasterGUID() ) );
+ }
+ }
- if(*i && (!spell || (*i)->GetId() != spell) && roll_chance_f(chance))
- {
- RemoveAurasDueToSpell((*i)->GetId());
- if (!m_ccAuras.empty())
- next = m_ccAuras.begin();
- else
- return;
- }
+ for(;remove_list.size();remove_list.pop())
+ {
+ RemoveAura(remove_list.front().first, remove_list.front().second, AURA_REMOVE_BY_ENEMY_SPELL);
}
}
-uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss)
+void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb)
{
- if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
- return 0;
+ if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ {
+ if(absorb)
+ absorb += damage;
+ damage = 0;
+ return;
+ }
//You don't lose health from damage taken from another player while in a sanctuary
//You still see it in the combat log though
@@ -651,45 +551,36 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
{
const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary
- return 0;
+ {
+ if(absorb)
+ absorb += damage;
+ damage = 0;
+ }
}
+ uint32 originalDamage = damage;
+
+ //Script Event damage Deal
+ //if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI())
+ // ((Creature *)this)->AI()->DamageDeal(pVictim, damage);
//Script Event damage taken
- if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->IsAIEnabled )
- {
- ((Creature *)pVictim)->AI()->DamageTaken(this, damage);
+ //if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->IsAIEnabled )
+ // ((Creature *)pVictim)->AI()->DamageTaken(this, damage);
- // Set tagging
- if(!pVictim->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER) && !((Creature*)pVictim)->isPet())
- {
- //Set Loot
- switch(GetTypeId())
- {
- case TYPEID_PLAYER:
- {
- ((Creature *)pVictim)->SetLootRecipient(this);
- //Set tagged
- ((Creature *)pVictim)->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER);
- break;
- }
- case TYPEID_UNIT:
- {
- if(((Creature*)this)->isPet())
- {
- ((Creature *)pVictim)->SetLootRecipient(this->GetOwner());
- ((Creature *)pVictim)->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER);
- }
- break;
- }
- }
- }
- }
+ if(absorb && originalDamage > damage)
+ absorb += (originalDamage - damage);
+}
+
+uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss)
+{
+ if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsAIEnabled)
+ ((Creature*)pVictim)->AI()->DamageTaken(this, damage);
if (damagetype != NODAMAGE)
{
- // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DAMAGE, spellProto ? spellProto->Id : 0);
- pVictim->RemoveSpellbyDamageTaken(damage, spellProto ? spellProto->Id : 0);
+ // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
+ pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DAMAGE, spellProto ? spellProto->Id : 0);
+ pVictim->RemoveSpellbyDamageTaken(damage, spellProto ? spellProto->Id : 0);
}
if(!damage)
@@ -701,30 +592,27 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
return 0;
}
- if(pVictim->GetTypeId() != TYPEID_PLAYER)
+ // no xp,health if type 8 /critters/
+ if(pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
{
- // no xp,health if type 8 /critters/
- if ( pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
+ // allow loot only if has loot_id in creature_template
+ if(damage >= pVictim->GetHealth())
{
- // allow loot only if has loot_id in creature_template
- if(damage >= pVictim->GetHealth())
- {
- pVictim->setDeathState(JUST_DIED);
- pVictim->SetHealth(0);
+ pVictim->setDeathState(JUST_DIED);
+ pVictim->SetHealth(0);
- CreatureInfo const* cInfo = ((Creature*)pVictim)->GetCreatureInfo();
- if(cInfo && cInfo->lootid)
- pVictim->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
-
- // some critters required for quests
- if(GetTypeId() == TYPEID_PLAYER)
- ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
- }
- else
- pVictim->ModifyHealth(- (int32)damage);
+ CreatureInfo const* cInfo = ((Creature*)pVictim)->GetCreatureInfo();
+ if(cInfo && cInfo->lootid)
+ pVictim->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
- return damage;
+ // some critters required for quests
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
}
+ else
+ pVictim->ModifyHealth(- (int32)damage);
+
+ return damage;
}
DEBUG_LOG("DealDamageStart");
@@ -777,52 +665,214 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
}
- if(pVictim->GetTypeId() == TYPEID_PLAYER && GetTypeId() == TYPEID_PLAYER)
+ if (GetTypeId() == TYPEID_PLAYER && this != pVictim)
{
- if(((Player*)pVictim)->InBattleGround())
+ Player *killer = ((Player*)this);
+
+ // in bg, count dmg if victim is also a player
+ if (pVictim->GetTypeId()==TYPEID_PLAYER)
{
- Player *killer = ((Player*)this);
- if(killer != ((Player*)pVictim))
- if(BattleGround *bg = killer->GetBattleGround())
- bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
+ if (BattleGround *bg = killer->GetBattleGround())
+ {
+ // FIXME: kept by compatibility. don't know in BG if the restriction apply.
+ bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
+ }
}
+
+ killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, pVictim);
+ killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
}
- if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->isPet())
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage);
+ else if(!pVictim->IsControlledByPlayer())
{
+ //!pVictim->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER)
if(!((Creature*)pVictim)->hasLootRecipient())
((Creature*)pVictim)->SetLootRecipient(this);
- if(GetCharmerOrOwnerPlayerOrPlayerItself())
+ if(IsControlledByPlayer())
((Creature*)pVictim)->AddDamageByPlayers(health < damage ? health : damage);
}
if (health <= damage)
{
DEBUG_LOG("DealDamage: victim just died");
+
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health);
+
Kill(pVictim, durabilityLoss);
- }
- else // if (health <= damage)
- {
- DEBUG_LOG("DealDamageAlive");
- pVictim->ModifyHealth(- (int32)damage);
+ /*// find player: owner of controlled `this` or `this` itself maybe
+ Player *player = GetCharmerOrOwnerPlayerOrPlayerItself();
+
+ if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->GetLootRecipient())
+ player = ((Creature*)pVictim)->GetLootRecipient();
+ // Reward player, his pets, and group/raid members
+ // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
+ if(player && player!=pVictim)
+ {
+ player->RewardPlayerAndGroupAtKill(pVictim);
+ player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
+ }
+
+ DEBUG_LOG("DealDamageAttackStop");
+
+ // stop combat
+ pVictim->CombatStop();
+ pVictim->getHostilRefManager().deleteReferences();
- if(damagetype != DOT)
+ bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795;
+
+ // if talent known but not triggered (check priest class for speedup check)
+ Aura* spiritOfRedemtionTalentReady = NULL;
+ if( !damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
+ pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST )
{
- if(!getVictim())
- /*{
- // if have target and damage pVictim just call AI reaction
- if(pVictim != getVictim() && pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsAIEnabled)
- ((Creature*)pVictim)->AI()->AttackedBy(this);
+ AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
+ for(AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
+ {
+ if((*itr)->GetSpellProto()->SpellIconID==1654)
+ {
+ spiritOfRedemtionTalentReady = *itr;
+ break;
+ }
}
- else*/
+ }
+
+ DEBUG_LOG("SET JUST_DIED");
+ if(!spiritOfRedemtionTalentReady)
+ pVictim->setDeathState(JUST_DIED);
+
+ DEBUG_LOG("DealDamageHealth1");
+
+ if(spiritOfRedemtionTalentReady)
+ {
+ // save value before aura remove
+ uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
+ if(!ressSpellId)
+ ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId();
+
+ //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
+ pVictim->RemoveAllAurasOnDeath();
+
+ // restore for use at real death
+ pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL,ressSpellId);
+
+ // FORM_SPIRITOFREDEMPTION and related auras
+ pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady);
+ }
+ else
+ pVictim->SetHealth(0);
+
+ // remember victim PvP death for corpse type and corpse reclaim delay
+ // at original death (not at SpiritOfRedemtionTalent timeout)
+ if( pVictim->GetTypeId()==TYPEID_PLAYER && !damageFromSpiritOfRedemtionTalent )
+ ((Player*)pVictim)->SetPvPDeath(player!=NULL);
+
+ // Call KilledUnit for creatures
+ if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
+ ((Creature*)this)->AI()->KilledUnit(pVictim);
+
+ // achievement stuff
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (GetTypeId() == TYPEID_UNIT)
+ ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
+ else if(GetTypeId() == TYPEID_PLAYER && pVictim != this)
+ ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ((Player*)this)->GetTeam());
+ }
+
+ // 10% durability loss on death
+ // clean InHateListOf
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
+ {
+ // only if not player and not controlled by player pet. And not at BG
+ if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround())
{
- // if not have main target then attack state with target (including AI call)
- //start melee attacks only after melee hit
- Attack(pVictim,(damagetype == DIRECT_DAMAGE));
+ DEBUG_LOG("We are dead, loosing 10 percents durability");
+ ((Player*)pVictim)->DurabilityLossAll(0.10f,false);
+ // durability lost message
+ WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
+ ((Player*)pVictim)->GetSession()->SendPacket(&data);
}
}
+ else // creature died
+ {
+ DEBUG_LOG("DealDamageNotPlayer");
+ Creature *cVictim = (Creature*)pVictim;
+
+ if(!cVictim->isPet())
+ {
+ cVictim->DeleteThreatList();
+ cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+ }
+ // Call creature just died function
+ if (cVictim->AI())
+ cVictim->AI()->JustDied(this);
+
+ // Dungeon specific stuff, only applies to players killing creatures
+ if(cVictim->GetInstanceId())
+ {
+ Map *m = cVictim->GetMap();
+ Player *creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself();
+ // TODO: do instance binding anyway if the charmer/owner is offline
+
+ if(m->IsDungeon() && creditedPlayer)
+ {
+ if(m->IsRaid() || m->IsHeroic())
+ {
+ if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
+ ((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer);
+ }
+ else
+ {
+ // the reset time is set but not added to the scheduler
+ // until the players leave the instance
+ time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR;
+ if(InstanceSave *save = sInstanceSaveManager.GetInstanceSave(cVictim->GetInstanceId()))
+ if(save->GetResetTime() < resettime) save->SetResetTime(resettime);
+ }
+ }
+ }
+ }
+
+ // last damage from non duel opponent or opponent controlled creature
+ if(duel_hasEnded)
+ {
+ assert(pVictim->GetTypeId()==TYPEID_PLAYER);
+ Player *he = (Player*)pVictim;
+
+ assert(he->duel);
+
+ he->duel->opponent->CombatStopWithPets(true);
+ he->CombatStopWithPets(true);
+
+ he->DuelComplete(DUEL_INTERUPTED);
+ }
+
+ // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
+ if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->InBattleGround())
+ {
+ Player *killed = ((Player*)pVictim);
+ if(BattleGround *bg = killed->GetBattleGround())
+ if(player)
+ bg->HandleKillPlayer(killed, player);
+ //later we can add support for creature->player kills here i'm
+ //not sure, but i guess those kills also get counted in av
+ //else if(GetTypeId() == TYPEID_UNIT)
+ // bg->HandleKillPlayer(killed,(Creature*)this);
+ }*/
+ }
+ else // if (health <= damage)
+ {
+ DEBUG_LOG("DealDamageAlive");
+
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage);
+
+ pVictim->ModifyHealth(- (int32)damage);
if(damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
{
@@ -831,7 +881,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
//if (!spellProto || !(spellProto->AuraInterruptFlags&AURA_INTERRUPT_FLAG_DIRECT_DAMAGE))
pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0);
}
-
if (pVictim->GetTypeId() != TYPEID_PLAYER)
{
if(spellProto && IsDamageToThreatSpell(spellProto))
@@ -898,7 +947,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if(spell->getState() == SPELL_STATE_PREPARING)
{
uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
- if(interruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE)
+ if(interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
pVictim->InterruptNonMeleeSpells(false);
else if(interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK)
spell->Delayed();
@@ -948,7 +997,7 @@ void Unit::CastStop(uint32 except_spellid)
InterruptSpell(i,false);
}
-void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
+void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
@@ -961,7 +1010,7 @@ void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castIte
CastSpell(Victim,spellInfo,triggered,castItem,triggeredByAura, originalCaster);
}
-void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
+void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
{
if(!spellInfo)
{
@@ -969,6 +1018,10 @@ void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, I
return;
}
+ if (!originalCaster && GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem() && IsControlledByPlayer())
+ if (Unit * owner = GetOwner())
+ originalCaster=owner->GetGUID();
+
SpellCastTargets targets;
uint32 targetMask = spellInfo->Targets;
//if(targetMask & (TARGET_FLAG_UNIT|TARGET_FLAG_UNK2))
@@ -1015,7 +1068,7 @@ void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, I
spell->prepare(&targets, triggeredByAura);
}
-void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
+void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
{
CustomSpellValues values;
if(bp0) values.AddSpellMod(SPELLVALUE_BASE_POINT0, *bp0);
@@ -1024,14 +1077,14 @@ void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32
CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
}
-void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, uint32 value, Unit* target, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
+void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* target, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
{
CustomSpellValues values;
values.AddSpellMod(mod, value);
CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
}
-void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* Victim, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
+void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* Victim, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
if(!spellInfo)
@@ -1088,7 +1141,7 @@ void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit*
}
// used for scripting
-void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
+void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
@@ -1113,7 +1166,7 @@ void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered,
}
// used for scripting
-void Unit::CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
+void Unit::CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
{
if(!go)
return;
@@ -1147,12 +1200,13 @@ void Unit::CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castI
}
// Obsolete func need remove, here only for comotability vs another patches
-uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
+uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask);
damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
+ DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
SendSpellNonMeleeDamageLog(&damageInfo);
DealSpellDamage(&damageInfo, true);
return damageInfo.damage;
@@ -1220,6 +1274,9 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama
if (blocked)
{
damageInfo->blocked = uint32(pVictim->GetShieldBlockValue());
+ //double blocked amount if block is critical
+ if (isBlockCritical())
+ damageInfo->blocked+=damageInfo->blocked;
if (damage < damageInfo->blocked)
damageInfo->blocked = damage;
damage-=damageInfo->blocked;
@@ -1234,7 +1291,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama
if (crit)
{
damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT;
- damage = SpellCriticalBonus(spellInfo, damage, pVictim);
+ damage = SpellCriticalDamageBonus(spellInfo, damage, pVictim);
// Resilience - reduce crit damage
if (pVictim->GetTypeId()==TYPEID_PLAYER)
damage -= ((Player*)pVictim)->GetSpellCritDamageReduction(damage);
@@ -1244,12 +1301,12 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama
}
if( damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL )
- damage = CalcArmorReducedDamage(pVictim, damage);
+ damage = CalcArmorReducedDamage(pVictim, damage, spellInfo, attackType);
// Calculate absorb resist
if(damage > 0)
{
- CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist);
+ CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
damage-= damageInfo->absorb + damageInfo->resist;
}
else
@@ -1257,6 +1314,37 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama
damageInfo->damage = damage;
}
+int32 Unit::GetIgnoredArmorMultiplier(SpellEntry const *spellInfo, WeaponAttackType attackType)
+{
+ if (GetTypeId() != TYPEID_PLAYER)
+ return 0;
+ //check if spell uses weapon
+ if (!spellInfo || spellInfo->EquippedItemClass!=ITEM_CLASS_WEAPON)
+ return 0;
+ Item *item = NULL;
+ if(attackType == BASE_ATTACK)
+ item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ else if (attackType == OFF_ATTACK)
+ item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ else if (attackType == RANGED_ATTACK)
+ item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
+ if (!item)
+ return 0;
+
+ AuraEffectList const& armAuras = GetAurasByType(SPELL_AURA_MOD_WEAPONTYPE_IGNORE_TARGET_RESISTANCE);
+ int32 armorIgnored = 0;
+ for(AuraEffectList::const_iterator i = armAuras.begin();i != armAuras.end(); ++i)
+ {
+ if (!((*i)->GetSpellProto()->EquippedItemClass==item->GetProto()->Class
+ && (*i)->GetSpellProto()->EquippedItemSubClassMask & (1<<item->GetProto()->SubClass)))
+ continue;
+
+ if((*i)->GetAmount())
+ armorIgnored += (*i)->GetAmount();
+ }
+ return (-armorIgnored);
+}
+
void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
{
if (damageInfo==0)
@@ -1267,7 +1355,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
if(!this || !pVictim)
return;
- if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
return;
SpellEntry const *spellProto = sSpellStore.LookupEntry(damageInfo->SpellID);
@@ -1286,20 +1374,6 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
return;
}
- // update at damage Judgement aura duration that applied by attacker at victim
- if(damageInfo->damage && spellProto->Id == 35395)
- {
- AuraMap& vAuras = pVictim->GetAuras();
- for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
- {
- SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
- if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
- {
- (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
- (*itr).second->UpdateAuraDuration();
- }
- }
- }
// Call default DealDamage
CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
@@ -1353,7 +1427,7 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da
}
// Physical Immune check
- if(damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask),true))
+ if(damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask)))
{
damageInfo->HitInfo |= HITINFO_NORMALSWING;
damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
@@ -1367,7 +1441,7 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da
// Add melee damage bonus
MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType);
// Calculate armor reduction
- damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage);
+ damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage, NULL , damageInfo->attackType);
damageInfo->cleanDamage += damage - damageInfo->damage;
damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType);
@@ -1455,8 +1529,12 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da
case MELEE_HIT_BLOCK:
{
damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->HitInfo |= HITINFO_BLOCK;
damageInfo->procEx|=PROC_EX_BLOCK;
damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue();
+ //double blocked amount if block is critical
+ if (isBlockCritical())
+ damageInfo->blocked_amount+=damageInfo->blocked_amount;
if (damageInfo->blocked_amount >= damageInfo->damage)
{
damageInfo->TargetState = VICTIMSTATE_BLOCKS;
@@ -1520,7 +1598,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
if(!this || !pVictim)
return;
- if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
return;
//You don't lose health from damage taken from another player while in a sanctuary
@@ -1546,29 +1624,29 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
// Reduce attack time
if (pVictim->haveOffhandWeapon() && offtime < basetime)
{
- float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20;
- float percent60 = 3 * percent20;
+ float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f;
+ float percent60 = 3.0f * percent20;
if(offtime > percent20 && offtime <= percent60)
{
pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
}
else if(offtime > percent60)
{
- offtime -= 2 * percent20;
+ offtime -= 2.0f * percent20;
pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
}
}
else
{
float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
- float percent60 = 3 * percent20;
+ float percent60 = 3.0f * percent20;
if(basetime > percent20 && basetime <= percent60)
{
pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
}
else if(basetime > percent60)
{
- basetime -= 2 * percent20;
+ basetime -= 2.0f * percent20;
pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
}
}
@@ -1580,50 +1658,35 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
// If this is a creature and it attacks from behind it has a probability to daze it's victim
if( (damageInfo->hitOutCome==MELEE_HIT_CRIT || damageInfo->hitOutCome==MELEE_HIT_CRUSHING || damageInfo->hitOutCome==MELEE_HIT_NORMAL || damageInfo->hitOutCome==MELEE_HIT_GLANCING) &&
- GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this)
+ GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->IsControlledByPlayer() && !pVictim->HasInArc(M_PI, this)
&& (pVictim->GetTypeId() == TYPEID_PLAYER || !((Creature*)pVictim)->isWorldBoss()))
{
// -probability is between 0% and 40%
// 20% base chance
- float Probability = 20;
+ float Probability = 20.0f;
//there is a newbie protection, at level 10 just 7% base chance; assuming linear function
if( pVictim->getLevel() < 30 )
- Probability = 0.65f*pVictim->getLevel()+0.5;
+ Probability = 0.65f*pVictim->getLevel()+0.5f;
uint32 VictimDefense=pVictim->GetDefenseSkillValue();
uint32 AttackerMeleeSkill=GetUnitMeleeSkill();
Probability *= AttackerMeleeSkill/(float)VictimDefense;
- if(Probability > 40)
- Probability = 40;
+ if(Probability > 40.0f)
+ Probability = 40.0f;
if(roll_chance_f(Probability))
CastSpell(pVictim, 1604, true);
}
- // update at damage Judgement aura duration that applied by attacker at victim
- if(damageInfo->damage)
- {
- AuraMap& vAuras = pVictim->GetAuras();
- for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
- {
- SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
- if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
- {
- (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
- (*itr).second->UpdateAuraDuration();
- }
- }
- }
-
if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
{
for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
{
// If usable, try to cast item spell
- if (Item * item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i))
+ if (Item * item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0,i))
if(!item->IsBroken())
if (ItemPrototype const *proto = item->GetProto())
{
@@ -1641,17 +1704,6 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
}
if (slot != i)
continue;
- // Check if item is useable (forms or disarm)
- if (damageInfo->attackType == BASE_ATTACK)
- {
- if (!((Player*)this)->IsUseEquipedWeapon(true))
- continue;
- }
- else
- {
- if (((Player*)this)->IsInFeralForm())
- continue;
- }
}
((Player*)this)->CastItemCombatSpell(item, damageInfo, proto);
}
@@ -1662,16 +1714,16 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
if (damageInfo->damage)
{
// victim's damage shield
- std::set<Aura*> alreadyDone;
- uint32 removedAuras = pVictim->m_removedAuras;
- AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
- for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
+ std::set<AuraEffect*> alreadyDone;
+ uint32 removedAuras = pVictim->m_removedAurasCount;
+ AuraEffectList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
+ for(AuraEffectList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
{
next++;
if (alreadyDone.find(*i) == alreadyDone.end())
{
alreadyDone.insert(*i);
- uint32 damage=(*i)->GetModifier()->m_amount;
+ uint32 damage=(*i)->GetAmount();
SpellEntry const *spellProto = sSpellStore.LookupEntry((*i)->GetId());
if(!spellProto)
continue;
@@ -1681,18 +1733,22 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
//CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
//damage-=absorb + resist;
- WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4));
+ pVictim->DealDamageMods(this,damage,NULL);
+
+ WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4+4+4));
data << uint64(pVictim->GetGUID());
data << uint64(GetGUID());
+ data << uint32(spellProto->Id);
+ data << uint32(damage); // Damage
+ data << uint32(0); // Overkill
data << uint32(spellProto->SchoolMask);
- data << uint32(damage);
pVictim->SendMessageToSet(&data, true );
pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true);
- if (pVictim->m_removedAuras > removedAuras)
+ if (pVictim->m_removedAurasCount > removedAuras)
{
- removedAuras = pVictim->m_removedAuras;
+ removedAuras = pVictim->m_removedAurasCount;
next = vDamageShields.begin();
}
}
@@ -1704,28 +1760,50 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
void Unit::HandleEmoteCommand(uint32 anim_id)
{
WorldPacket data( SMSG_EMOTE, 12 );
- data << anim_id << GetGUID();
- WPAssert(data.size() == 12);
-
+ data << uint32(anim_id);
+ data << uint64(GetGUID());
SendMessageToSet(&data, true);
}
-uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage)
+uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType)
{
uint32 newdamage = 0;
float armor = pVictim->GetArmor();
// Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL);
- if (armor<0.0f) armor=0.0f;
+ armor *= float((GetIgnoredArmorMultiplier(spellInfo, attackType)+100.0f)/100.0f);
+ if(spellInfo)
+ if(Player *modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
+
+ AuraEffectList const& ResIgnoreAurasAb = GetAurasByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
+ for(AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin();j != ResIgnoreAurasAb.end(); ++j)
+ {
+ if( (*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL
+ && (*j)->isAffectedOnSpell(spellInfo))
+ armor= int32(float(armor) * (float(100-(*j)->GetAmount())/100.0f));
+ }
+
+ AuraEffectList const& ResIgnoreAuras = GetAurasByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
+ for(AuraEffectList::const_iterator j = ResIgnoreAuras.begin();j != ResIgnoreAuras.end(); ++j)
+ {
+ if( (*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
+ armor= int32(float(armor) * (float(100-(*j)->GetAmount())/100.0f));
+ }
+
+ // Apply Player CR_ARMOR_PENETRATION rating
+ if (GetTypeId()==TYPEID_PLAYER)
+ armor *= 1.0f - ((Player*)this)->GetRatingBonusValue(CR_ARMOR_PENETRATION) / 100.0f;
- float tmpvalue = 0.0f;
- if(getLevel() <= 59) //Level 1-59
- tmpvalue = armor / (armor + 400.0f + 85.0f * getLevel());
- else if(getLevel() < 70) //Level 60-69
- tmpvalue = armor / (armor - 22167.5f + 467.5f * getLevel());
- else //Level 70+
- tmpvalue = armor / (armor + 10557.5f);
+ if (armor < 0.0f) armor=0.0f;
+
+ float levelModifier = getLevel();
+ if ( levelModifier > 59 )
+ levelModifier = levelModifier + (4.5f * (levelModifier-59));
+
+ float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40);
+ tmpvalue = tmpvalue/(1.0f + tmpvalue);
if(tmpvalue < 0.0f)
tmpvalue = 0.0f;
@@ -1736,7 +1814,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage)
return (newdamage > 1) ? newdamage : 1;
}
-void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist)
+void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, SpellEntry const *spellInfo)
{
if(!pVictim || !pVictim->isAlive() || !damage)
return;
@@ -1772,124 +1850,350 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
*resist += uint32(damage * m / 4);
if(*resist > damage)
*resist = damage;
+
+ AuraEffectList const& ResIgnoreAurasAb = GetAurasByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
+ for(AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin();j != ResIgnoreAurasAb.end(); ++j)
+ {
+ if( (*j)->GetMiscValue() & schoolMask
+ && (*j)->isAffectedOnSpell(spellInfo))
+ *resist= int32(float(*resist) * (float(100-(*j)->GetAmount())/100.0f));
+ }
+
+ AuraEffectList const& ResIgnoreAuras = GetAurasByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
+ for(AuraEffectList::const_iterator j = ResIgnoreAuras.begin();j != ResIgnoreAuras.end(); ++j)
+ {
+ if( (*j)->GetMiscValue() & schoolMask)
+ *resist= int32(float(*resist) * (float(100-(*j)->GetAmount())/100.0f));
+ }
}
else
*resist = 0;
int32 RemainingDamage = damage - *resist;
-
+ int32 TotalAbsorb = RemainingDamage;
+ // Get unit state (need for some absorb check)
+ uint32 unitflag = pVictim->GetUInt32Value(UNIT_FIELD_FLAGS);
+ // Reflect damage spells (not cast any damage spell in aura lookup)
+ uint32 reflectSpell = 0;
+ int32 reflectDamage = 0;
+ uint32 healSpell = 0;
+ int32 healAmount = 0;
+ Unit * healCaster = NULL;
+ // Death Prevention Aura
+ SpellEntry const* preventDeathSpell = NULL;
+ int32 preventDeathAmount = 0;
+ // Need remove expired auras after
+ bool existExpired = false;
// absorb without mana cost
- int32 reflectDamage = 0;
- Aura* reflectAura = NULL;
- AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
- for(AuraList::const_iterator i = vSchoolAbsorb.begin(), next; i != vSchoolAbsorb.end() && RemainingDamage > 0; i = next)
+ AuraEffectList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
+ for(AuraEffectList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end() && RemainingDamage > 0; ++i)
{
- next = i; ++next;
-
- if (((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
+ if (!((*i)->GetMiscValue() & schoolMask))
continue;
- // Cheat Death
- if((*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && (*i)->GetSpellProto()->SpellIconID == 2109)
+ SpellEntry const* spellProto = (*i)->GetSpellProto();
+
+ // Max Amount can be absorbed by this aura
+ int32 currentAbsorb = (*i)->GetAmount();
+
+ // Found empty aura (impossible but..)
+ if (currentAbsorb <=0)
{
- if (((Player*)pVictim)->HasSpellCooldown(31231))
- continue;
- if (pVictim->GetHealth() <= RemainingDamage)
+ existExpired = true;
+ continue;
+ }
+ // Handle custom absorb auras
+ // TODO: try find better way
+ switch(spellProto->SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
{
- int32 chance = (*i)->GetModifier()->m_amount;
- if (roll_chance_i(chance))
+ // Astral Shift
+ if (spellProto->SpellIconID == 3066)
{
- pVictim->CastSpell(pVictim,31231,true);
- ((Player*)pVictim)->AddSpellCooldown(31231,0,time(NULL)+60);
-
- // with health > 10% lost health until health==10%, in other case no losses
- uint32 health10 = pVictim->GetMaxHealth()/10;
- RemainingDamage = pVictim->GetHealth() > health10 ? pVictim->GetHealth() - health10 : 0;
+ //reduces all damage taken while stun, fear or silence
+ if (unitflag & (UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED))
+ RemainingDamage -= RemainingDamage * currentAbsorb / 100;
+ continue;
+ }
+ // Nerves of Steel
+ if (spellProto->SpellIconID == 2115)
+ {
+ // while affected by Stun and Fear
+ if (unitflag&(UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING))
+ RemainingDamage -= RemainingDamage * currentAbsorb / 100;
+ continue;
}
+ // Spell Deflection
+ if (spellProto->SpellIconID == 3006)
+ {
+ // You have a chance equal to your Parry chance
+ if (damagetype == DIRECT_DAMAGE && // Only for direct damage
+ roll_chance_f(pVictim->GetUnitParryChance())) // Roll chance
+ RemainingDamage -= RemainingDamage * currentAbsorb / 100;
+ continue;
+ }
+ // Reflective Shield (Lady Malande boss)
+ if (spellProto->Id == 41475)
+ {
+ if(RemainingDamage < currentAbsorb)
+ reflectDamage = RemainingDamage / 2;
+ else
+ reflectDamage = currentAbsorb / 2;
+ reflectSpell = 33619;
+ break;
+ }
+ if (spellProto->Id == 39228 || // Argussian Compass
+ spellProto->Id == 60218) // Essence of Gossamer
+ {
+ // Max absorb stored in 1 dummy effect
+ if (spellProto->EffectBasePoints[1] < currentAbsorb)
+ currentAbsorb = spellProto->EffectBasePoints[1];
+ break;
+ }
+ break;
}
- continue;
- }
+ case SPELLFAMILY_DRUID:
+ {
+ // Primal Tenacity
+ if (spellProto->SpellIconID == 2253)
+ {
+ //reduces all damage taken while Stunned
+ if (unitflag & UNIT_FLAG_STUNNED)
+ RemainingDamage -= RemainingDamage * currentAbsorb / 100;
+ continue;
+ }
+ break;
+ }
+ case SPELLFAMILY_ROGUE:
+ {
+ // Cheat Death (make less prio with Guardian Spirit case)
+ if (spellProto->SpellIconID == 2109)
+ {
+ if (!preventDeathSpell &&
+ pVictim->GetTypeId()==TYPEID_PLAYER && // Only players
+ !((Player*)pVictim)->HasSpellCooldown(31231) &&
+ // Only if no cooldown
+ roll_chance_i((*i)->GetAmount()))
+ // Only if roll
+ {
+ preventDeathSpell = (*i)->GetSpellProto();
+ }
+ continue;
+ }
+ break;
+ }
+ case SPELLFAMILY_PRIEST:
+ {
+ // Guardian Spirit
+ // Two implementation please check it
+ /*if (spellProto->Id==47788)
+ {
+ if (pVictim->GetHealth() <= RemainingDamage) // Killing Blow
+ {
+ healAmount = pVictim->GetMaxHealth()/2;
+ healCaster = pVictim;
+ healSpell = 48153;
+ (*i)->SetAmount(0);
+ RemainingDamage=0;
+ }
+ continue;
+ }*/
- int32 currentAbsorb;
+ if (spellProto->SpellIconID == 2873)
+ {
+ preventDeathSpell = (*i)->GetSpellProto();
+ preventDeathAmount = (*i)->GetAmount();
+ continue;
+ }
- //Reflective Shield
- if ((pVictim != this) && (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && (*i)->GetSpellProto()->SpellFamilyFlags == 0x1)
- {
- if(Unit* caster = (*i)->GetCaster())
- {
- AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k)
+ // Reflective Shield
+ if (spellProto->SpellFamilyFlags.IsEqual(0x1, 0, 0x400))
{
- switch((*k)->GetModifier()->m_miscvalue)
+ if (pVictim == this)
+ break;
+ Unit* caster = (*i)->GetCaster();
+ if (!caster)
+ break;
+ AuraEffectList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_DUMMY);
+ for(AuraEffectList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k)
{
- case 5065: // Rank 1
- case 5064: // Rank 2
- case 5063: // Rank 3
- case 5062: // Rank 4
- case 5061: // Rank 5
+ if((*k)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_PRIEST)
+ continue;
+ switch((*k)->GetMiscValue())
{
- if(RemainingDamage >= (*i)->GetModifier()->m_amount)
- reflectDamage = (*i)->GetModifier()->m_amount * (*k)->GetModifier()->m_amount/100;
- else
- reflectDamage = (*k)->GetModifier()->m_amount * RemainingDamage/100;
- reflectAura = *i;
+ case 5065: // Rank 1
+ case 5064: // Rank 2
+ case 5063: // Rank 3
+ {
+ if(RemainingDamage >= currentAbsorb)
+ reflectDamage = (*k)->GetAmount() * currentAbsorb/100;
+ else
+ reflectDamage = (*k)->GetAmount() * RemainingDamage/100;
+ reflectSpell = 33619;
+ } break;
+ }
+ }
+ }
+ // no break here, rapture can proc with reflective shield
+ // Rapture
+ if (spellProto->SpellFamilyFlags.HasFlag(0x1, 0x1000000))
+ {
+ if (pVictim == this)
+ break;
+ healCaster = (*i)->GetCaster();
+ if (!healCaster)
+ break;
- } break;
- default: break;
+ AuraEffectList const& lOverRideCS = pVictim->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(AuraEffectList::const_iterator k = lOverRideCS.begin(); k != lOverRideCS.end(); ++k)
+ {
+ switch((*k)->GetMiscValue())
+ {
+ case 7556: // Rank 1
+ case 7555: // Rank 2
+ case 7554: // Rank 3
+ case 7553: // Rank 4
+ case 7552: // Rank 5
+ {
+ healSpell = 47755;
+ healAmount += ((pVictim->getLevel() * (-0.2) + 18) / 1000000) * currentAbsorb * pVictim->GetMaxPower(POWER_MANA);
+ // limitation based on aura amount
+ if(healAmount > pVictim->GetMaxPower(POWER_MANA) * (*k)->GetAmount() / 1000)
+ healAmount = pVictim->GetMaxPower(POWER_MANA) * (*k)->GetAmount() / 1000;
+ } break;
+ }
}
+ }
+ break;
+ }
+ case SPELLFAMILY_SHAMAN:
+ {
+ // Astral Shift
+ if (spellProto->SpellIconID == 3066)
+ {
+ //reduces all damage taken while stun, fear or silence
+ if (unitflag & (UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED))
+ RemainingDamage -= RemainingDamage * currentAbsorb / 100;
+ continue;
+ }
+ break;
+ }
+ case SPELLFAMILY_DEATHKNIGHT:
+ {
+ // Shadow of Death
+ if (spellProto->SpellIconID == 1958)
+ {
+ // TODO: absorb only while transform
+ continue;
+ }
+ // Anti-Magic Shell (on self)
+ if (spellProto->Id == 48707)
+ {
+ // damage absorbed by Anti-Magic Shell energizes the DK with additional runic power.
+ // This, if I'm not mistaken, shows that we get back ~2% of the absorbed damage as runic power.
+ int32 absorbed = RemainingDamage * currentAbsorb / 100;
+ int32 regen = absorbed * 2 / 10;
+ pVictim->CastCustomSpell(pVictim, 49088, &regen, 0, 0, true, 0, (*i));
+ RemainingDamage -= absorbed;
+ continue;
+ }
+ // Anti-Magic Shell (on single party/raid member)
+ if (spellProto->Id == 50462)
+ {
+ RemainingDamage -= RemainingDamage * currentAbsorb / 100;
+ continue;
+ }
+ // Anti-Magic Zone
+ if (spellProto->Id == 50461)
+ {
+ Unit* caster = (*i)->GetCaster();
+ if (!caster)
+ continue;
+ int32 absorbed = RemainingDamage * currentAbsorb / 100;
+ int32 canabsorb = caster->GetHealth();
+ if (canabsorb < absorbed)
+ absorbed = canabsorb;
- if(reflectDamage)
- break;
+ RemainingDamage -= absorbed;
+
+ uint32 ab_damage = absorbed;
+ DealDamageMods(caster,ab_damage,NULL);
+ DealDamage(caster, ab_damage, NULL, damagetype, schoolMask, 0, false);
+ continue;
}
+ break;
}
+ default:
+ break;
}
- if (RemainingDamage >= (*i)->GetModifier()->m_amount)
- {
- currentAbsorb = (*i)->GetModifier()->m_amount;
- pVictim->RemoveAurasDueToSpell((*i)->GetId());
- next = vSchoolAbsorb.begin();
- }
- else
- {
+ // currentAbsorb - damage can be absorbed by shield
+ // If need absorb less damage
+ if (RemainingDamage < currentAbsorb)
currentAbsorb = RemainingDamage;
- (*i)->GetModifier()->m_amount -= RemainingDamage;
- }
RemainingDamage -= currentAbsorb;
+
+ // Reduce shield amount
+ (*i)->SetAmount((*i)->GetAmount() -currentAbsorb);
+ // Need remove it later
+ if ((*i)->GetAmount()<=0)
+ existExpired = true;
+ }
+ if(healSpell && healCaster)
+ healCaster->CastCustomSpell(healCaster, healSpell, &healAmount, NULL, NULL, true);
+
+ // Remove all expired absorb auras
+ if (existExpired)
+ {
+ for(AuraEffectList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end();)
+ {
+ Aura *aura=(*i)->GetParentAura();
+ AuraEffect *auraeff =(*i);
+ ++i;
+ if (auraeff->GetAmount()<=0)
+ {
+ uint32 removedAuras = pVictim->m_removedAurasCount;
+ pVictim->RemoveAura(aura, AURA_REMOVE_BY_ENEMY_SPELL);
+ if (removedAuras+1<pVictim->m_removedAurasCount)
+ i=vSchoolAbsorb.begin();
+ }
+ }
}
- // do not cast spells while looping auras; auras can get invalid otherwise
- if (reflectDamage)
- pVictim->CastCustomSpell(this, 33619, &reflectDamage, NULL, NULL, true, NULL, reflectAura);
+
+ // Cast back reflect damage spell
+ if (reflectSpell)
+ pVictim->CastCustomSpell(this, reflectSpell, &reflectDamage, NULL, NULL, true);
// absorb by mana cost
- AuraList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
- for(AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next)
+ AuraEffectList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
+ for(AuraEffectList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next)
{
next = i; ++next;
// check damage school mask
- if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
+ if(((*i)->GetMiscValue() & schoolMask)==0)
continue;
int32 currentAbsorb;
- if (RemainingDamage >= (*i)->GetModifier()->m_amount)
- currentAbsorb = (*i)->GetModifier()->m_amount;
+ if (RemainingDamage >= (*i)->GetAmount())
+ currentAbsorb = (*i)->GetAmount();
else
currentAbsorb = RemainingDamage;
float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
- if(Player *modOwner = GetSpellModOwner())
+ if(Player *modOwner = pVictim->GetSpellModOwner())
modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
if (currentAbsorb > maxAbsorb)
currentAbsorb = maxAbsorb;
- (*i)->GetModifier()->m_amount -= currentAbsorb;
- if((*i)->GetModifier()->m_amount <= 0)
+ (*i)->SetAmount((*i)->GetAmount()-currentAbsorb);
+ if((*i)->GetAmount() <= 0)
{
- pVictim->RemoveAurasDueToSpell((*i)->GetId());
+ pVictim->RemoveAura((*i)->GetParentAura(), AURA_REMOVE_BY_ENEMY_SPELL);
next = vManaShield.begin();
}
@@ -1902,13 +2206,13 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
// only split damage if not damaging yourself
if(pVictim != this)
{
- AuraList const& vSplitDamageFlat = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT);
- for(AuraList::const_iterator i = vSplitDamageFlat.begin(), next; i != vSplitDamageFlat.end() && RemainingDamage >= 0; i = next)
+ AuraEffectList const& vSplitDamageFlat = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT);
+ for(AuraEffectList::const_iterator i = vSplitDamageFlat.begin(), next; i != vSplitDamageFlat.end() && RemainingDamage >= 0; i = next)
{
next = i; ++next;
// check damage school mask
- if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
+ if(((*i)->GetMiscValue() & schoolMask)==0)
continue;
// Damage can be splitted only if aura has an alive caster
@@ -1917,26 +2221,31 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
continue;
int32 currentAbsorb;
- if (RemainingDamage >= (*i)->GetModifier()->m_amount)
- currentAbsorb = (*i)->GetModifier()->m_amount;
+ if (RemainingDamage >= (*i)->GetAmount())
+ currentAbsorb = (*i)->GetAmount();
else
currentAbsorb = RemainingDamage;
RemainingDamage -= currentAbsorb;
- SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, currentAbsorb, schoolMask, 0, 0, false, 0, false);
- CleanDamage cleanDamage = CleanDamage(currentAbsorb, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, currentAbsorb, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
+ uint32 splitted = currentAbsorb;
+ uint32 splitted_absorb = 0;
+ DealDamageMods(caster,splitted,&splitted_absorb);
+
+ SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
+
+ CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
+ DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
}
- AuraList const& vSplitDamagePct = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT);
- for(AuraList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next)
+ AuraEffectList const& vSplitDamagePct = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT);
+ for(AuraEffectList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next)
{
next = i; ++next;
// check damage school mask
- if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
+ if(((*i)->GetMiscValue() & schoolMask)==0)
continue;
// Damage can be splitted only if aura has an alive caster
@@ -1944,420 +2253,102 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive())
continue;
- int32 splitted = int32(RemainingDamage * (*i)->GetModifier()->m_amount / 100.0f);
+ uint32 splitted = uint32(RemainingDamage * (*i)->GetAmount() / 100.0f);
- RemainingDamage -= splitted;
+ RemainingDamage -= int32(splitted);
- SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, 0, 0, false, 0, false);
+ uint32 split_absorb = 0;
+ DealDamageMods(caster,splitted,&split_absorb);
+
+ SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
}
}
- *absorb = damage - RemainingDamage - *resist;
-}
-
-/*
-void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell)
-{
- MeleeHitOutcome outcome;
-
- // If is casted Melee spell, calculate like physical
- if(!spellCasted)
- outcome = RollMeleeOutcomeAgainst (pVictim, attType);
- else
- outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted);
-
- if(outcome == MELEE_HIT_MISS ||outcome == MELEE_HIT_DODGE ||outcome == MELEE_HIT_BLOCK ||outcome == MELEE_HIT_PARRY)
- pVictim->AddThreat(this, 0.0f);
- switch(outcome)
- {
- case MELEE_HIT_EVADE:
- {
- *hitInfo |= HITINFO_MISS;
- *damage = 0;
- cleanDamage->damage = 0;
- return;
- }
- case MELEE_HIT_MISS:
- {
- *hitInfo |= HITINFO_MISS;
- *damage = 0;
- cleanDamage->damage = 0;
- if(GetTypeId()== TYPEID_PLAYER)
- ((Player*)this)->UpdateWeaponSkill(attType);
- return;
- }
- }
-
- /// If this is a creature and it attacks from behind it has a probability to daze it's victim
- if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) &&
- GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this)
- && pVictim->GetTypeId() == TYPEID_PLAYER)
- {
- // -probability is between 0% and 40%
- // 20% base chance
- float Probability = 20;
-
- //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
- if( pVictim->getLevel() < 30 )
- Probability = 0.65f*pVictim->getLevel()+0.5;
-
- uint32 VictimDefense=pVictim->GetDefenseSkillValue(this);
- uint32 AttackerMeleeSkill=GetUnitMeleeSkill(pVictim);
-
- Probability *= AttackerMeleeSkill/(float)VictimDefense;
-
- if(Probability > 40.0f)
- Probability = 40.0f;
-
- if(roll_chance_f(Probability))
- CastSpell(pVictim, 1604, true);
- }
-
- //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
- if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)
+ TotalAbsorb = (TotalAbsorb - RemainingDamage > 0) ? TotalAbsorb - RemainingDamage : 0;
+ // TODO: School should be checked for absorbing auras or for attacks?
+ int32 auraAbsorbMod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL);
+ AuraEffectList const& AbsIgnoreAurasAb = GetAurasByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL);
+ for(AuraEffectList::const_iterator i = AbsIgnoreAurasAb.begin();i != AbsIgnoreAurasAb.end(); ++i)
{
- uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage);
-
- // random durability for main hand weapon (ABSORB)
- if(damageAfterArmor < *damage)
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB)))
- ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK)));
-
- cleanDamage->damage += *damage - damageAfterArmor;
- *damage = damageAfterArmor;
+ if ((*i)->GetAmount() > auraAbsorbMod
+ && (*i)->isAffectedOnSpell(spellInfo))
+ auraAbsorbMod = (*i)->GetAmount();
}
- if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
- ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false);
-
- if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
- ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true);
+ // Ignore absorb - add reduced amount again to damage
+ RemainingDamage += auraAbsorbMod * TotalAbsorb / 100;
- switch (outcome)
+ // Apply death prevention spells effects
+ if (preventDeathSpell && RemainingDamage >= pVictim->GetHealth())
{
- case MELEE_HIT_BLOCK_CRIT:
- case MELEE_HIT_CRIT:
+ switch(preventDeathSpell->SpellFamilyName)
{
- //*hitInfo = 0xEA;
- // 0xEA
- *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8;
-
- // Crit bonus calc
- uint32 crit_bonus;
- crit_bonus = *damage;
-
- // Apply crit_damage bonus for melee spells
- if (spellCasted)
- {
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
-
- uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
- AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS);
- for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- crit_bonus = uint32(crit_bonus * ((*i)->GetModifierValue()+100.0f)/100.0f);
- }
-
- *damage += crit_bonus;
-
- uint32 resilienceReduction = 0;
-
- if(attType == RANGED_ATTACK)
- {
- int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
- *damage = int32((*damage) * float((100.0f + mod)/100.0f));
- // Resilience - reduce crit damage
- if (pVictim->GetTypeId()==TYPEID_PLAYER)
- resilienceReduction = ((Player*)pVictim)->GetRangedCritDamageReduction(*damage);
- }
- else
- {
- int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
- mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
- *damage = int32((*damage) * float((100.0f + mod)/100.0f));
- // Resilience - reduce crit damage
- if (pVictim->GetTypeId()==TYPEID_PLAYER)
- resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage);
- }
-
- *damage -= resilienceReduction;
- cleanDamage->damage += resilienceReduction;
-
- if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER )
- ((Player*)this)->UpdateWeaponSkill(attType);
-
- ModifyAuraState(AURA_STATE_CRIT, true);
- StartReactiveTimer( REACTIVE_CRIT );
-
- if(getClass()==CLASS_HUNTER)
- {
- ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true);
- StartReactiveTimer( REACTIVE_HUNTER_CRIT );
- }
-
- if ( outcome == MELEE_HIT_BLOCK_CRIT )
+ // Cheat Death
+ case SPELLFAMILY_ROGUE:
{
- *blocked_amount = pVictim->GetShieldBlockValue();
-
- if (pVictim->GetUnitBlockChance())
- pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
- else
- pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
-
- //Only set VICTIMSTATE_BLOCK on a full block
- if (*blocked_amount >= uint32(*damage))
- {
- *victimState = VICTIMSTATE_BLOCKS;
- *blocked_amount = uint32(*damage);
- }
-
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
+ // Cheat Death
+ if (preventDeathSpell->SpellIconID == 2109)
{
- // Update defense
- ((Player*)pVictim)->UpdateDefense();
-
- // random durability for main hand weapon (BLOCK)
- if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK)))
- ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND);
+ pVictim->CastSpell(pVictim,31231,true);
+ ((Player*)pVictim)->AddSpellCooldown(31231,0,time(NULL)+60);
+ // with health > 10% lost health until health==10%, in other case no losses
+ uint32 health10 = pVictim->GetMaxHealth()/10;
+ RemainingDamage = pVictim->GetHealth() > health10 ? pVictim->GetHealth() - health10 : 0;
}
-
- pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true);
- pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
break;
}
-
- pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
- break;
- }
- case MELEE_HIT_PARRY:
- {
- if(attType == RANGED_ATTACK) //range attack - no parry
- {
- outcome = MELEE_HIT_NORMAL;
- break;
- }
-
- cleanDamage->damage += *damage;
- *damage = 0;
- *victimState = VICTIMSTATE_PARRY;
-
- // instant (maybe with small delay) counter attack
+ // Guardian Spirit
+ case SPELLFAMILY_PRIEST:
{
- float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
- float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
-
- // after parry nearest next attack time will reduced at %40 from full attack time.
- // The delay cannot be reduced to less than 20% of your weapon base swing delay.
- if (pVictim->haveOffhandWeapon() && offtime < basetime)
- {
- float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20;
- float percent60 = 3*percent20;
- // set to 20% if in range 20%...20+40% of full time
- if(offtime > percent20 && offtime <= percent60)
- {
- pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20));
- }
- // decrease at %40 from full time
- else if(offtime > percent60)
- {
- offtime -= 2*percent20;
- pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime));
- }
- // ELSE not changed
- }
- else
+ // Guardian Spirit
+ if (preventDeathSpell->SpellIconID == 2873)
{
- float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20;
- float percent60 = 3*percent20;
- // set to 20% if in range 20%...20+40% of full time
- if(basetime > percent20 && basetime <= percent60)
- {
- pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20));
- }
- // decrease at %40 from full time
- else if(basetime > percent60)
- {
- basetime -= 2*percent20;
- pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime));
- }
- // ELSE not changed
+ int32 healAmount = pVictim->GetMaxHealth() * preventDeathAmount / 100;
+ pVictim->CastCustomSpell(pVictim, 48153, &healAmount, NULL, NULL, true);
+ pVictim->RemoveAurasDueToSpell(preventDeathSpell->Id);
+ RemainingDamage = 0;
}
- }
-
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- {
- // Update victim defense ?
- ((Player*)pVictim)->UpdateDefense();
-
- // random durability for main hand weapon (PARRY)
- if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY)))
- ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND);
- }
-
- pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
-
- if (pVictim->getClass() == CLASS_HUNTER)
- {
- pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true);
- pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY );
- }
- else
- {
- pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
- pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
- }
-
- CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
- return;
- }
- case MELEE_HIT_DODGE:
- {
- if(attType == RANGED_ATTACK) //range attack - no dodge
- {
- outcome = MELEE_HIT_NORMAL;
break;
}
-
- cleanDamage->damage += *damage;
- *damage = 0;
- *victimState = VICTIMSTATE_DODGE;
-
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- ((Player*)pVictim)->UpdateDefense();
-
- pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
-
- if (pVictim->getClass() != CLASS_ROGUE) // Riposte
- {
- pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true);
- pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
- }
-
- // Overpower
- if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
- {
- ((Player*)this)->AddComboPoints(pVictim, 1);
- StartReactiveTimer( REACTIVE_OVERPOWER );
- }
-
- CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
- return;
- }
- case MELEE_HIT_BLOCK:
- {
- *blocked_amount = pVictim->GetShieldBlockValue();
-
- if (pVictim->GetUnitBlockChance())
- pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
- else
- pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED);
-
- //Only set VICTIMSTATE_BLOCK on a full block
- if (*blocked_amount >= uint32(*damage))
- {
- *victimState = VICTIMSTATE_BLOCKS;
- *blocked_amount = uint32(*damage);
- }
-
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- {
- // Update defense
- ((Player*)pVictim)->UpdateDefense();
-
- // random durability for main hand weapon (BLOCK)
- if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK)))
- ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND);
- }
-
- pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true);
- pVictim->StartReactiveTimer( REACTIVE_DEFENSE );
-
- break;
- }
- case MELEE_HIT_GLANCING:
- {
- int32 leveldif = int32(pVictim->getLevel()) - int32(getLevel());
- if (leveldif > 3) leveldif = 3;
- *damage *= (1 - leveldif * 0.1f);
- cleanDamage->damage = *damage;
- *hitInfo |= HITINFO_GLANCING;
- break;
- }
- case MELEE_HIT_CRUSHING:
- {
- // 150% normal damage
- *damage += (*damage / 2);
- cleanDamage->damage = *damage;
- *hitInfo |= HITINFO_CRUSHING;
- // TODO: victimState, victim animation?
- break;
}
- default:
- break;
- }
-
- // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
- if(*victimState != VICTIMSTATE_BLOCKS)
- {
- MeleeDamageBonus(pVictim, damage,attType,spellCasted);
- CalcAbsorbResist(pVictim, damageSchoolMask, DIRECT_DAMAGE, *damage-*blocked_amount, absorbDamage, resistDamage);
- }
-
- if (*absorbDamage) *hitInfo |= HITINFO_ABSORB;
- if (*resistDamage) *hitInfo |= HITINFO_RESIST;
-
- cleanDamage->damage += *blocked_amount;
-
- if (*damage <= *absorbDamage + *resistDamage + *blocked_amount)
- {
- //*hitInfo = 0x00010020;
- //*hitInfo |= HITINFO_SWINGNOHITSOUND;
- //*damageType = 0;
- CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
- return;
}
- // update at damage Judgement aura duration that applied by attacker at victim
- if(*damage)
- {
- AuraMap const& vAuras = pVictim->GetAuras();
- for(AuraMap::const_iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
- {
- SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
- if( (spellInfo->AttributesEx3 & 0x40000) && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN &&
- ((*itr).second->GetCasterGUID() == GetGUID() && (!spellCasted || spellCasted->Id == 35395)) )
- {
- (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
- (*itr).second->UpdateAuraDuration();
- }
- }
- }
+ *absorb = damage - RemainingDamage - *resist;
- CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);eld
- // yet another hack to fix crashes related to the aura getting removed during iteration
- std::set<Aura*> alreadyDone;
- uint32 removedAuras = pVictim->m_removedAuras;
- AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
- for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
+ if (*absorb)
{
- ++next;
- if (alreadyDone.find(*i) == alreadyDone.end())
+ bool found = false;
+ int32 spell_dmg=0;
+ // Incanter's Absorption
+ AuraEffectList const& DummmyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
+ for(AuraEffectList::const_iterator i = DummmyAuras.begin(); i != DummmyAuras.end(); ++i)
{
- alreadyDone.insert(*i);
- pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifierValue(), false, false);
- if (pVictim->m_removedAuras > removedAuras)
+ SpellEntry const* spellInfo = (*i)->GetSpellProto();
+ if (spellmgr.GetFirstSpellInChain(spellInfo->Id) == 44394)
{
- removedAuras = pVictim->m_removedAuras;
- next = vDamageShields.begin();
- }
+ int32 total_dmg=0;
+ // Get total bonus from auras
+ AuraEffectList const& BonusAuras = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
+ for(AuraEffectList::const_iterator itr = BonusAuras.begin(); itr != BonusAuras.end(); ++itr)
+ {
+ if ((*itr)->GetId()==44413)
+ total_dmg += (*itr)->GetMiscValue();
+ }
+ spell_dmg = int32(*absorb * (*i)->GetAmount() / 100);
+ // Do not apply more auras if more than 5% hp
+ if(total_dmg+spell_dmg > int32(GetMaxHealth() * 5 / 100))
+ break;
+ found=true;
+ break;
+ }
}
+ if (found)
+ pVictim->CastCustomSpell(pVictim, 44413, &spell_dmg, NULL, NULL, false);
}
-}*/
+}
void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra )
{
@@ -2395,13 +2386,16 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
--m_extraAttacks;
}
}
-
return;
}
+ // attack can be redirected to another target
+ pVictim = SelectMagnetTarget(pVictim);
+
CalcDamageInfo damageInfo;
CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
// Send log damage message to client
+ DealDamageMods(pVictim,damageInfo.damage,&damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
DealMeleeDamage(&damageInfo,true);
@@ -2413,6 +2407,10 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
+ // if damage pVictim call AI reaction
+ //if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->AI())
+ // ((Creature*)pVictim)->AI()->AttackedBy(this);
+
// extra attack only at any non extra attack (normal case)
if(!extra && extraAttacks)
{
@@ -2425,67 +2423,6 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
}
}
-/*
-MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo)
-{
- // Miss chance based on melee
- float miss_chance = MeleeMissChanceCalc(pVictim, attType);
-
- // Critical hit chance
- float crit_chance = GetUnitCriticalChance(attType, pVictim);
- // this is to avoid compiler issue when declaring variables inside if
- float block_chance, parry_chance, dodge_chance;
-
- // cannot be dodged/parried/blocked
- if(spellInfo->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
- {
- block_chance = 0.0f;
- parry_chance = 0.0f;
- dodge_chance = 0.0f;
- }
- else
- {
- // parry can be avoided only by some abilities
- parry_chance = pVictim->GetUnitParryChance();
- // block might be bypassed by it as well
- block_chance = pVictim->GetUnitBlockChance();
- // stunned target cannot dodge and this is check in GetUnitDodgeChance()
- dodge_chance = pVictim->GetUnitDodgeChance();
- }
-
- // Only players can have Talent&Spell bonuses
- if (GetTypeId() == TYPEID_PLAYER)
- {
- // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
- crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, spellInfo->SchoolMask);
-
- if( dodge_chance != 0.0f ) // if dodge chance is already 0, ignore talents for speed
- {
- AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
- for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
- {
- // can't be dodged rogue finishing move
- if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE)
- {
- if(spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
- {
- dodge_chance = 0.0f;
- break;
- }
- }
- }
- }
- }
-
- // Spellmods
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
-
- DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance,crit_chance,dodge_chance,parry_chance, block_chance);
-
- return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100),int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), true);
-}*/
-
MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const
{
// This is only wrapper
@@ -2505,10 +2442,10 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackT
// Useful if want to specify crit & miss chances for melee, else it could be removed
DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance,crit_chance,dodge_chance,parry_chance,block_chance);
- return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), false);
+ return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100));
}
-MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const
+MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const
{
if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
return MELEE_HIT_EVADE;
@@ -2521,7 +2458,6 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack
// bonus from skills is 0.04%
int32 skillBonus = 4 * ( attackerWeaponSkill - victimMaxSkillValueForLevel );
- int32 skillBonus2 = 4 * ( attackerMaxSkillValueForLevel - victimDefenseSkill );
int32 sum = 0, tmp = 0;
int32 roll = urand (0, 10000);
@@ -2559,6 +2495,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack
// Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
+ dodge_chance = int32 (float (dodge_chance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
tmp = dodge_chance;
if ( (tmp > 0) // check if unit _can_ dodge
@@ -2585,12 +2522,12 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack
if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY) )
{
- int32 tmp = int32(parry_chance);
- if ( (tmp > 0) // check if unit _can_ parry
- && ((tmp -= skillBonus) > 0)
- && (roll < (sum += tmp)))
+ int32 tmp2 = int32(parry_chance);
+ if ( (tmp2 > 0) // check if unit _can_ parry
+ && ((tmp2 -= skillBonus) > 0)
+ && (roll < (sum += tmp2)))
{
- DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp, sum);
+ DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp2, sum);
return MELEE_HIT_PARRY;
}
}
@@ -2602,16 +2539,6 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack
&& ((tmp -= skillBonus) > 0)
&& (roll < (sum += tmp)))
{
- // Critical chance
- tmp = crit_chance + skillBonus2;
- if ( GetTypeId() == TYPEID_PLAYER && SpellCasted && tmp > 0 )
- {
- if ( roll_chance_i(tmp/100))
- {
- DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
- return MELEE_HIT_BLOCK_CRIT;
- }
- }
DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
return MELEE_HIT_BLOCK;
}
@@ -2619,7 +2546,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack
}
// Critical chance
- tmp = crit_chance + skillBonus2;
+ tmp = crit_chance;
if (tmp > 0 && roll < (sum += tmp))
{
@@ -2631,7 +2558,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack
}
// Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon)
- if( attType != RANGED_ATTACK && !SpellCasted &&
+ if( attType != RANGED_ATTACK &&
(GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) &&
pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() &&
getLevel() < pVictim->getLevelForTarget(this) )
@@ -2650,10 +2577,13 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack
}
}
- if(GetTypeId()!=TYPEID_PLAYER && !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) && !((Creature*)this)->isPet() && !SpellCasted /*Only autoattack can be crushing blow*/ )
+ // mobs can score crushing blows if they're 4 or more levels above victim
+ if (getLevelForTarget(pVictim) >= pVictim->getLevelForTarget(this) + 4 &&
+ // can be from by creature (if can) or from controlled player that considered as creature
+ !IsControlledByPlayer() &&
+ !(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH))
{
- // mobs can score crushing blows if they're 3 or more levels above victim
- // or when their weapon skill is 15 or more above victim's defense skill
+ // when their weapon skill is 15 or more above victim's defense skill
tmp = victimDefenseSkill;
int32 tmpmax = victimMaxSkillValueForLevel;
// having defense above your maximum (from items, talents etc.) has no effect
@@ -2759,36 +2689,56 @@ void Unit::SendAttackStop(Unit* victim)
((Creature*)victim)->AI().EnterEvadeMode(this);*/
}
-bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType)
+bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const * /*spellProto*/, WeaponAttackType attackType)
{
if (pVictim->HasInArc(M_PI,this))
{
- float blockChance = GetUnitBlockChance();
- blockChance += (GetWeaponSkillValue(attackType) - pVictim->GetMaxSkillValueForLevel() )*0.04;
+ /* Currently not exist spells with ignore block
+ // Ignore combat result aura (parry/dodge check on prepare)
+ AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
+ for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
+ {
+ if (!(*i)->isAffectedOnSpell(spellProto))
+ continue;
+ if ((*i)->GetMiscValue() == )
+ return false;
+ }
+ */
+
+ // Check creatures flags_extra for disable block
+ if(pVictim->GetTypeId()==TYPEID_UNIT &&
+ ((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK )
+ return false;
+
+ float blockChance = pVictim->GetUnitBlockChance();
+ blockChance += (int32(GetWeaponSkillValue(attackType)) - int32(pVictim->GetMaxSkillValueForLevel()))*0.04f;
if (roll_chance_f(blockChance))
return true;
}
return false;
}
+bool Unit::isBlockCritical()
+{
+ if (roll_chance_i(GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_CRIT_CHANCE)))
+ return true;
+ return false;
+}
+
// Melee based spells can be miss, parry or dodge on this step
// Crit or block - determined on damage calculation phase! (and can be both in some time)
-float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
+/*float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
{
// Calculate hit chance (more correct for chance mod)
int32 HitChance;
// PvP - PvE melee chances
- /*int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
+ int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
if(leveldif < 3)
HitChance = 95 - leveldif;
else
- HitChance = 93 - (leveldif - 2) * lchance;*/
- if (spellId || attType == RANGED_ATTACK || !haveOffhandWeapon())
- HitChance = 95.0f;
- else
- HitChance = 76.0f;
+ HitChance = 93 - (leveldif - 2) * lchance;
// Hit chance depends from victim auras
if(attType == RANGED_ATTACK)
@@ -2797,11 +2747,8 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType,
HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
- if(spellId)
- {
- if(Player *modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
- }
+ if(Player *modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
// Miss = 100 - hit
float miss_chance= 100.0f - HitChance;
@@ -2813,12 +2760,7 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType,
miss_chance -= m_modMeleeHitChance;
// bonus from skills is 0.04%
- //miss_chance -= skillDiff * 0.04f;
- int32 diff = -skillDiff;
- if(pVictim->GetTypeId()==TYPEID_PLAYER)
- miss_chance += diff > 0 ? diff * 0.04 : diff * 0.02;
- else
- miss_chance += diff > 10 ? 2 + (diff - 10) * 0.4 : diff * 0.1;
+ miss_chance -= skillDiff * 0.04f;
// Limit miss chance from 0 to 60%
if (miss_chance < 0.0f)
@@ -2826,84 +2768,141 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType,
if (miss_chance > 60.0f)
return 60.0f;
return miss_chance;
-}
+}*/
// Melee based spells hit result calculations
SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
{
WeaponAttackType attType = BASE_ATTACK;
- if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
+ if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED && IsRangedWeaponSpell(spell))
attType = RANGED_ATTACK;
+ int32 attackerWeaponSkill;
+ // skill value for these spells (for example judgements) is 5* level
+ if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !IsRangedWeaponSpell(spell))
+ attackerWeaponSkill = getLevel() * 5;
// bonus from skills is 0.04% per skill Diff
- int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
+ else
+ attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
+
int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
uint32 roll = urand (0, 10000);
- uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell->Id)*100.0f);
+ uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell->Id)*100.0f);
// Roll miss
uint32 tmp = missChance;
if (roll < tmp)
return SPELL_MISS_MISS;
+ // Chance resist mechanic (select max value from every mechanic spell effect)
+ int32 resist_mech = 0;
+ // Get effects mechanic and chance
+ for(int eff = 0; eff < 3; ++eff)
+ {
+ int32 effect_mech = GetEffectMechanic(spell, eff);
+ if (effect_mech)
+ {
+ int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech);
+ if (resist_mech < temp*100)
+ resist_mech = temp*100;
+ }
+ }
+ // Roll chance
+ tmp += resist_mech;
+ if (roll < tmp)
+ return SPELL_MISS_RESIST;
+
+ bool canDodge = true;
+ bool canParry = true;
+
// Same spells cannot be parry/dodge
if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
return SPELL_MISS_NONE;
- // Ranged attack can`t miss too
- if (attType == RANGED_ATTACK)
+ // Ranged attack cannot be parry/dodge only deflect
+ // Check damage class instead of attack type to correctly handle judgements
+ // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
+ if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
+ {
+ // only if in front
+ if (pVictim->HasInArc(M_PI,this))
+ {
+ int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS)*100;
+ tmp+=deflect_chance;
+ if (roll < tmp)
+ return SPELL_MISS_DEFLECT;
+ }
return SPELL_MISS_NONE;
+ }
- bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
-
- // Roll dodge
- int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
- // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
- dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
-
- // Reduce dodge chance by attacker expertise rating
- if (GetTypeId() == TYPEID_PLAYER)
- dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
- if (dodgeChance < 0)
- dodgeChance = 0;
-
- // Can`t dodge from behind in PvP (but its possible in PvE)
- if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
- dodgeChance = 0;
-
- // Rogue talent`s cant be dodged
- AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
- for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
+ // Check for attack from behind
+ if (!pVictim->HasInArc(M_PI,this))
{
- if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
+ // Can`t dodge from behind in PvP (but its possible in PvE)
+ if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ canDodge = false;
+ // Can`t parry
+ canParry = false;
+ }
+ // Check creatures flags_extra for disable parry
+ if(pVictim->GetTypeId()==TYPEID_UNIT)
+ {
+ uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->flags_extra;
+ if( flagEx & CREATURE_FLAG_EXTRA_NO_PARRY )
+ canParry = false;
+ }
+ // Ignore combat result aura
+ AuraEffectList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
+ for(AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
+ {
+ if (!(*i)->isAffectedOnSpell(spell))
+ continue;
+ switch((*i)->GetMiscValue())
{
- if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
- {
- dodgeChance = 0;
+ case MELEE_HIT_DODGE: canDodge = false; break;
+ case MELEE_HIT_BLOCK: break; // Block check in hit step
+ case MELEE_HIT_PARRY: canParry = false; break;
+ default:
+ DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue());
break;
- }
}
}
- tmp += dodgeChance;
- if (roll < tmp)
- return SPELL_MISS_DODGE;
+ if (canDodge)
+ {
+ // Roll dodge
+ int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
+ // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
+ dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE)*100;
+ dodgeChance = int32 (float (dodgeChance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
+ // Reduce dodge chance by attacker expertise rating
+ if (GetTypeId() == TYPEID_PLAYER)
+ dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
+ if (dodgeChance < 0)
+ dodgeChance = 0;
- // Roll parry
- int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
- // Reduce parry chance by attacker expertise rating
- if (GetTypeId() == TYPEID_PLAYER)
- parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
- // Can`t parry from behind
- if (parryChance < 0 || attackFromBehind)
- parryChance = 0;
+ tmp += dodgeChance;
+ if (roll < tmp)
+ return SPELL_MISS_DODGE;
+ }
- tmp += parryChance;
- if (roll < tmp)
- return SPELL_MISS_PARRY;
+ if (canParry)
+ {
+ // Roll parry
+ int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
+ // Reduce parry chance by attacker expertise rating
+ if (GetTypeId() == TYPEID_PLAYER)
+ parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
+ if (parryChance < 0)
+ parryChance = 0;
+
+ tmp += parryChance;
+ if (roll < tmp)
+ return SPELL_MISS_PARRY;
+ }
return SPELL_MISS_NONE;
}
@@ -2968,11 +2967,24 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell)
HitChance -= int32(((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)*100.0f);
if (HitChance < 100) HitChance = 100;
- if (HitChance > 9900) HitChance = 9900;
+ if (HitChance > 10000) HitChance = 10000;
+
+ int32 tmp = 10000 - HitChance;
uint32 rand = urand(0,10000);
- if (rand > HitChance)
+
+ if (rand < tmp)
return SPELL_MISS_RESIST;
+
+ // cast by caster in front of victim
+ if (pVictim->HasInArc(M_PI,this))
+ {
+ int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS)*100;
+ tmp+=deflect_chance;
+ if (rand < tmp)
+ return SPELL_MISS_DEFLECT;
+ }
+
return SPELL_MISS_NONE;
}
@@ -2990,12 +3002,8 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool
if (pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
return SPELL_MISS_EVADE;
- // If Spel has this flag cannot be resisted/immuned/etc
- if (spell->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY)
- return SPELL_MISS_NONE;
-
- // Check for immune (use charges)
- if (pVictim->IsImmunedToSpell(spell,true))
+ // Check for immune
+ if (pVictim->IsImmunedToSpell(spell))
return SPELL_MISS_IMMUNE;
// All positive spells can`t miss
@@ -3003,9 +3011,8 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool
if (IsPositiveSpell(spell->Id)
&&(!IsHostileTo(pVictim))) //prevent from affecting enemy by "positive" spell
return SPELL_MISS_NONE;
-
- // Check for immune (use charges)
- if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell),true))
+ // Check for immune
+ if (pVictim->IsImmunedToDamage(spell))
return SPELL_MISS_IMMUNE;
if(this == pVictim)
@@ -3015,10 +3022,10 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool
if (CanReflect)
{
int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
- Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
- for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
- if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell))
- reflectchance = (*i)->GetModifierValue();
+ Unit::AuraEffectList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
+ for(Unit::AuraEffectList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
+ if((*i)->GetMiscValue() & GetSpellSchoolMask(spell))
+ reflectchance += (*i)->GetAmount();
if (reflectchance > 0 && roll_chance_i(reflectchance))
{
// Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
@@ -3193,7 +3200,7 @@ float Unit::GetUnitBlockChance() const
Player const* player = (Player const*)this;
if(player->CanBlock() )
{
- Item *tmpitem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ Item *tmpitem = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block)
return GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
}
@@ -3259,6 +3266,9 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVict
crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE);
}
+ // Apply crit chance from defence skill
+ crit += (int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetDefenseSkillValue(this))) * 0.04f;
+
if (crit < 0.0f)
crit = 0.0f;
return crit;
@@ -3273,20 +3283,16 @@ uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target)
// feral or unarmed skill only for base attack
if(attType != BASE_ATTACK && !item )
- {
- if(attType == RANGED_ATTACK && getClass() == CLASS_PALADIN) //hammer
- return GetMaxSkillValueForLevel();
return 0;
- }
- if(((Player*)this)->IsInFeralForm())
+ if(IsInFeralForm())
return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
// weapon skill or (unarmed for base attack)
uint32 skill = item ? item->GetSkill() : SKILL_UNARMED;
// in PvP use full skill instead current skill value
- value = (target && target->GetTypeId() == TYPEID_PLAYER)
+ value = (target && target->IsControlledByPlayer())
? ((Player*)this)->GetMaxSkillValue(skill)
: ((Player*)this)->GetSkillValue(skill);
// Modify value from ratings
@@ -3303,6 +3309,17 @@ uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target)
return value;
}
+void Unit::_DeleteAuras()
+{
+ for (AuraList::iterator i = m_removedAuras.begin(); i != m_removedAuras.end();i = m_removedAuras.begin())
+ {
+ Aura * Aur = *i;
+ sLog.outDebug("Aura %d is deleted from unit %d", Aur->GetId(), GetGUIDLow());
+ m_removedAuras.pop_front();
+ delete (Aur);
+ }
+}
+
void Unit::_UpdateSpells( uint32 time )
{
if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
@@ -3319,54 +3336,48 @@ void Unit::_UpdateSpells( uint32 time )
}
// TODO: Find a better way to prevent crash when multiple auras are removed.
- m_removedAuras = 0;
for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
- if ((*i).second)
- (*i).second->SetUpdated(false);
+ i->second->SetUpdated(false);
- for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next)
+ for(AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
{
- next = i;
- ++next;
- if ((*i).second)
+ Aura *aur = i->second;
+
+ // prevent double update
+ if(aur->IsUpdated())
{
- // prevent double update
- if ((*i).second->IsUpdated())
- continue;
- (*i).second->SetUpdated(true);
- (*i).second->Update( time );
- // several auras can be deleted due to update
- if (m_removedAuras)
- {
- if (m_Auras.empty()) break;
- next = m_Auras.begin();
- m_removedAuras = 0;
- }
+ ++i;
+ continue;
}
- }
- for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
- {
- if ((*i).second)
+ aur->SetUpdated(true);
+
+ m_removedAurasCount = 0;
+ aur->Update( time );
+
+ // several auras can be deleted due to update
+ if(m_removedAurasCount)
{
- if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) )
- {
- RemoveAura(i);
- }
- else
- {
- ++i;
- }
+ m_removedAurasCount = 0;
+ i = m_Auras.begin();
}
else
- {
++i;
- }
}
+ for(AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
+ {
+ if(i->second->IsExpired())
+ RemoveAura(i, AURA_REMOVE_BY_EXPIRE);
+ else
+ ++i;
+ }
+
+ _DeleteAuras();
+
if(!m_gameObj.empty())
{
- std::list<GameObject*>::iterator ite1, dnext1;
+ GameObjectList::iterator ite1, dnext1;
for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1)
{
dnext1 = ite1;
@@ -3390,7 +3401,7 @@ void Unit::_UpdateAutoRepeatSpell()
if ( (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
{
// cancel wand shoot
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
+ if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT)
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
m_AutoRepeatFirstCast = true;
return;
@@ -3405,7 +3416,7 @@ void Unit::_UpdateAutoRepeatSpell()
if (isAttackReady(RANGED_ATTACK))
{
// Check if able to cast
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true))
+ if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK)
{
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
return;
@@ -3424,7 +3435,7 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell )
{
assert(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
- uint32 CSpellType = pSpell->GetCurrentContainer();
+ CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
@@ -3443,7 +3454,7 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell )
if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
{
// break autorepeat if not Auto Shot
- if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351)
+ if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT)
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
m_AutoRepeatFirstCast = true;
}
@@ -3458,7 +3469,7 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell )
// it also does break autorepeat if not Auto Shot
if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
- m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351 )
+ m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT )
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
addUnitState(UNIT_STAT_CASTING);
} break;
@@ -3466,7 +3477,7 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell )
case CURRENT_AUTOREPEAT_SPELL:
{
// only Auto Shoot does not break anything
- if (pSpell->m_spellInfo->Category == 351)
+ if (pSpell->m_spellInfo->Id != SPELL_ID_AUTOSHOT)
{
// generic autorepeats break generic non-delayed and channeled non-delayed spells
InterruptSpell(CURRENT_GENERIC_SPELL,false);
@@ -3565,7 +3576,7 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
return NULL;
}
-bool Unit::isInFront(Unit const* target, float distance, float arc) const
+bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
{
return IsWithinDistInMap(target, distance) && HasInArc( arc, target );
}
@@ -3575,7 +3586,7 @@ void Unit::SetInFront(Unit const* target)
SetOrientation(GetAngle(target));
}
-bool Unit::isInBack(Unit const* target, float distance, float arc) const
+bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
{
return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target );
}
@@ -3615,9 +3626,9 @@ int32 Unit::GetTotalAuraModifier(AuraType auratype) const
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- modifier += (*i)->GetModifierValue();
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ modifier += (*i)->GetAmount();
return modifier;
}
@@ -3626,23 +3637,22 @@ float Unit::GetTotalAuraMultiplier(AuraType auratype) const
{
float multiplier = 1.0f;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ multiplier *= (100.0f + (*i)->GetAmount())/100.0f;
return multiplier;
}
-int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const
+int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype)
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- int32 amount = (*i)->GetModifierValue();
- if (amount > modifier)
- modifier = amount;
+ if ((*i)->GetAmount() > modifier)
+ modifier = (*i)->GetAmount();
}
return modifier;
@@ -3652,13 +3662,10 @@ int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- {
- int32 amount = (*i)->GetModifierValue();
- if (amount < modifier)
- modifier = amount;
- }
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ if ((*i)->GetAmount() < modifier)
+ modifier = (*i)->GetAmount();
return modifier;
}
@@ -3667,12 +3674,11 @@ int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask)
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue & misc_mask)
- modifier += (*i)->GetModifierValue();
+ if ((*i)->GetMiscValue()& misc_mask)
+ modifier += (*i)->GetAmount();
}
return modifier;
}
@@ -3681,12 +3687,11 @@ float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask
{
float multiplier = 1.0f;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue & misc_mask)
- multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
+ if ((*i)->GetMiscValue()& misc_mask)
+ multiplier *= (100.0f + (*i)->GetAmount())/100.0f;
}
return multiplier;
}
@@ -3695,13 +3700,11 @@ int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- int32 amount = (*i)->GetModifierValue();
- if (mod->m_miscvalue & misc_mask && amount > modifier)
- modifier = amount;
+ if ((*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() > modifier)
+ modifier = (*i)->GetAmount();
}
return modifier;
@@ -3711,13 +3714,11 @@ int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- int32 amount = (*i)->GetModifierValue();
- if (mod->m_miscvalue & misc_mask && amount < modifier)
- modifier = amount;
+ if ((*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() < modifier)
+ modifier = (*i)->GetAmount();
}
return modifier;
@@ -3727,12 +3728,11 @@ int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value)
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue == misc_value)
- modifier += (*i)->GetModifierValue();
+ if ((*i)->GetMiscValue()== misc_value)
+ modifier += (*i)->GetAmount();
}
return modifier;
}
@@ -3741,12 +3741,11 @@ float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_valu
{
float multiplier = 1.0f;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue == misc_value)
- multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
+ if ((*i)->GetMiscValue()== misc_value)
+ multiplier *= (100.0f + (*i)->GetAmount())/100.0f;
}
return multiplier;
}
@@ -3755,13 +3754,11 @@ int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- int32 amount = (*i)->GetModifierValue();
- if (mod->m_miscvalue == misc_value && amount > modifier)
- modifier = amount;
+ if ((*i)->GetMiscValue()== misc_value && (*i)->GetAmount() > modifier)
+ modifier = (*i)->GetAmount();
}
return modifier;
@@ -3771,20 +3768,25 @@ int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_
{
int32 modifier = 0;
- AuraList const& mTotalAuraList = GetAurasByType(auratype);
- for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
- Modifier* mod = (*i)->GetModifier();
- int32 amount = (*i)->GetModifierValue();
- if (mod->m_miscvalue == misc_value && amount < modifier)
- modifier = amount;
+ if ((*i)->GetMiscValue()== misc_value && (*i)->GetAmount() < modifier)
+ modifier = (*i)->GetAmount();
}
return modifier;
}
-bool Unit::AddAura(Aura *Aur)
+bool Unit::AddAura(Aura *Aur, bool handleEffects)
{
+ // aura doesn't apply effects-return
+ if (!Aur->GetEffectMask() || Aur->IsExpired())
+ {
+ delete Aur;
+ return false;
+ }
+
// ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
if( !isAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 &&
(GetTypeId()!=TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading()) )
@@ -3795,8 +3797,8 @@ bool Unit::AddAura(Aura *Aur)
if(Aur->GetTarget() != this)
{
- sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
- Aur->GetId(),Aur->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(),
+ sLog.outError("Aura (spell %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
+ Aur->GetId(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(),
(Aur->GetTarget()->GetTypeId()==TYPEID_PLAYER?"player":"creature"),Aur->GetTarget()->GetGUIDLow());
delete Aur;
return false;
@@ -3804,62 +3806,28 @@ bool Unit::AddAura(Aura *Aur)
SpellEntry const* aurSpellInfo = Aur->GetSpellProto();
- spellEffectPair spair = spellEffectPair(Aur->GetId(), Aur->GetEffIndex());
-
- bool stackModified=false;
- // passive and persistent auras can stack with themselves any number of times
- if (!Aur->IsPassive() && !Aur->IsPersistent())
+ // passive and persistent and Incanter's Absorption auras can stack with themselves any number of times
+ if (!Aur->IsPassive() && !Aur->IsPersistent() && aurSpellInfo->Id != 44413)
{
- for(AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair);)
+ // find current aura from spell and change it's stackamount
+ if (Aura * foundAura = GetAura(aurSpellInfo->Id, Aur->GetCasterGUID()))
{
- if(i2->second->GetCasterGUID()==Aur->GetCasterGUID())
- {
- if (!stackModified)
- {
- // replace aura if next will > spell StackAmount
- if(aurSpellInfo->StackAmount)
- {
- // prevent adding stack more than once
- stackModified=true;
- Aur->SetStackAmount(i2->second->GetStackAmount());
- if(Aur->GetStackAmount() < aurSpellInfo->StackAmount)
- Aur->SetStackAmount(Aur->GetStackAmount()+1);
- }
- RemoveAura(i2,AURA_REMOVE_BY_STACK);
- i2=m_Auras.lower_bound(spair);
- continue;
- }
- }
- switch(aurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()])
+ if(aurSpellInfo->StackAmount)
{
- // DOT or HOT from different casters will stack
- case SPELL_AURA_PERIODIC_DAMAGE:
- case SPELL_AURA_PERIODIC_HEAL:
- case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
- case SPELL_AURA_PERIODIC_ENERGIZE:
- case SPELL_AURA_PERIODIC_MANA_LEECH:
- case SPELL_AURA_PERIODIC_LEECH:
- case SPELL_AURA_POWER_BURN_MANA:
- case SPELL_AURA_OBS_MOD_MANA:
- case SPELL_AURA_OBS_MOD_HEALTH:
- ++i2;
- continue;
+ uint8 stackAmount = foundAura->GetStackAmount() + 1;
+ if (stackAmount > aurSpellInfo->StackAmount)
+ stackAmount = aurSpellInfo->StackAmount;
+ Aur->SetStackAmount(stackAmount, false);
}
- RemoveAura(i2,AURA_REMOVE_BY_STACK);
- i2=m_Auras.lower_bound(spair);
- continue;
+ RemoveAura(foundAura, AURA_REMOVE_BY_STACK);
}
}
- // passive auras stack with all (except passive spell proc auras)
- if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) &&
- !(Aur->GetId() == 20584 || Aur->GetId() == 8326))
+ // passive auras not stacable with other ranks
+ if (!RemoveNoStackAurasDueToAura(Aur))
{
- if (!RemoveNoStackAurasDueToAura(Aur))
- {
- delete Aur;
- return false; // couldn't remove conflicting aura with higher rank
- }
+ delete Aur;
+ return false; // couldn't remove conflicting aura with higher rank
}
// update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
@@ -3879,12 +3847,7 @@ bool Unit::AddAura(Aura *Aur)
if( (*itr)->GetTarget() != Aur->GetTarget() &&
IsSingleTargetSpells((*itr)->GetSpellProto(),aurSpellInfo) )
{
- if ((*itr)->IsInUse())
- {
- sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for IsSingleTargetSpell", (*itr)->GetId(), (*itr)->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
- continue;
- }
- (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
+ (*itr)->GetTarget()->RemoveAurasDueToSpell((*itr)->GetId(), caster->GetGUID(), AURA_REMOVE_BY_STACK);
restart = true;
break;
}
@@ -3901,99 +3864,56 @@ bool Unit::AddAura(Aura *Aur)
// add aura, register in lists and arrays
Aur->_AddAura();
- m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur));
- if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
+ m_Auras.insert(AuraMap::value_type(Aur->GetId(), Aur));
+
+ if(Aur->GetSpellProto()->AuraInterruptFlags)
{
- m_modAuras[Aur->GetModifier()->m_auraname].push_back(Aur);
- if(Aur->GetSpellProto()->AuraInterruptFlags)
- {
- m_interruptableAuras.push_back(Aur);
- AddInterruptMask(Aur->GetSpellProto()->AuraInterruptFlags);
- }
- if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE)
- && (Aur->GetModifier()->m_auraname != SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
- {
- m_ccAuras.push_back(Aur);
- }
+ m_interruptableAuras.push_back(Aur);
+ AddInterruptMask(Aur->GetSpellProto()->AuraInterruptFlags);
}
-
- Aur->ApplyModifier(true,true);
-
- uint32 id = Aur->GetId();
- if(spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_AURA)
+ if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE
+ && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
+ || ((GetAllSpellMechanicMask(Aur->GetSpellProto()) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN)))
{
- if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(id + SPELL_LINK_AURA))
- for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
- if(*itr < 0)
- ApplySpellImmune(id, IMMUNITY_ID, -(*itr), true);
- else if(Unit* caster = Aur->GetCaster())
- caster->AddAura(*itr, this);
+ m_ccAuras.push_back(Aur);
}
- sLog.outDebug("Aura %u now is in use", Aur->GetModifier()->m_auraname);
- return true;
-}
+ if (handleEffects)
+ Aur->HandleEffects(true);
-void Unit::RemoveRankAurasDueToSpell(uint32 spellId)
-{
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
- if(!spellInfo)
- return;
- AuraMap::iterator i,next;
- for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
- {
- next = i;
- ++next;
- uint32 i_spellId = (*i).second->GetId();
- if((*i).second && i_spellId && i_spellId != spellId)
- {
- if(spellmgr.IsRankSpellDueToSpell(spellInfo,i_spellId))
- {
- RemoveAurasDueToSpell(i_spellId);
-
- if( m_Auras.empty() )
- break;
- else
- next = m_Auras.begin();
- }
- }
- }
+ sLog.outDebug("Aura %u now is in use", Aur->GetId());
+ return true;
}
bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
{
- if (!Aur)
- return false;
-
SpellEntry const* spellProto = Aur->GetSpellProto();
- if (!spellProto)
- return false;
uint32 spellId = Aur->GetId();
- uint32 effIndex = Aur->GetEffIndex();
- SpellSpecific spellId_spec = GetSpellSpecific(spellId);
-
- AuraMap::iterator i,next;
- for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
- {
- next = i;
- ++next;
- if (!(*i).second) continue;
+ // passive spell special case (only non stackable with ranks)
+ if(IsPassiveSpell(spellId) && IsPassiveSpellStackableWithRanks(spellProto))
+ return true;
- SpellEntry const* i_spellProto = (*i).second->GetSpellProto();
+ //bool linked = spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_LINK_AURA? true : false;
- if (!i_spellProto)
- continue;
+ bool remove = false;
+ for(AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
+ {
+ if(remove)
+ {
+ remove = false;
+ i = m_Auras.begin();
+ }
+ SpellEntry const* i_spellProto = i->second->GetSpellProto();
uint32 i_spellId = i_spellProto->Id;
-
- if (spellId==i_spellId)
- continue;
+ bool sameCaster = Aur->GetCasterGUID() == (*i).second->GetCasterGUID();
if(IsPassiveSpell(i_spellId))
{
- if(IsPassiveStackableSpell(i_spellId))
+ // passive non-stackable spells not stackable only for same caster
+ if(!sameCaster)
continue;
// passive non-stackable spells not stackable only with another rank of same spell
@@ -4001,180 +3921,133 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
continue;
}
- uint32 i_effIndex = (*i).second->GetEffIndex();
-
bool is_triggered_by_spell = false;
// prevent triggered aura of removing aura that triggered it
for(int j = 0; j < 3; ++j)
if (i_spellProto->EffectTriggerSpell[j] == spellProto->Id)
is_triggered_by_spell = true;
- if (is_triggered_by_spell) continue;
-
- for(int j = 0; j < 3; ++j)
- {
- // prevent remove dummy triggered spells at next effect aura add
- switch(spellProto->Effect[j]) // main spell auras added added after triggered spell
- {
- case SPELL_EFFECT_DUMMY:
- switch(spellId)
- {
- case 5420: if(i_spellId==34123) is_triggered_by_spell = true; break;
- }
- break;
- }
- if(is_triggered_by_spell)
- break;
+ // check if they can stack
- // prevent remove form main spell by triggered passive spells
- switch(i_spellProto->EffectApplyAuraName[j]) // main aura added before triggered spell
- {
- case SPELL_AURA_MOD_SHAPESHIFT:
- switch(i_spellId)
+ /*// Dont remove by stack with linked auras
+ // Not needed for now
+ if(sameCaster && linked)
+ {
+ if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(spellId + SPELL_LINK_AURA))
+ for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
+ if(*itr>0 && *itr==i_spellId)
{
- case 24858: if(spellId==24905) is_triggered_by_spell = true; break;
- case 33891: if(spellId==5420 || spellId==34123) is_triggered_by_spell = true; break;
- case 34551: if(spellId==22688) is_triggered_by_spell = true; break;
+ is_triggered_by_spell=true;
+ break;
}
- break;
- }
- }
+ }*/
- if(!is_triggered_by_spell)
- {
- bool sameCaster = Aur->GetCasterGUID() == (*i).second->GetCasterGUID();
- if( spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId, sameCaster) )
- {
- //some spells should be not removed by lower rank of them (totem, paladin aura)
- if (!sameCaster
- &&(spellProto->Effect[effIndex]==SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
- &&(spellProto->DurationIndex==21)
- &&(spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
- &&(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0))
- return false;
+ if (is_triggered_by_spell)
+ continue;
- // Its a parent aura (create this aura in ApplyModifier)
- if ((*i).second->IsInUse())
- {
- sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
- continue;
- }
+ if(!spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId, sameCaster))
+ continue;
- uint64 caster = (*i).second->GetCasterGUID();
- // Remove all auras by aura caster
- for (uint8 a=0;a<3;++a)
- {
- spellEffectPair spair = spellEffectPair(i_spellId, a);
- for(AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
- {
- if(iter->second->GetCasterGUID()==caster)
- {
- RemoveAura(iter, AURA_REMOVE_BY_STACK);
- iter = m_Auras.lower_bound(spair);
- }
- else
- ++iter;
- }
- }
+ //some spells should be not removed by lower rank of them (totem, paladin aura)
+ if (!sameCaster
+ &&(Aur->IsAreaAura())
+ &&(spellProto->DurationIndex==21)
+ &&(spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
+ &&(IsHigherHankOfSpell(spellId,i_spellId)))
+ return false;
- if( m_Auras.empty() )
- break;
- else
- next = m_Auras.begin();
- }
- }
+ // Remove all auras by aura caster
+ RemoveAura(i, AURA_REMOVE_BY_STACK);
+ if(i == m_Auras.end())
+ break;
+ remove = true;
}
return true;
}
-void Unit::RemoveAura(uint32 spellId, uint32 effindex, Aura* except)
+void Unit::RemoveAura(uint32 spellId, uint64 caster ,AuraRemoveMode removeMode)
{
- spellEffectPair spair = spellEffectPair(spellId, effindex);
- for(AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
+ for(AuraMap::iterator iter = m_Auras.lower_bound(spellId); iter != m_Auras.upper_bound(spellId);)
{
- if(iter->second!=except)
+ if (!caster || iter->second->GetCasterGUID()==caster)
{
- RemoveAura(iter);
- iter = m_Auras.lower_bound(spair);
+ RemoveAura(iter, removeMode);
+ return;
}
else
++iter;
}
}
-void Unit::RemoveAurasByCasterSpell(uint32 spellId, uint64 casterGUID)
+void Unit::RemoveAura(Aura * aur ,AuraRemoveMode mode)
{
- for(int k = 0; k < 3; ++k)
+ // no need to remove
+ if (!aur || aur->IsRemoved())
+ return;
+ for(AuraMap::iterator iter = m_Auras.lower_bound(aur->GetId()); iter != m_Auras.upper_bound(aur->GetId());)
{
- spellEffectPair spair = spellEffectPair(spellId, k);
- for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
+ if (aur == iter->second)
{
- if (iter->second->GetCasterGUID() == casterGUID)
- {
- RemoveAura(iter);
- iter = m_Auras.upper_bound(spair); // overwrite by more appropriate
- }
- else
- ++iter;
+ RemoveAura(iter, mode);
+ return;
}
+ else
+ ++iter;
}
}
-void Unit::SetAurasDurationByCasterSpell(uint32 spellId, uint64 casterGUID, int32 duration)
+void Unit::RemoveAurasDueToSpell(uint32 spellId, uint64 caster ,AuraRemoveMode removeMode)
{
- for(uint8 i = 0; i < 3; ++i)
+ for(AuraMap::iterator iter = m_Auras.lower_bound(spellId); iter != m_Auras.upper_bound(spellId);)
{
- spellEffectPair spair = spellEffectPair(spellId, i);
- for(AuraMap::const_iterator itr = GetAuras().lower_bound(spair); itr != GetAuras().upper_bound(spair); ++itr)
+ if (!caster || iter->second->GetCasterGUID()==caster)
{
- if(itr->second->GetCasterGUID()==casterGUID)
- {
- itr->second->SetAuraDuration(duration);
- break;
- }
+ RemoveAura(iter, removeMode);
+ iter = m_Auras.lower_bound(spellId);
}
+ else
+ ++iter;
}
}
-Aura* Unit::GetAuraByCasterSpell(uint32 spellId, uint64 casterGUID)
+void Unit::RemoveAuraFromStack(uint32 spellId, uint64 caster ,AuraRemoveMode removeMode)
{
- // Returns first found aura from spell-use only in cases where effindex of spell doesn't matter!
- for(uint8 i = 0; i < 3; ++i)
+ for(AuraMap::iterator iter = m_Auras.lower_bound(spellId); iter != m_Auras.upper_bound(spellId);)
{
- spellEffectPair spair = spellEffectPair(spellId, i);
- for(AuraMap::const_iterator itr = GetAuras().lower_bound(spair); itr != GetAuras().upper_bound(spair); ++itr)
+ if (!caster || iter->second->GetCasterGUID()==caster)
{
- if(itr->second->GetCasterGUID()==casterGUID)
- return itr->second;
+ RemoveAuraFromStack(iter, removeMode);
+ return;
}
+ else
+ ++iter;
}
- return NULL;
+}
+
+inline void Unit::RemoveAuraFromStack(AuraMap::iterator &iter,AuraRemoveMode removeMode)
+{
+ if (iter->second->modStackAmount(-1))
+ RemoveAura(iter, removeMode);
}
void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler)
{
- for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
+ for(AuraMap::iterator iter = m_Auras.lower_bound(spellId); iter != m_Auras.upper_bound(spellId);)
{
- Aura *aur = iter->second;
- if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
+ Aura * aur= iter->second;
+ if (casterGUID == aur->GetCasterGUID())
{
- // Custom dispel case
// Unstable Affliction
- if (aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (aur->GetSpellProto()->SpellFamilyFlags & 0x010000000000LL))
+ if (aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (aur->GetSpellProto()->SpellFamilyFlags[1] & 0x0100))
{
- int32 damage = aur->GetModifier()->m_amount*9;
- uint64 caster_guid = aur->GetCasterGUID();
-
- // Remove aura
- RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
-
+ int32 damage = aur->GetPartAura(0)->GetAmount()*9;
+ RemoveAuraFromStack(iter, AURA_REMOVE_BY_ENEMY_SPELL);
// backfire damage and silence
- dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL,caster_guid);
-
- iter = m_Auras.begin(); // iterator can be invalidate at cast if self-dispel
+ dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL,GetGUID());
+ return;
}
- else
- RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
+ RemoveAuraFromStack(iter, AURA_REMOVE_BY_ENEMY_SPELL);
+ return;
}
else
++iter;
@@ -4183,134 +4056,86 @@ void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit
void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer)
{
- for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
+ if (casterGUID == stealer->GetGUID())
+ return;
+
+ for(AuraMap::iterator iter = m_Auras.lower_bound(spellId); iter != m_Auras.upper_bound(spellId);)
{
- Aura *aur = iter->second;
- if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
+ Aura * aur= iter->second;
+ if (casterGUID == aur->GetCasterGUID())
{
- int32 basePoints = aur->GetBasePoints();
- // construct the new aura for the attacker
- Aura * new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), NULL/*&basePoints*/, stealer);
- if(!new_aur)
- continue;
-
- // set its duration and maximum duration
- // max duration 2 minutes (in msecs)
- int32 dur = aur->GetAuraDuration();
- const int32 max_dur = 2*MINUTE*1000;
- new_aur->SetAuraMaxDuration( max_dur > dur ? dur : max_dur );
- new_aur->SetAuraDuration( max_dur > dur ? dur : max_dur );
+ int32 damage[3];
+ for (uint8 i=0;i<3;++i)
+ {
+ if (aur->GetPartAura(i))
+ damage[i]=aur->GetPartAura(i)->GetAmount();
+ else
+ damage[i]=NULL;
+ }
+ int32 dur = 2*MINUTE*IN_MILISECONDS < aur->GetAuraDuration() ? 2*MINUTE*IN_MILISECONDS : aur->GetAuraDuration();
+ Aura * new_aur = new Aura(aur->GetSpellProto(),aur->GetEffectMask(), NULL, stealer, stealer, NULL);
+ new_aur->SetLoadedState(aur->GetCasterGUID(), dur, dur, aur->GetAuraCharges(), aur->GetStackAmount(), &damage[0]);
// Unregister _before_ adding to stealer
aur->UnregisterSingleCastAura();
// strange but intended behaviour: Stolen single target auras won't be treated as single targeted
new_aur->SetIsSingleTarget(false);
- // add the new aura to stealer
stealer->AddAura(new_aur);
- // Remove aura as dispel
- RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
+ RemoveAuraFromStack(iter, AURA_REMOVE_BY_ENEMY_SPELL);
+ return;
}
else
++iter;
}
}
-void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId)
-{
- for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
- {
- if (iter->second->GetId() == spellId)
- RemoveAura(iter, AURA_REMOVE_BY_CANCEL);
- else
- ++iter;
- }
-}
-
-void Unit::RemoveAurasWithDispelType( DispelType type )
+void Unit::RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId)
{
- // Create dispel mask by dispel type
- uint32 dispelMask = GetDispellMask(type);
- // Dispel all existing auras vs current dispel type
- AuraMap& auras = GetAuras();
- for(AuraMap::iterator itr = auras.begin(); itr != auras.end(); )
+ for (AuraMap::iterator iter = m_Auras.lower_bound(spellId); iter != m_Auras.upper_bound(spellId);)
{
- SpellEntry const* spell = itr->second->GetSpellProto();
- if( (1<<spell->Dispel) & dispelMask )
+ if (!castItem || iter->second->GetCastItemGUID()==castItem->GetGUID())
{
- // Dispel aura
- RemoveAurasDueToSpell(spell->Id);
- itr = auras.begin();
+ RemoveAura(iter);
+ iter = m_Auras.upper_bound(spellId); // overwrite by more appropriate
}
else
- ++itr;
+ ++iter;
}
}
-void Unit::RemoveSingleAuraFromStackByDispel(uint32 spellId)
+void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura * except)
{
- for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
+ if (auraType >= TOTAL_AURAS) return;
+ for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
{
- Aura *aur = iter->second;
- if (aur->GetId() == spellId)
+ Aura * aur = (*iter)->GetParentAura();
+ ++iter;
+ if (aur != except && (!casterGUID || aur->GetCasterGUID()==casterGUID))
{
- if(iter->second->GetStackAmount() > 1)
- {
- // reapply modifier with reduced stack amount
- iter->second->ApplyModifier(false,true);
- iter->second->SetStackAmount(iter->second->GetStackAmount()-1);
- iter->second->ApplyModifier(true,true);
-
- iter->second->UpdateSlotCounterAndDuration();
- return; // not remove aura if stack amount > 1
- }
- else
- RemoveAura(iter,AURA_REMOVE_BY_DISPEL);
+ uint32 removedAuras = m_removedAurasCount;
+ RemoveAura(aur);
+ if (removedAuras+1< m_removedAurasCount)
+ iter=m_modAuras[auraType].begin();
}
- else
- ++iter;
}
}
-void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex)
+void Unit::RemoveAurasByTypeWithDispel(AuraType auraType, Spell * spell)
{
- AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
- if(iter != m_Auras.end())
- {
- if(iter->second->GetStackAmount() > 1)
- {
- // reapply modifier with reduced stack amount
- iter->second->ApplyModifier(false,true);
- iter->second->SetStackAmount(iter->second->GetStackAmount()-1);
- iter->second->ApplyModifier(true,true);
+ if (auraType >= TOTAL_AURAS) return;
+ std::queue < std::pair < uint32, uint64 > > remove_list;
- iter->second->UpdateSlotCounterAndDuration();
- return; // not remove aura if stack amount > 1
- }
- RemoveAura(iter);
+ for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();++iter)
+ {
+ if(GetDispelChance((*iter)->GetCaster(), (*iter)->GetId()))
+ {
+ remove_list.push(std::make_pair((*iter)->GetId(), (*iter)->GetCasterGUID() ) );
+ }
}
-}
-
-void Unit::RemoveAurasDueToSpell(uint32 spellId, Aura* except)
-{
- for (int i = 0; i < 3; ++i)
- RemoveAura(spellId,i,except);
-}
-void Unit::RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId)
-{
- for (int k=0; k < 3; ++k)
+ for(;remove_list.size();remove_list.pop())
{
- spellEffectPair spair = spellEffectPair(spellId, k);
- for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
- {
- if (iter->second->GetCastItemGUID() == castItem->GetGUID())
- {
- RemoveAura(iter);
- iter = m_Auras.upper_bound(spair); // overwrite by more appropriate
- }
- else
- ++iter;
- }
+ RemoveAura(remove_list.front().first, remove_list.front().second, AURA_REMOVE_BY_ENEMY_SPELL);
}
}
@@ -4327,169 +4152,70 @@ void Unit::RemoveNotOwnSingleTargetAuras()
// single target auras at other targets
AuraList& scAuras = GetSingleCastAuras();
- for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end(); )
+ for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
{
- Aura* aura = *iter;
- if (aura->GetTarget()!=this)
+ Aura * aur=*iter;
+ ++iter;
+ if (aur->GetTarget()!=this)
{
- scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveAura
- aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetEffIndex());
- iter = scAuras.begin();
+ uint32 removedAuras = m_removedAurasCount;
+ aur->GetTarget()->RemoveAura(aur->GetId(),aur->GetCasterGUID());
+ if (removedAuras+1<m_removedAurasCount)
+ iter=scAuras.begin();
}
- else
- ++iter;
}
-
}
void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
{
Aura* Aur = i->second;
- SpellEntry const* AurSpellInfo = Aur->GetSpellProto();
// some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
// remove aura from list before to prevent deleting it before
m_Auras.erase(i);
- ++m_removedAuras; // internal count used by unit update
+ m_removedAurasCount += 1;
- Unit* caster = NULL;
Aur->UnregisterSingleCastAura();
- // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
- if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
+ if(Aur->GetSpellProto()->AuraInterruptFlags)
{
- m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur);
-
- if(Aur->GetSpellProto()->AuraInterruptFlags)
- {
- m_interruptableAuras.remove(Aur);
- UpdateInterruptMask();
- }
-
- if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE)
- && (Aur->GetModifier()->m_auraname != SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
- {
- m_ccAuras.remove(Aur);
- }
+ m_interruptableAuras.remove(Aur);
+ UpdateInterruptMask();
}
- // Set remove mode
- Aur->SetRemoveMode(mode);
-
- // Statue unsummoned at aura remove
- Totem* statue = NULL;
- bool channeled = false;
- if(Aur->GetAuraDuration() && !Aur->IsPersistent() && IsChanneledSpell(AurSpellInfo))
+ if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE
+ && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
+ || ((GetAllSpellMechanicMask(Aur->GetSpellProto()) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN)))
{
- if(!caster) // can be already located for IsSingleTargetSpell case
- caster = Aur->GetCaster();
-
- if(caster && caster->isAlive())
- {
- // stop caster chanelling state
- if(caster->m_currentSpells[CURRENT_CHANNELED_SPELL]
- //prevent recurential call
- && caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED)
- {
- if (caster==this || !IsAreaOfEffectSpell(AurSpellInfo))
- {
- // remove auras only for non-aoe spells or when chanelled aura is removed
- // because aoe spells don't require aura on target to continue
- if (AurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()]!=SPELL_AURA_PERIODIC_DUMMY
- && AurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()]!= SPELL_AURA_DUMMY)
- //don't stop channeling of scripted spells (this is actually a hack)
- {
- caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel();
- caster->m_currentSpells[CURRENT_CHANNELED_SPELL]=NULL;
-
- }
- }
-
- if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE)
- statue = ((Totem*)caster);
- }
-
- // Unsummon summon as possessed creatures on spell cancel
- if(caster->GetTypeId() == TYPEID_PLAYER)
- {
- for(int i = 0; i < 3; ++i)
- {
- if(AurSpellInfo->Effect[i] == SPELL_EFFECT_SUMMON &&
- (AurSpellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED ||
- AurSpellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED2 ||
- AurSpellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED3))
- {
- ((Player*)caster)->StopCastingCharm();
- break;
- }
- }
- }
- }
+ m_ccAuras.remove(Aur);
}
- sLog.outDebug("Aura %u (%u) now is remove mode %d", Aur->GetId(), Aur->GetModifier()->m_auraname, mode);
- assert(!Aur->IsInUse());
- Aur->ApplyModifier(false,true);
+ Aur->SetRemoveMode(mode);
+
+ sLog.outDebug("Aura %u now is remove mode %d", Aur->GetId(), mode);
+ Aur->HandleEffects(false);
- Aur->SetStackAmount(0);
+ // set aura to be removed during unit::_updatespells
+ m_removedAuras.push_back(Aur);
Aur->_RemoveAura();
- bool stack = false;
- spellEffectPair spair = spellEffectPair(Aur->GetId(), Aur->GetEffIndex());
- for(AuraMap::const_iterator itr = GetAuras().lower_bound(spair); itr != GetAuras().upper_bound(spair); ++itr)
+ // Remove totem at next update if totem looses its aura
+ if (GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem()&& ((TempSummon*)this)->GetSummonerGUID()==Aur->GetCasterGUID())
{
- if (itr->second->GetCasterGUID()==GetGUID())
- {
- stack = true;
- }
+ if (((Totem*)this)->GetSpell()==Aur->GetId() && ((Totem*)this)->GetTotemType()==TOTEM_PASSIVE)
+ ((Totem*)this)->setDeathState(JUST_DIED);
}
- if (!stack)
- {
- // Remove all triggered by aura spells vs unlimited duration
- Aur->CleanupTriggeredSpells();
-
- // Remove Linked Auras
- uint32 id = Aur->GetId();
- if(spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_REMOVE)
- {
- if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(-(int32)id))
- for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
- if(*itr < 0)
- RemoveAurasDueToSpell(-(*itr));
- else if(Unit* caster = Aur->GetCaster())
- CastSpell(this, *itr, true, 0, 0, caster->GetGUID());
- }
- if(spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_AURA)
- {
- if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(id + SPELL_LINK_AURA))
- for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
- if(*itr < 0)
- ApplySpellImmune(id, IMMUNITY_ID, -(*itr), false);
- else
- RemoveAurasDueToSpell(*itr);
- }
- }
-
- delete Aur;
-
- if(statue)
- statue->UnSummon();
// only way correctly remove all auras from list
- if( m_Auras.empty() )
- i = m_Auras.end();
- else
- i = m_Auras.begin();
+ i = m_Auras.begin();
}
void Unit::RemoveAllAuras()
{
+ AuraMap::iterator iter = m_Auras.begin();
while (!m_Auras.empty())
- {
- AuraMap::iterator iter = m_Auras.begin();
RemoveAura(iter);
- }
}
void Unit::RemoveArenaAuras(bool onleave)
@@ -4521,17 +4247,17 @@ void Unit::RemoveAllAurasOnDeath()
}
}
-void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime)
+void Unit::DelayAura(uint32 spellId, uint64 caster, int32 delaytime)
{
- AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
- if (iter != m_Auras.end())
+ if (Aura * aur = GetAura(spellId, caster))
{
- if (iter->second->GetAuraDuration() < delaytime)
- iter->second->SetAuraDuration(0);
+ if (aur->GetAuraDuration() < delaytime)
+ aur->SetAuraDuration(0);
else
- iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime);
- iter->second->UpdateAuraDuration();
- sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration());
+ aur->SetAuraDuration(aur->GetAuraDuration() - delaytime);
+ // update for out of range group members (on 1 slot use)
+ UpdateAuraForGroup(aur->GetAuraSlot());
+ sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",aur->GetId(), GetGUIDLow(), aur->GetAuraDuration());
}
}
@@ -4539,7 +4265,7 @@ void Unit::_RemoveAllAuraMods()
{
for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
{
- (*i).second->ApplyModifier(false);
+ (*i).second->ApplyAllModifiers(false);
}
}
@@ -4547,15 +4273,94 @@ void Unit::_ApplyAllAuraMods()
{
for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
{
- (*i).second->ApplyModifier(true);
+ (*i).second->ApplyAllModifiers(true);
+ }
+}
+
+bool Unit::HasAuraTypeWithMiscvalue(AuraType auratype, uint32 miscvalue) const
+{
+ AuraEffectList const& mTotalAuraList = GetAurasByType(auratype);
+ for(AuraEffectList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
+ if (miscvalue == (*i)->GetMiscValue())
+ return true;
+ return false;
+}
+
+bool Unit::HasAuraType(AuraType auraType) const
+{
+ return (!m_modAuras[auraType].empty());
+}
+
+bool Unit::HasAura(uint32 spellId, uint64 caster) const
+{
+ //Special case for non existing spell
+ if (spellId==61988)
+ return HasAura(61987, caster) || HasAura(25771, caster);
+
+ if (Aura * aur = GetAura(spellId, caster))
+ return true;
+ return false;
+}
+
+bool Unit::HasAura(Aura * aur) const
+{
+ // no need to find aura
+ if (!aur || aur->IsRemoved())
+ return false;
+ for(AuraMap::const_iterator iter = m_Auras.lower_bound(aur->GetId()); iter != m_Auras.upper_bound(aur->GetId());)
+ {
+ if (aur == iter->second)
+ return true;
+ else
+ ++iter;
}
+ return false;
}
-Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
+bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const
{
- AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
- if (iter != m_Auras.end())
- return iter->second;
+ if (Aura * aur = GetAura(spellId, caster))
+ return aur->HasEffect(effIndex);
+ return false;
+}
+
+Aura * Unit::GetAura(uint32 spellId, uint64 caster) const
+{
+ if (!caster)
+ {
+ AuraMap::const_iterator itr = m_Auras.find(spellId);
+ return itr != m_Auras.end() ? itr->second : NULL;
+ }
+ else
+ {
+ AuraMap const& auras = GetAuras();
+ for(AuraMap::const_iterator itr = auras.lower_bound(spellId); itr != auras.upper_bound(spellId); ++itr)
+ if(itr->second->GetCasterGUID()==caster)
+ return itr->second;
+ return NULL;
+ }
+}
+
+AuraEffect * Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const
+{
+ if (Aura * aur = GetAura(spellId, caster))
+ return aur->GetPartAura(effIndex);
+ return false;
+}
+
+AuraEffect* Unit::GetAura(AuraType type, uint32 family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID)
+{
+ AuraEffectList const& auras = GetAurasByType(type);
+ for(AuraEffectList::const_iterator i = auras.begin();i != auras.end(); ++i)
+ {
+ SpellEntry const *spell = (*i)->GetSpellProto();
+ if (spell->SpellFamilyName == family && spell->SpellFamilyFlags.HasFlag(familyFlag1, familyFlag2, familyFlag3))
+ {
+ if (casterGUID && (*i)->GetCasterGUID()!=casterGUID)
+ continue;
+ return (*i);
+ }
+ }
return NULL;
}
@@ -4570,7 +4375,7 @@ void Unit::RemoveDynObject(uint32 spellid)
return;
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
{
- DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this, *i);
+ DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
if(!dynObj) // may happen if a dynobj is removed when grid unload
{
i = m_dynObjGUIDs.erase(i);
@@ -4589,7 +4394,7 @@ void Unit::RemoveAllDynObjects()
{
while(!m_dynObjGUIDs.empty())
{
- DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin());
+ DynamicObject* dynObj = GetMap()->GetDynamicObject(*m_dynObjGUIDs.begin());
if(dynObj)
dynObj->Delete();
m_dynObjGUIDs.erase(m_dynObjGUIDs.begin());
@@ -4600,7 +4405,7 @@ DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex)
{
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
{
- DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this, *i);
+ DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
if(!dynObj)
{
i = m_dynObjGUIDs.erase(i);
@@ -4618,7 +4423,7 @@ DynamicObject * Unit::GetDynObject(uint32 spellId)
{
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
{
- DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this, *i);
+ DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
if(!dynObj)
{
i = m_dynObjGUIDs.erase(i);
@@ -4632,27 +4437,54 @@ DynamicObject * Unit::GetDynObject(uint32 spellId)
return NULL;
}
+GameObject* Unit::GetGameObject(uint32 spellId) const
+{
+ for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
+ if ((*i)->GetSpellId() == spellId)
+ return *i;
+
+ return NULL;
+}
+
void Unit::AddGameObject(GameObject* gameObj)
{
assert(gameObj && gameObj->GetOwnerGUID()==0);
m_gameObj.push_back(gameObj);
gameObj->SetOwnerGUID(GetGUID());
+
+ if ( GetTypeId()==TYPEID_PLAYER && gameObj->GetSpellId() )
+ {
+ SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId());
+ // Need disable spell use for owner
+ if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
+ ((Player*)this)->AddSpellAndCategoryCooldowns(createBySpell,0,NULL,true);
+ }
}
void Unit::RemoveGameObject(GameObject* gameObj, bool del)
{
assert(gameObj && gameObj->GetOwnerGUID()==GetGUID());
+ gameObj->SetOwnerGUID(0);
+
// GO created by some spell
- if ( GetTypeId()==TYPEID_PLAYER && gameObj->GetSpellId() )
+ if (uint32 spellid = gameObj->GetSpellId())
{
- SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId());
- // Need activate spell use for owner
- if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
- ((Player*)this)->SendCooldownEvent(createBySpell);
+ RemoveAurasDueToSpell(spellid);
+
+ if (GetTypeId()==TYPEID_PLAYER)
+ {
+ SpellEntry const* createBySpell = sSpellStore.LookupEntry(spellid );
+ // Need activate spell use for owner
+ if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
+ ((Player*)this)->SendCooldownEvent(createBySpell);
+ }
}
- gameObj->SetOwnerGUID(0);
+
m_gameObj.remove(gameObj);
+
if(del)
{
gameObj->SetRespawnTime(0);
@@ -4664,7 +4496,7 @@ void Unit::RemoveGameObject(uint32 spellid, bool del)
{
if(m_gameObj.empty())
return;
- std::list<GameObject*>::iterator i, next;
+ GameObjectList::iterator i, next;
for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
{
next = i;
@@ -4687,7 +4519,7 @@ void Unit::RemoveGameObject(uint32 spellid, bool del)
void Unit::RemoveAllGameObjects()
{
// remove references to unit
- for(std::list<GameObject*>::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
+ for(GameObjectList::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
{
(*i)->SetOwnerGUID(0);
(*i)->SetRespawnTime(0);
@@ -4702,46 +4534,43 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log)
data.append(log->target->GetPackGUID());
data.append(log->attacker->GetPackGUID());
data << uint32(log->SpellID);
- data << uint32(log->damage); //damage amount
- data << uint8 (log->schoolMask); //damage school
- data << uint32(log->absorb); //AbsorbedDamage
- data << uint32(log->resist); //resist
- data << uint8 (log->phusicalLog); // damsge type? flag
- data << uint8 (log->unused); //unused
- data << uint32(log->blocked); //blocked
+ data << uint32(log->damage); // damage amount
+ data << uint32(int32 (log->target->GetHealth()-log->damage ) >0 ? 0 : log->damage - log->target->GetHealth());
+ //data << uint32(log->overkill); // overkill
+ data << uint8 (log->schoolMask); // damage school
+ data << uint32(log->absorb); // AbsorbedDamage
+ data << uint32(log->resist); // resist
+ data << uint8 (log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
+ data << uint8 (log->unused); // unused
+ data << uint32(log->blocked); // blocked
data << uint32(log->HitInfo);
- data << uint8 (0); // flag to use extend data
+ data << uint8 (0); // flag to use extend data
SendMessageToSet( &data, true );
}
void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
{
- sLog.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
- WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
- data.append(target->GetPackGUID());
- data.append(GetPackGUID());
- data << uint32(SpellID);
- data << uint32(Damage-AbsorbedDamage-Resist-Blocked);
- data << uint8(damageSchoolMask); // spell school
- data << uint32(AbsorbedDamage); // AbsorbedDamage
- data << uint32(Resist); // resist
- data << uint8(PhysicalDamage); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
- data << uint8(0); // unk isFromAura
- data << uint32(Blocked); // blocked
- data << uint32(CriticalHit ? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
- data << uint8(0); // isDebug?
- SendMessageToSet( &data, true );
+ SpellNonMeleeDamage log(this,target,SpellID,damageSchoolMask);
+ log.damage = Damage-AbsorbedDamage-Resist-Blocked;
+ log.absorb = AbsorbedDamage;
+ log.resist = Resist;
+ log.physicalLog = PhysicalDamage;
+ log.blocked = Blocked;
+ log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6;
+ if(CriticalHit)
+ log.HitInfo |= SPELL_HIT_TYPE_CRIT;
+ SendSpellNonMeleeDamageLog(&log);
}
-void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const *procSpell)
+void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const *procSpell, SpellEntry const * procAura)
{
// Not much to do if no flags are set.
if (procAttacker)
- ProcDamageAndSpellFor(false,pVictim,procAttacker, procExtra,attType, procSpell, amount);
+ ProcDamageAndSpellFor(false,pVictim,procAttacker, procExtra,attType, procSpell, amount, procAura);
// Now go on with a victim's events'n'auras
// Not much to do if no flags are set or there is no victim
if(pVictim && pVictim->isAlive() && procVictim)
- pVictim->ProcDamageAndSpellFor(true,this,procVictim, procExtra, attType, procSpell, amount);
+ pVictim->ProcDamageAndSpellFor(true,this,procVictim, procExtra, attType, procSpell, amount, procAura);
}
void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
@@ -4760,25 +4589,65 @@ void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo)
{
- WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+84)); // we guess size
+ uint32 count = 1;
+ WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size
data << (uint32)damageInfo->HitInfo;
data.append(GetPackGUID());
data.append(damageInfo->target->GetPackGUID());
data << (uint32)(damageInfo->damage); // Full damage
+ data << uint32(int32 (damageInfo->target->GetHealth()-damageInfo->damage ) >0 ? 0 : damageInfo->damage - damageInfo->target->GetHealth()); // Overkill
+
+ data << (uint8)count; // Sub damage count
+
+ for(int i = 0; i < count; ++i)
+ {
+ data << (uint32)(damageInfo->damageSchoolMask); // School of sub damage
+ data << (float)damageInfo->damage; // sub damage
+ data << (uint32)damageInfo->damage; // Sub Damage
+ }
- data << (uint8)1; // Sub damage count
- //=== Sub damage description
- data << (uint32)(damageInfo->damageSchoolMask); // School of sub damage
- data << (float)damageInfo->damage; // sub damage
- data << (uint32)damageInfo->damage; // Sub Damage
- data << (uint32)damageInfo->absorb; // Absorb
- data << (uint32)damageInfo->resist; // Resist
- //=================================================
- data << (uint32)damageInfo->TargetState;
+ if(damageInfo->HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2))
+ {
+ for(int i = 0; i < count; ++i)
+ data << (uint32)damageInfo->absorb; // Absorb
+ }
+
+ if(damageInfo->HitInfo & (HITINFO_RESIST | HITINFO_RESIST2))
+ {
+ for(int i = 0; i < count; ++i)
+ data << (uint32)damageInfo->resist; // Resist
+ }
+
+ data << (uint8)damageInfo->TargetState;
data << (uint32)0;
data << (uint32)0;
- data << (uint32)damageInfo->blocked_amount;
- SendMessageToSet( &data, true );/**/
+
+ if(damageInfo->HitInfo & HITINFO_BLOCK)
+ data << (uint32)damageInfo->blocked_amount;
+
+ if(damageInfo->HitInfo & HITINFO_UNK3)
+ data << uint32(0);
+
+ if(damageInfo->HitInfo & HITINFO_UNK1)
+ {
+ data << uint32(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ for(uint8 i = 0; i < 5; ++i)
+ {
+ data << float(0);
+ data << float(0);
+ }
+ data << uint32(0);
+ }
+
+ SendMessageToSet( &data, true );
}
void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
@@ -4786,176 +4655,77 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType,
sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size
- data << (uint32)HitInfo;
+ data << uint32(HitInfo); // flags
data.append(GetPackGUID());
data.append(target->GetPackGUID());
- data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
+ int32 damageDone = Damage-AbsorbDamage-Resist-BlockedAmount;
+ data << uint32(damageDone);// damage
+ data << uint32(int32 (target->GetHealth()-damageDone ) >0 ? 0 : damageDone - target->GetHealth()); // Overkill
data << (uint8)SwingType; // count?
// for(i = 0; i < SwingType; ++i)
data << (uint32)damageSchoolMask;
- data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount);
- // still need to double check damage
- data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount);
- data << (uint32)AbsorbDamage;
- data << (uint32)Resist;
+ data << (float)(damageDone);
+ data << (uint32)(damageDone);
// end loop
- data << (uint32)TargetState;
-
- if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens
- data << (uint32)0;
- else
- data << (uint32)-1;
-
- data << (uint32)0;
- data << (uint32)BlockedAmount;
-
- SendMessageToSet( &data, true );
-}
-/*
-void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
-{
- sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim);
- if(procSpell)
- sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":""));
-
- // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
- // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect
- // That is the question though if it's fully correct
- if(procSpell && !isTriggeredSpell)
+ if(HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2))
{
- if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE)
- {
- if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE;
- if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE;
- if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE;
- if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE;
- attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon
- }
- else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
- {
- if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED;
- if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED;
- if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED;
- if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED;
- attType = RANGED_ATTACK;
- }
+ // for(i = 0; i < SwingType; ++i)
+ data << uint32(AbsorbDamage);
+ // end loop
}
- if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL)))
- procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH);
- // Not much to do if no flags are set.
- if (procAttacker)
+ if(HitInfo & (HITINFO_RESIST | HITINFO_RESIST2))
{
- // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
- ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcEffectAuraTypes,attType, procSpell, damage, damageSchoolMask);
- ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcCastAuraTypes,attType, procSpell, damage, damageSchoolMask);
+ // for(i = 0; i < SwingType; ++i)
+ data << uint32(Resist);
+ // end loop
}
- // Now go on with a victim's events'n'auras
- // Not much to do if no flags are set or there is no victim
- if(pVictim && pVictim->isAlive() && procVictim)
+ data << (uint8)TargetState;
+ data << (uint32)0;
+ data << (uint32)0;
+
+ if(HitInfo & HITINFO_BLOCK)
{
- // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
- pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcEffectAuraTypes,attType,procSpell, damage, damageSchoolMask);
- pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcCastAuraTypes,attType,procSpell, damage, damageSchoolMask);
+ data << uint32(BlockedAmount);
}
-}
-
-void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell)
-{
- if(!pVictim)
- return;
- uint32 procAttacker = PROC_FLAG_NONE;
- uint32 procVictim = PROC_FLAG_NONE;
-
- switch(outcome)
+ if(HitInfo & HITINFO_UNK3)
{
- case MELEE_HIT_EVADE:
- return;
- case MELEE_HIT_MISS:
- if(attType == BASE_ATTACK || attType == OFF_ATTACK)
- {
- procAttacker = PROC_FLAG_MISS;
- }
- break;
- case MELEE_HIT_BLOCK_CRIT:
- case MELEE_HIT_CRIT:
- if(spellCasted && attType == BASE_ATTACK)
- {
- procAttacker |= PROC_FLAG_CRIT_SPELL;
- procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL;
- if ( outcome == MELEE_HIT_BLOCK_CRIT )
- {
- procVictim |= PROC_FLAG_BLOCK;
- procAttacker |= PROC_FLAG_TARGET_BLOCK;
- }
- }
- else if(attType == BASE_ATTACK || attType == OFF_ATTACK)
- {
- procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
- procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
- }
- else
- {
- procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
- procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
- }
- break;
- case MELEE_HIT_PARRY:
- procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
- procVictim = PROC_FLAG_PARRY;
- break;
- case MELEE_HIT_BLOCK:
- procAttacker = PROC_FLAG_TARGET_BLOCK;
- procVictim = PROC_FLAG_BLOCK;
- break;
- case MELEE_HIT_DODGE:
- procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY;
- procVictim = PROC_FLAG_DODGE;
- break;
- case MELEE_HIT_CRUSHING:
- if(attType == BASE_ATTACK || attType == OFF_ATTACK)
- {
- procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE;
- procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE;
- }
- else
- {
- procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED;
- procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED;
- }
- break;
- default:
- if(attType == BASE_ATTACK || attType == OFF_ATTACK)
- {
- procAttacker = PROC_FLAG_HIT_MELEE;
- procVictim = PROC_FLAG_STRUCK_MELEE;
- }
- else
- {
- procAttacker = PROC_FLAG_HIT_RANGED;
- procVictim = PROC_FLAG_STRUCK_RANGED;
- }
- break;
+ data << uint32(0);
}
- if(damage > 0)
- procVictim |= PROC_FLAG_TAKE_DAMAGE;
+ if(HitInfo & HITINFO_UNK1)
+ {
+ data << uint32(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ data << float(0);
+ for(uint8 i = 0; i < 5; ++i)
+ {
+ data << float(0);
+ data << float(0);
+ }
+ data << uint32(0);
+ }
- if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE)
- ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType);
-}*/
+ SendMessageToSet( &data, true );
+}
-bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
+bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
{
SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto();
- Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
- ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
+ Item* castItem = triggeredByAura->GetParentAura()->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
+ ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetParentAura()->GetCastItemGUID()) : NULL;
uint32 triggered_spell_id = 0;
Unit* target = pVictim;
@@ -5013,34 +4783,59 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return true;
}
-bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
+bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
- uint32 effIndex = triggeredByAura->GetEffIndex ();
+ uint32 effIndex = triggeredByAura->GetEffIndex();
+ int32 triggerAmount = triggeredByAura->GetAmount();
- Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
- ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
+ Item* castItem = triggeredByAura->GetParentAura()->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
+ ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetParentAura()->GetCastItemGUID()) : NULL;
uint32 triggered_spell_id = 0;
Unit* target = pVictim;
int32 basepoints0 = 0;
+ // Master of subtlety (checked here because ranks have different spellfamilynames)
+ if (dummySpell->Id == 31223 || dummySpell->Id == 31221 || dummySpell->Id == 31222)
+ {
+ if (procEx & AURA_REMOVE_PROC_EX_MASK)
+ triggered_spell_id = 31666;
+ else
+ {
+ triggered_spell_id = 31665;
+ basepoints0 = triggerAmount;
+ }
+ }
switch(dummySpell->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
switch (dummySpell->Id)
{
- // Eye of Eye
+ // Improved Divine Spirit
+ case 33174:
+ case 33182:
+ {
+ // Tricky thing here, we find current aura from spell by caster and change its modifier value
+ int32 spelldmg = CalculateSpellDamage(procSpell, 0, procSpell->EffectBasePoints[0],pVictim);
+ if (AuraEffect * Aur = pVictim->GetAuraEffect(procSpell->Id, effIndex+1, triggeredByAura->GetCasterGUID()))
+ {
+ // Remove aura mods
+ Aur->ApplyModifier(false);
+ Aur->SetAmount(Aur->GetAmount() + spelldmg/* * triggerAmount / 100*/);
+ // Apply extended aura mods
+ Aur->ApplyModifier(true);
+ return true;
+ }
+ return false;
+ }
+ // Eye for an Eye
case 9799:
case 25988:
{
- // prevent damage back from weapon special attacks
- if (!procSpell || procSpell->DmgClass != SPELL_DAMAGE_CLASS_MAGIC )
- return false;
-
// return damage % to attacker but < 50% own total health
- basepoints0 = triggeredByAura->GetModifier()->m_amount*int32(damage)/100;
+ basepoints0 = triggerAmount*int32(damage)/100;
if(basepoints0 > GetMaxHealth()/2)
basepoints0 = GetMaxHealth()/2;
@@ -5069,15 +4864,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
if (!procSpell || procSpell->Id == 24659)
return false;
// Need remove one 24659 aura
- RemoveSingleAuraFromStack(24659, 0);
- RemoveSingleAuraFromStack(24659, 1);
+ RemoveAuraFromStack(24659);
return true;
}
// Restless Strength
case 24661:
{
// Need remove one 24662 aura
- RemoveSingleAuraFromStack(24662, 0);
+ RemoveAuraFromStack(24662);
return true;
}
// Adaptive Warding (Frostfire Regalia set)
@@ -5088,12 +4882,12 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
// find Mage Armor
bool found = false;
- AuraList const& mRegenInterupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
- for(AuraList::const_iterator iter = mRegenInterupt.begin(); iter != mRegenInterupt.end(); ++iter)
+ AuraEffectList const& mRegenInterupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
+ for(AuraEffectList::const_iterator iter = mRegenInterupt.begin(); iter != mRegenInterupt.end(); ++iter)
{
if(SpellEntry const* iterSpellProto = (*iter)->GetSpellProto())
{
- if(iterSpellProto->SpellFamilyName==SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags & 0x10000000))
+ if(iterSpellProto->SpellFamilyName==SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags[0] & 0x10000000))
{
found=true;
break;
@@ -5151,15 +4945,26 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
if(!target)
return false;
- basepoints0 = int32(damage * 2.5f); // manaregen
triggered_spell_id = 34650;
break;
}
+ // Overkill
+ case 58426:
+ {
+ if (procEx & AURA_REMOVE_PROC_EX_MASK)
+ triggered_spell_id = 58428;
+ else
+ {
+ basepoints0 = -triggerAmount;
+ triggered_spell_id = 58427;
+ }
+ break;
+ }
// Mark of Malice
case 33493:
{
// Cast finish spell at last charge
- if (triggeredByAura->m_procCharges > 1)
+ if (triggeredByAura->GetParentAura()->GetAuraCharges() > 1)
return false;
target = this;
@@ -5265,7 +5070,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
break;
}
return false;
- }/**/
+ }*/
// Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
// cast 45479 Light's Wrath if Exalted by Aldor
// cast 45429 Arcane Bolt if Exalted by Scryers
@@ -5362,6 +5167,57 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
}
return false;
}
+ // Living Seed
+ case 48504:
+ {
+ triggered_spell_id = 48503;
+ basepoints0 = triggerAmount;
+ target = this;
+ break;
+ }
+ // Kill command
+ case 58914:
+ {
+ // Remove aura stack from pet
+ RemoveAuraFromStack(58914);
+ Unit* owner = GetOwner();
+ if(!owner)
+ return true;
+ // reduce the owner's aura stack
+ owner->RemoveAuraFromStack(34027);
+ return true;
+ }
+ // Vampiric Touch (generic, used by some boss)
+ case 52723:
+ case 60501:
+ {
+ triggered_spell_id = 52724;
+ basepoints0 = damage / 2;
+ target = this;
+ break;
+ }
+ // Divine purpose
+ case 31871:
+ case 31872:
+ {
+ // Roll chane
+ if (!roll_chance_i(triggerAmount))
+ return false;
+
+ // Remove any stun effect on target
+ AuraMap& Auras = pVictim->GetAuras();
+ for(AuraMap::iterator iter = Auras.begin(); iter != Auras.end();)
+ {
+ SpellEntry const *spell = iter->second->GetSpellProto();
+ if( GetAllSpellMechanicMask(spell) & 1<<(MECHANIC_STUN))
+ {
+ pVictim->RemoveAura(iter);
+ }
+ else
+ ++iter;
+ }
+ return true;
+ }
}
break;
}
@@ -5374,7 +5230,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return false;
// mana reward
- basepoints0 = (triggeredByAura->GetModifier()->m_amount * GetMaxPower(POWER_MANA) / 100);
+ basepoints0 = (triggerAmount * GetMaxPower(POWER_MANA) / 100);
target = this;
triggered_spell_id = 29442;
break;
@@ -5386,7 +5242,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return false;
// mana cost save
- basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100;
+ int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
+ basepoints0 = cost * triggerAmount/100;
if( basepoints0 <=0 )
return false;
@@ -5394,8 +5251,72 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 29077;
break;
}
+ // Shattered Barrier
+ if (dummySpell->SpellIconID == 2945)
+ {
+ // only on dispel/remove aura by destroy
+ target = NULL;
+ triggered_spell_id = 55080;
+ CastSpell(target, triggered_spell_id, true, 0, triggeredByAura);
+ return true;
+ }
+
+ //Arcane Potency
+ if (dummySpell->SpellIconID == 2120)
+ {
+ if(!procSpell)
+ return false;
+
+ target = this;
+ switch (dummySpell->Id)
+ {
+ case 31571: triggered_spell_id = 57529; break;
+ case 31572: triggered_spell_id = 57531; break;
+ default:
+ sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u",dummySpell->Id);
+ return false;
+ }
+ break;
+ }
+
+ // Hot Streak
+ if (dummySpell->SpellIconID == 2999)
+ {
+ if (effIndex!=0)
+ return false;
+ AuraEffect *counter = triggeredByAura->GetParentAura()->GetPartAura(1);
+ if (!counter)
+ return true;
+
+ // Count spell criticals in a row in second aura
+ if (procEx & PROC_EX_CRITICAL_HIT)
+ {
+ counter->SetAmount(counter->GetAmount()*2);
+ if (counter->GetAmount() < 100) // not enough
+ return true;
+ // Crititcal counted -> roll chance
+ if (roll_chance_i(triggerAmount))
+ CastSpell(this, 48108, true, castItem, triggeredByAura);
+ }
+ counter->SetAmount(25);
+ return true;
+ }
+ // Burnout
+ if (dummySpell->SpellIconID == 2998)
+ {
+ if(!procSpell)
+ return false;
+
+ int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
+ basepoints0 = cost * triggerAmount/100;
+ if( basepoints0 <=0 )
+ return false;
+ triggered_spell_id = 44450;
+ target = this;
+ break;
+ }
// Incanter's Regalia set (add trigger chance to Mana Shield)
- if (dummySpell->SpellFamilyFlags & 0x0000000000008000LL)
+ if (dummySpell->SpellFamilyFlags[0] & 0x8000)
{
if(GetTypeId() != TYPEID_PLAYER)
return false;
@@ -5432,7 +5353,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
case 11129:
{
//last charge and crit
- if (triggeredByAura->m_procCharges <= 1 && (procEx & PROC_EX_CRITICAL_HIT) )
+ if (triggeredByAura->GetParentAura()->GetAuraCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT) )
{
RemoveAurasDueToSpell(28682); //-> remove Combustion auras
return true; // charge counting (will removed)
@@ -5441,13 +5362,32 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
CastSpell(this, 28682, true, castItem, triggeredByAura);
return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns
}
+ // Glyph of Ice Block
+ case 56372:
+ {
+ if(GetTypeId() != TYPEID_PLAYER)
+ return false;
+
+ SpellCooldowns SpellCDs = ((Player*)this)->GetSpellCooldowns();
+ // remove cooldowns on all ranks of Frost Nova
+ for(SpellCooldowns::const_iterator itr = SpellCDs.begin(); itr != SpellCDs.end(); itr++)
+ {
+ SpellEntry const* SpellCDs_entry = sSpellStore.LookupEntry(itr->first);
+ // Frost Nova
+ if(SpellCDs_entry && SpellCDs_entry->SpellFamilyName == SPELLFAMILY_MAGE && SpellCDs_entry->SpellFamilyFlags[0] & 0x00000040)
+ {
+ ((Player*)this)->RemoveSpellCooldown(SpellCDs_entry->Id, true);
+ }
+ }
+ break;
+ }
}
break;
}
case SPELLFAMILY_WARRIOR:
{
// Retaliation
- if(dummySpell->SpellFamilyFlags==0x0000000800000000LL)
+ if(dummySpell->SpellFamilyFlags.IsEqual(0, 0x8, 0))
{
// check attack comes not from behind
if (!HasInArc(M_PI, pVictim))
@@ -5456,26 +5396,51 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 22858;
break;
}
- else if (dummySpell->SpellIconID == 1697) // Second Wind
+ // Glyph of Devastate
+ if(dummySpell->Id==58388)
+ {
+ // get highest rank of the Sunder Armor spell
+ if (GetTypeId()!=TYPEID_PLAYER)
+ return false;
+ const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap();
+ for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ {
+ // only highest rank is shown in spell book, so simply check if shown in spell book
+ if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
+ continue;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
+ if (!spellInfo)
+ continue;
+
+ if (spellInfo->SpellFamilyFlags.IsEqual(SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR)
+ && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR)
+ {
+ triggered_spell_id = spellInfo->Id;
+ break;
+ }
+ }
+ if (!triggered_spell_id)
+ return false;
+ for (int32 value = CalculateSpellDamage(dummySpell, 0 , dummySpell->EffectBasePoints[0], pVictim);value>0;value--)
+ CastSpell(target,triggered_spell_id,true);
+ return true;
+ }
+ // Second Wind
+ if (dummySpell->SpellIconID == 1697)
{
// only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example)
if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim)
return false;
// Need stun or root mechanic
- if (procSpell->Mechanic != MECHANIC_ROOT && procSpell->Mechanic != MECHANIC_STUN)
- {
- int32 i;
- for (i=0; i<3; i++)
- if (procSpell->EffectMechanic[i] == MECHANIC_ROOT || procSpell->EffectMechanic[i] == MECHANIC_STUN)
- break;
- if (i == 3)
- return false;
- }
+ if (!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_STUN))))
+ return false;
switch (dummySpell->Id)
{
case 29838: triggered_spell_id=29842; break;
case 29834: triggered_spell_id=29841; break;
+ case 42770: triggered_spell_id=42771; break;
default:
sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)",dummySpell->Id);
return false;
@@ -5484,16 +5449,23 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
target = this;
break;
}
+ // Damage Shield
+ if (dummySpell->SpellIconID == 3214)
+ {
+ triggered_spell_id = 59653;
+ // % of amount blocked
+ basepoints0 = GetShieldBlockValue() * triggerAmount / 100;
+ break;
+ }
break;
}
case SPELLFAMILY_WARLOCK:
{
// Seed of Corruption
- if (dummySpell->SpellFamilyFlags & 0x0000001000000000LL)
+ if (dummySpell->SpellFamilyFlags[1] & 0x00000010)
{
- Modifier* mod = triggeredByAura->GetModifier();
// if damage is more than need or target die from damage deal finish spell
- if( mod->m_amount <= damage || GetHealth() <= damage )
+ if( triggeredByAura->GetAmount() <= damage || GetHealth() <= damage )
{
// remember guid before aura delete
uint64 casterGuid = triggeredByAura->GetCasterGUID();
@@ -5508,15 +5480,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
}
// Damage counting
- mod->m_amount-=damage;
+ triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
return true;
}
// Seed of Corruption (Mobs cast) - no die req
- if (dummySpell->SpellFamilyFlags == 0x00LL && dummySpell->SpellIconID == 1932)
+ if (dummySpell->SpellFamilyFlags.IsEqual(0,0,0) && dummySpell->SpellIconID == 1932)
{
- Modifier* mod = triggeredByAura->GetModifier();
// if damage is more than need deal finish spell
- if( mod->m_amount <= damage )
+ if( triggeredByAura->GetAmount() <= damage )
{
// remember guid before aura delete
uint64 casterGuid = triggeredByAura->GetCasterGUID();
@@ -5530,14 +5501,26 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return true; // no hidden cooldown
}
// Damage counting
- mod->m_amount-=damage;
+ triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
return true;
}
+ // Fel Synergy
+ if (dummySpell->SpellIconID == 3222)
+ {
+ target = GetGuardianPet();
+ if (!target)
+ return false;
+ triggered_spell_id = 54181;
+ basepoints0 = damage * 15 / 100;
+ break;
+ }
switch(dummySpell->Id)
{
// Nightfall
case 18094:
case 18095:
+ // Glyph of corruption
+ case 56218:
{
target = this;
triggered_spell_id = 17941;
@@ -5548,12 +5531,45 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
case 30295:
case 30296:
{
+ // Improved Soul Leech
+ AuraEffectList const& SoulLeechAuras = GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator i = SoulLeechAuras.begin();i != SoulLeechAuras.end(); ++i)
+ {
+ if ((*i)->GetId()==54117 || (*i)->GetId()==54118)
+ {
+ basepoints0 = int32((*i)->GetAmount());
+ if (target = GetGuardianPet())
+ {
+ // regen mana for pet
+ CastCustomSpell(target,54607,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ }
+ // regen mana for caster
+ CastCustomSpell(this,59117,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ break;
+ }
+ }
// health
- basepoints0 = int32(damage*triggeredByAura->GetModifier()->m_amount/100);
+ basepoints0 = int32(damage*triggerAmount/100);
target = this;
triggered_spell_id = 30294;
break;
}
+ // Improved Fear
+ case 53754:
+ {
+ if(!pVictim || !pVictim->isAlive())
+ return false;
+ pVictim->CastSpell(pVictim, 60946,true, castItem, triggeredByAura);
+ return true;
+ }
+ // Improved Fear (Rank 2)
+ case 53759:
+ {
+ if(!pVictim || !pVictim->isAlive())
+ return false;
+ pVictim->CastSpell(pVictim, 60947,true, castItem, triggeredByAura);
+ return true;
+ }
// Shadowflame (Voidheart Raiment set bonus)
case 37377:
{
@@ -5563,12 +5579,12 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
// Pet Healing (Corruptor Raiment or Rift Stalker Armor)
case 37381:
{
- target = GetPet();
+ target = GetGuardianPet();
if(!target)
return false;
// heal amount
- basepoints0 = damage * triggeredByAura->GetModifier()->m_amount/100;
+ basepoints0 = damage * triggerAmount/100;
triggered_spell_id = 37382;
break;
}
@@ -5584,7 +5600,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
case SPELLFAMILY_PRIEST:
{
// Vampiric Touch
- if( dummySpell->SpellFamilyFlags & 0x0000040000000000LL )
+ if( dummySpell->SpellFamilyFlags[1] & 0x00000400 )
{
if(!pVictim || !pVictim->isAlive())
return false;
@@ -5593,11 +5609,17 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID())
return false;
- // energize amount
- basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100;
- pVictim->CastCustomSpell(pVictim,34919,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ // Energize 0.25% of max. mana
+ pVictim->CastSpell(pVictim,57669,true,castItem,triggeredByAura);
return true; // no hidden cooldown
}
+ // Divine Aegis
+ if (dummySpell->SpellIconID == 2820)
+ {
+ basepoints0 = damage * triggerAmount/100;
+ triggered_spell_id = 47753;
+ break;
+ }
switch(dummySpell->Id)
{
// Vampiric Embrace
@@ -5611,18 +5633,19 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return false;
// heal amount
- basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100;
- pVictim->CastCustomSpell(pVictim,15290,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ int32 team = triggerAmount*damage/500;
+ int32 self = triggerAmount*damage/100 - team;
+ pVictim->CastCustomSpell(pVictim,15290,&team,&self,NULL,true,castItem,triggeredByAura);
return true; // no hidden cooldown
}
// Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
case 40438:
{
// Shadow Word: Pain
- if( procSpell->SpellFamilyFlags & 0x0000000000008000LL )
+ if( procSpell->SpellFamilyFlags[0] & 0x8000 )
triggered_spell_id = 40441;
// Renew
- else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL )
+ else if( procSpell->SpellFamilyFlags[0] & 0x10 )
triggered_spell_id = 40440;
else
return false;
@@ -5630,6 +5653,75 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
target = this;
break;
}
+ // Glyph of Power Word: Shield
+ case 55672:
+ {
+ basepoints0 = damage * triggerAmount/100;
+ triggered_spell_id = 56160;
+ break;
+ }
+ // Glyph of Prayer of Healing
+ case 55680:
+ {
+ triggered_spell_id = 56161;
+
+ SpellEntry const* GoPoH = sSpellStore.LookupEntry(triggered_spell_id);
+ if(!GoPoH)
+ return false;
+
+ int EffIndex = 0;
+ for(int i = 0; i < MAX_SPELL_EFFECTS; i++)
+ {
+ if(GoPoH->Effect[i] == SPELL_EFFECT_APPLY_AURA)
+ {
+ EffIndex = i;
+ break;
+ }
+ }
+ int32 tickcount = GetSpellMaxDuration(GoPoH) / GoPoH->EffectAmplitude[EffIndex];
+ if(!tickcount)
+ return false;
+
+ basepoints0 = damage * triggerAmount / tickcount / 100;
+ break;
+ }
+ // Improved Shadowform
+ case 47570:
+ case 47569:
+ {
+ RemoveAurasByTypeWithDispel(SPELL_AURA_MOD_ROOT);
+ RemoveAurasByTypeWithDispel(SPELL_AURA_MOD_DECREASE_SPEED);
+ break;
+ }
+ // Psychic Horror
+ case 47571:
+ {
+ if(!pVictim || !pVictim->isAlive())
+ return false;
+ pVictim->CastSpell(pVictim, 59980,true, castItem, triggeredByAura);
+ return true;
+ }
+ // Psychic Horror (Rank 2)
+ case 47572:
+ {
+ if(!pVictim || !pVictim->isAlive())
+ return false;
+ pVictim->CastSpell(pVictim, 59981,true, castItem, triggeredByAura);
+ return true;
+ }
+ // Glyph of Dispel Magic
+ case 55677:
+ {
+ // Dispel Magic shares spellfamilyflag with abolish disease
+ if (procSpell->SpellIconID!=74)
+ return false;
+ if(!target->IsFriendlyTo(this))
+ return false;
+
+ basepoints0 = int32(target->GetMaxHealth() * triggerAmount / 100);
+ triggered_spell_id = 56131;
+ break;
+ }
// Oracle Healing Bonus ("Garments of the Oracle" set)
case 26169:
{
@@ -5646,12 +5738,12 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return false;
// heal amount
- basepoints0 = int32(damage * 2 / 100);
+ basepoints0 = damage * triggerAmount/100;
target = this;
triggered_spell_id = 39373;
break;
}
- // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
+ // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus)
case 28809:
{
triggered_spell_id = 28810;
@@ -5664,6 +5756,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
{
switch(dummySpell->Id)
{
+ // Leader of the Pack
+ case 24932:
+ {
+ if (triggerAmount <= 0)
+ return false;
+ basepoints0 = triggerAmount * GetMaxHealth() / 100;
+ target = this;
+ triggered_spell_id = 34299;
+ if (triggeredByAura->GetCaster() != this)
+ break;
+ int32 basepoints1 = triggerAmount * 2;
+ CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura);
+ break;
+ }
// Healing Touch (Dreamwalker Raiment set)
case 28719:
{
@@ -5673,6 +5779,15 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 28742;
break;
}
+ // Glyph of Rejuvenation
+ case 54754:
+ {
+ if (!pVictim || pVictim->GetHealth() >= triggerAmount * pVictim->GetMaxHealth()/100)
+ return false;
+ basepoints0 = int32(triggerAmount * damage / 100);
+ triggered_spell_id = 54755;
+ break;
+ }
// Healing Touch Refund (Idol of Longevity trinket)
case 28847:
{
@@ -5694,22 +5809,22 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
float chance;
// Starfire
- if( procSpell->SpellFamilyFlags & 0x0000000000000004LL )
+ if( procSpell->SpellFamilyFlags[0] & 0x4 )
{
triggered_spell_id = 40445;
- chance = 25.f;
+ chance = 25.0f;
}
// Rejuvenation
- else if( procSpell->SpellFamilyFlags & 0x0000000000000010LL )
+ else if( procSpell->SpellFamilyFlags[0] & 0x10 )
{
triggered_spell_id = 40446;
- chance = 25.f;
+ chance = 25.0f;
}
// Mangle (cat/bear)
- else if( procSpell->SpellFamilyFlags & 0x0000044000000000LL )
+ else if( procSpell->SpellFamilyFlags[1] & 0x00000440)
{
triggered_spell_id = 40452;
- chance = 40.f;
+ chance = 40.0f;
}
else
return false;
@@ -5728,6 +5843,39 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
break;
}
}
+ // Eclipse
+ if (dummySpell->SpellIconID == 2856)
+ {
+ if (!procSpell)
+ return false;
+ // Only 0 aura can proc
+ if (effIndex!=0)
+ return false;
+ // Wrath crit
+ if (procSpell->SpellFamilyFlags[0] & 0x1)
+ {
+ if (!roll_chance_i(60))
+ return false;
+ triggered_spell_id = 48518;
+ target = this;
+ break;
+ }
+ // Starfire crit
+ if (procSpell->SpellFamilyFlags[0] & 0x4)
+ {
+ triggered_spell_id = 48517;
+ target = this;
+ break;
+ }
+ return false;
+ }
+ // Living Seed
+ else if (dummySpell->SpellIconID == 2860)
+ {
+ triggered_spell_id = 48504;
+ basepoints0 = triggerAmount * damage / 100;
+ break;
+ }
break;
}
case SPELLFAMILY_ROGUE:
@@ -5745,19 +5893,32 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
break;
}
}
+ // Cut to the Chase
+ if( dummySpell->SpellIconID == 2909 )
+ {
+ // "refresh your Slice and Dice duration to its 5 combo point maximum"
+ // lookup Slice and Dice
+ if (AuraEffect * aur = GetAura(SPELL_AURA_MOD_HASTE, SPELLFAMILY_ROGUE,0x40000, 0, 0))
+ {
+ aur->GetParentAura()->SetAuraDuration(GetSpellMaxDuration(aur->GetSpellProto()), true);
+ return true;
+ }
+ return false;
+ }
+ // Deadly Brew
+ else if( dummySpell->SpellIconID == 2963 )
+ {
+ triggered_spell_id = 3409;
+ break;
+ }
// Quick Recovery
- if( dummySpell->SpellIconID == 2116 )
+ else if( dummySpell->SpellIconID == 2116 )
{
if(!procSpell)
return false;
- // only rogue's finishing moves (maybe need additional checks)
- if( procSpell->SpellFamilyName!=SPELLFAMILY_ROGUE ||
- (procSpell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE) == 0)
- return false;
-
// energy cost save
- basepoints0 = procSpell->manaCost * triggeredByAura->GetModifier()->m_amount/100;
+ basepoints0 = procSpell->manaCost * triggerAmount/100;
if(basepoints0 <= 0)
return false;
@@ -5776,7 +5937,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return false;
// mana cost save
- basepoints0 = procSpell->manaCost * 40/100;
+ int32 mana = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
+ basepoints0 = mana * 40/100;
if(basepoints0 <= 0)
return false;
@@ -5784,75 +5946,142 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 34720;
break;
}
+ // Hunting Party
+ if ( dummySpell->SpellIconID == 3406 )
+ {
+ triggered_spell_id = 57669;
+ target = this;
+ break;
+ }
+ // Lock and Load
+ if ( dummySpell->SpellIconID == 3579 )
+ {
+ // Proc only from periodic (from trap activation proc another aura of this spell)
+ if (!(procFlag & PROC_FLAG_ON_DO_PERIODIC) || !roll_chance_i(triggerAmount))
+ return false;
+ triggered_spell_id = 56453;
+ target = this;
+ break;
+ }
+ // Rapid Recuperation
+ if ( dummySpell->SpellIconID == 3560 )
+ {
+ // This effect only from Rapid Killing (mana regen)
+ if (!(procSpell->SpellFamilyFlags[1] & 0x01000000))
+ return false;
+ triggered_spell_id = 56654;
+ target = this;
+ break;
+ }
break;
}
case SPELLFAMILY_PALADIN:
{
- // Seal of Righteousness - melee proc dummy
- if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggeredByAura->GetEffIndex()==0)
+ // Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage)
+ if (dummySpell->SpellFamilyFlags[0]&0x8000000)
{
- if(GetTypeId() != TYPEID_PLAYER)
+ if (effIndex!=0)
return false;
-
- uint32 spellId;
- switch (triggeredByAura->GetId())
- {
- case 21084: spellId = 25742; break; // Rank 1
- case 20287: spellId = 25740; break; // Rank 2
- case 20288: spellId = 25739; break; // Rank 3
- case 20289: spellId = 25738; break; // Rank 4
- case 20290: spellId = 25737; break; // Rank 5
- case 20291: spellId = 25736; break; // Rank 6
- case 20292: spellId = 25735; break; // Rank 7
- case 20293: spellId = 25713; break; // Rank 8
- case 27155: spellId = 27156; break; // Rank 9
- default:
- sLog.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura->GetId());
- return false;
- }
- Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
- float speed = (item ? item->GetProto()->Delay : BASE_ATTACK_TIME)/1000.0f;
-
- float damageBasePoints;
- if(item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON)
- // two hand weapon
- damageBasePoints=1.20f*triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f + 1;
- else
- // one hand weapon/no weapon
- damageBasePoints=0.85f*ceil(triggeredByAura->GetModifier()->m_amount * 1.2f * 1.03f * speed/100.0f) - 1;
-
- int32 damagePoint = int32(damageBasePoints + 0.03f * (GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE)+GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE))/2.0f) + 1;
-
- // apply damage bonuses manually
- if(damagePoint >= 0)
- damagePoint = SpellDamageBonus(pVictim, dummySpell, damagePoint, SPELL_DIRECT_DAMAGE);
-
- CastCustomSpell(pVictim,spellId,&damagePoint,NULL,NULL,true,NULL, triggeredByAura);
- return true; // no hidden cooldown
+ triggered_spell_id = 25742;
+ float ap = GetTotalAttackPowerValue(BASE_ATTACK);
+ int32 holy = SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
+ SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, pVictim);
+ basepoints0 = (int32)GetAttackTime(BASE_ATTACK) * int32(ap*0.022f + 0.044f * holy) / 1000;
+ break;
}
- // Seal of Blood do damage trigger
- if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL)
+ // Light's Beacon - Beacon of Light
+ if ( dummySpell->Id == 53651 )
{
- switch(triggeredByAura->GetEffIndex())
+ if (Unit * caster = triggeredByAura->GetCaster())
{
- case 0:
- triggered_spell_id = 31893;
- break;
- case 1:
+ // do not proc when target of beacon of light is healed
+ if (caster == pVictim)
+ return false;
+ if (Aura * aur = caster->GetAura(53563))
{
- // damage
- damage += CalculateDamage(BASE_ATTACK, false) * 35 / 100; // add spell damage from prev effect (35%)
- basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100;
-
- target = this;
- triggered_spell_id = 32221;
- break;
+ if (Unit * paladin = aur->GetCaster())
+ {
+ if (paladin != this)
+ return false;
+ basepoints0 = damage;
+ triggered_spell_id = 53654;
+ target = caster;
+ break;
+ }
+ else
+ {
+ pVictim->RemoveAura(triggeredByAura->GetParentAura());
+ return false;
+ }
}
}
+ else return false;
+ }
+ // Judgements of the Wise
+ if (dummySpell->SpellIconID == 3017)
+ {
+ // hardcoded amount
+ basepoints0 = 15 * GetCreatePowers(POWER_MANA)/100;
+ target = this;
+ triggered_spell_id = 31930;
+ // replenishment
+ CastSpell(this,57669,true, castItem, triggeredByAura);
+ break;
+ }
+ // Sanctified Wrath
+ if (dummySpell->SpellIconID == 3029)
+ {
+ triggered_spell_id = 57318;
+ target = this;
+ basepoints0 = triggerAmount;
+ CastCustomSpell(target,triggered_spell_id,&basepoints0,&basepoints0,NULL,true,castItem,triggeredByAura);
+ return true;
+ }
+ // Sacred Shield
+ if (dummySpell->SpellFamilyFlags[1]&0x00080000)
+ {
+ triggered_spell_id = 58597;
+ target = this;
+ break;
+ }
+ // Righteous Vengeance
+ if (dummySpell->SpellIconID == 3025)
+ {
+ // 4 damage tick
+ basepoints0 = triggerAmount*damage/400;
+ triggered_spell_id = 61840;
+ break;
+ }
+ // Sheath of Light
+ if (dummySpell->SpellIconID == 3030)
+ {
+ // 4 healing tick
+ basepoints0 = triggerAmount*damage/400;
+ triggered_spell_id = 54203;
+ break;
}
-
switch(dummySpell->Id)
{
+ // Judgement of Light
+ case 20185:
+ {
+ // Get judgement caster
+ Unit *caster = triggeredByAura->GetCaster();
+ if (!caster)
+ return false;
+ float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
+ int32 holy = caster->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
+ caster->SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, this);
+ basepoints0 = int32(ap*0.10f + 0.10f*holy);
+ pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura);
+ return true;
+ }
+ // Judgement of Wisdom
+ case 20186:
+ {
+ pVictim->CastSpell(pVictim, 20268, true, NULL, triggeredByAura);
+ return true;
+ }
// Holy Power (Redemption Armor set)
case 28789:
{
@@ -5884,7 +6113,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
}
break;
}
- //Seal of Vengeance
+ // Seal of Vengeance (damage calc on apply aura)
case 31801:
{
if(effIndex != 0) // effect 1,2 used by seal unleashing code
@@ -5893,7 +6122,16 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 31803;
break;
}
- // Spiritual Att.
+ // Seal of Corruption
+ case 53736:
+ {
+ if(effIndex != 0) // effect 1,2 used by seal unleashing code
+ return false;
+
+ triggered_spell_id = 53742;
+ break;
+ }
+ // Spiritual Attunement
case 31785:
case 33776:
{
@@ -5902,11 +6140,45 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return false;
// heal amount
- basepoints0 = triggeredByAura->GetModifier()->m_amount*damage/100;
+ basepoints0 = triggerAmount*damage/100;
target = this;
triggered_spell_id = 31786;
break;
}
+ // Seal of Blood do damage trigger
+ case 31892:
+ {
+ if (effIndex == 0) // 0 effect - is proc on enemy
+ triggered_spell_id = 31893;
+ else if (effIndex == 1) // 1 effect - is proc on self
+ {
+ // add spell damage from prev effect (27%)
+ damage += CalculateDamage(BASE_ATTACK, false) * 27 / 100;
+ basepoints0 = triggerAmount * damage / 100;
+ target = this;
+ triggered_spell_id = 32221;
+ }
+ else
+ return false;
+ break;
+ }
+ // Seal of the Martyr do damage trigger
+ case 53720:
+ {
+ if (effIndex == 0) // 0 effect - is proc on enemy
+ triggered_spell_id = 53719;
+ else if (effIndex == 1) // 1 effect - is proc on self
+ {
+ // add spell damage from prev effect (27%)
+ damage += CalculateDamage(BASE_ATTACK, false) * 27 / 100;
+ basepoints0 = triggerAmount * damage / 100;
+ target = this;
+ triggered_spell_id = 53718;
+ }
+ else
+ return false;
+ break;
+ }
// Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
case 40470:
{
@@ -5916,16 +6188,16 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
float chance;
// Flash of light/Holy light
- if( procSpell->SpellFamilyFlags & 0x00000000C0000000LL)
+ if( procSpell->SpellFamilyFlags[0] & 0xC0000000)
{
triggered_spell_id = 40471;
- chance = 15.f;
+ chance = 15.0f;
}
// Judgement
- else if( procSpell->SpellFamilyFlags & 0x0000000000800000LL )
+ else if( procSpell->SpellFamilyFlags[0] & 0x800000 )
{
triggered_spell_id = 40472;
- chance = 50.f;
+ chance = 50.0f;
}
else
return false;
@@ -5935,6 +6207,33 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
break;
}
+ // Glyph of Divinity
+ case 54939:
+ {
+ // Lookup base amount mana restore
+ for (int i=0; i<3;i++)
+ if (procSpell->Effect[i] == SPELL_EFFECT_ENERGIZE)
+ {
+ int32 mana = procSpell->EffectBasePoints[i];
+ CastCustomSpell(this, 54986, 0, &mana, 0, true, castItem, triggeredByAura);
+ break;
+ }
+ return true;
+ }
+ // Glyph of Flash of Light
+ case 54936:
+ {
+ triggered_spell_id = 54957;
+ basepoints0 = triggerAmount*damage/100;
+ break;
+ }
+ // Glyph of Holy Light
+ case 54937:
+ {
+ triggered_spell_id = 54968;
+ basepoints0 = triggerAmount*damage/100;
+ break;
+ }
}
break;
}
@@ -5942,6 +6241,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
{
switch(dummySpell->Id)
{
+ // Improved fire nova totem
+ case 16544:
+ {
+ triggered_spell_id = 51880;
+ break;
+ }
+ // Tidal Force
+ case 55198:
+ {
+ // Remove aura stack from caster
+ RemoveAuraFromStack(55166);
+ // drop charges
+ return false;
+ }
// Totemic Power (The Earthshatterer set)
case 28823:
{
@@ -5993,14 +6306,19 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id))
return false;
+ // Now amount of extra power stored in 1 effect of Enchant spell
+ // Get it by item enchant id
uint32 spellId;
switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)))
{
- case 283: spellId = 33757; break; //1 Rank
- case 284: spellId = 33756; break; //2 Rank
- case 525: spellId = 33755; break; //3 Rank
- case 1669:spellId = 33754; break; //4 Rank
- case 2636:spellId = 33727; break; //5 Rank
+ case 283: spellId = 8232; break; // 1 Rank
+ case 284: spellId = 8235; break; // 2 Rank
+ case 525: spellId = 10486; break; // 3 Rank
+ case 1669:spellId = 16362; break; // 4 Rank
+ case 2636:spellId = 25505; break; // 5 Rank
+ case 3785:spellId = 58801; break; // 6 Rank
+ case 3786:spellId = 58803; break; // 7 Rank
+ case 3787:spellId = 58804; break; // 8 Rank
default:
{
sLog.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
@@ -6016,7 +6334,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return false;
}
- int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry,0,windfurySpellEntry->EffectBasePoints[0],pVictim);
+ int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry, 1, windfurySpellEntry->EffectBasePoints[1], pVictim);
// Off-Hand case
if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND )
@@ -6050,20 +6368,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return false;
float chance;
- if (procSpell->SpellFamilyFlags & 0x0000000000000001LL)
+ if (procSpell->SpellFamilyFlags[0] & 0x1)
{
triggered_spell_id = 40465; // Lightning Bolt
- chance = 15.f;
+ chance = 15.0f;
}
- else if (procSpell->SpellFamilyFlags & 0x0000000000000080LL)
+ else if (procSpell->SpellFamilyFlags[0] & 0x80)
{
triggered_spell_id = 40465; // Lesser Healing Wave
- chance = 10.f;
+ chance = 10.0f;
}
- else if (procSpell->SpellFamilyFlags & 0x0000001000000000LL)
+ else if (procSpell->SpellFamilyFlags[1] & 0x00000010)
{
triggered_spell_id = 40466; // Stormstrike
- chance = 50.f;
+ chance = 50.0f;
}
else
return false;
@@ -6074,20 +6392,67 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
target = this;
break;
}
+ // Glyph of Healing Wave
+ case 55440:
+ {
+ // Not proc from self heals
+ if (this==pVictim)
+ return false;
+ basepoints0 = triggerAmount * damage / 100;
+ target = this;
+ triggered_spell_id = 55533;
+ break;
+ }
+ // Spirit Hunt
+ case 58877:
+ {
+ // Cast on owner
+ target = GetOwner();
+ if(!target)
+ return false;
+ basepoints0 = triggerAmount * damage / 100;
+ triggered_spell_id = 58879;
+ break;
+ }
+ }
+ // Ancestral Awakening
+ if (dummySpell->SpellIconID == 3065)
+ {
+ triggered_spell_id = 52759;
+ basepoints0 = triggerAmount * damage / 100;
+ target = this;
+ break;
}
-
// Earth Shield
- if(dummySpell->SpellFamilyFlags==0x40000000000LL)
+ if(dummySpell->SpellFamilyFlags[1] & 0x00000400)
{
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
-
- // heal
- basepoints0 = triggeredByAura->GetModifier()->m_amount;
+ basepoints0 = triggerAmount;
target = this;
triggered_spell_id = 379;
break;
}
+ // Improved Water Shield
+ if (dummySpell->SpellIconID == 2287)
+ {
+ // Lesser Healing Wave need aditional 60% roll
+ if (procSpell->SpellFamilyFlags[0] & 0x80 && !roll_chance_i(60))
+ return false;
+ // lookup water shield
+ AuraEffectList const& vs = GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL);
+ for(AuraEffectList::const_iterator itr = vs.begin(); itr != vs.end(); ++itr)
+ {
+ if( (*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN &&
+ (*itr)->GetSpellProto()->SpellFamilyFlags[1] & 0x00000020)
+ {
+ uint32 spell = (*itr)->GetSpellProto()->EffectTriggerSpell[(*itr)->GetEffIndex()];
+ CastSpell(this, spell, true, castItem, triggeredByAura);
+ (*itr)->GetParentAura()->DropAuraCharge();
+ return true;
+ }
+ }
+ return false;
+ break;
+ }
// Lightning Overload
if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
{
@@ -6115,6 +6480,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
case 15208: spellId = 45294; break; // Rank 10
case 25448: spellId = 45295; break; // Rank 11
case 25449: spellId = 45296; break; // Rank 12
+ case 49237: spellId = 49239; break; // Rank 13
+ case 49238: spellId = 49240; break; // Rank 14
// Chain Lightning
case 421: spellId = 45297; break; // Rank 1
case 930: spellId = 45298; break; // Rank 2
@@ -6122,44 +6489,162 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
case 10605: spellId = 45300; break; // Rank 4
case 25439: spellId = 45301; break; // Rank 5
case 25442: spellId = 45302; break; // Rank 6
+ case 49268: spellId = 49270; break; // Rank 7
+ case 49269: spellId = 49271; break; // Rank 8
default:
sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id);
return false;
}
- // No thread generated mod
- SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_THREAT;
- mod->value = -100;
- mod->type = SPELLMOD_PCT;
- mod->spellId = dummySpell->Id;
- mod->effectId = 0;
- mod->lastAffected = NULL;
- mod->mask = 0x0000000000000003LL;
- mod->charges = 0;
- ((Player*)this)->AddSpellMod(mod, true);
-
// Remove cooldown (Chain Lightning - have Category Recovery time)
- if (procSpell->SpellFamilyFlags & 0x0000000000000002LL)
+ if (procSpell->SpellFamilyFlags[0] & 0x2)
((Player*)this)->RemoveSpellCooldown(spellId);
- // Hmmm.. in most case spells already set half basepoints but...
- // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
- // As on wiki:
- // BUG: Rank 2 to 10 (and maybe 11) of Lightning Bolt will proc another Bolt with FULL damage (not halved). This bug is known and will probably be fixed soon.
- // So - no add changes :)
- CastSpell(pVictim, spellId, true, castItem, triggeredByAura);
+ // do not reduce damage-spells have correct basepoints
+ int32 mod = 0;
- ((Player*)this)->AddSpellMod(mod, false);
+ // Apply spellmod
+ CastCustomSpell(this, 39805, NULL, &mod, NULL, true, castItem, triggeredByAura);
+
+ CastSpell(pVictim, spellId, true, castItem, triggeredByAura);
if( cooldown && GetTypeId()==TYPEID_PLAYER )
((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown);
return true;
}
+ // Static Shock
+ if(dummySpell->SpellIconID == 3059)
+ {
+ // lookup Lightning Shield
+ AuraEffectList const& vs = GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL);
+ for(AuraEffectList::const_iterator itr = vs.begin(); itr != vs.end(); ++itr)
+ {
+ if( (*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN &&
+ (*itr)->GetSpellProto()->SpellFamilyFlags[0] & 0x400)
+ {
+ uint32 spell = 0;
+ switch ((*itr)->GetId())
+ {
+ case 324: spell = 26364; break;
+ case 325: spell = 26365; break;
+ case 905: spell = 26366; break;
+ case 945: spell = 26367; break;
+ case 8134: spell = 26369; break;
+ case 10431: spell = 26370; break;
+ case 10432: spell = 26363; break;
+ case 25469: spell = 26371; break;
+ case 25472: spell = 26372; break;
+ case 49280: spell = 49278; break;
+ case 49281: spell = 49279; break;
+ default:
+ return false;
+ }
+ CastSpell(target, spell, true, castItem, triggeredByAura);
+ (*itr)->GetParentAura()->DropAuraCharge();
+ return true;
+ }
+ }
+ return false;
+ break;
+ }
+ break;
+ }
+ case SPELLFAMILY_DEATHKNIGHT:
+ {
+ // Blood Aura
+ if (dummySpell->SpellIconID == 2636)
+ {
+ if (GetTypeId() != TYPEID_PLAYER || !((Player*)this)->isHonorOrXPTarget(pVictim))
+ return false;
+ basepoints0 = triggerAmount * damage / 100;
+ triggered_spell_id = 53168;
+ break;
+ }
+ // Butchery
+ if (dummySpell->SpellIconID == 2664)
+ {
+ basepoints0 = triggerAmount;
+ triggered_spell_id = 50163;
+ target = this;
+ break;
+ }
+ // Dancing Rune Weapon
+ if (dummySpell->Id == 49028)
+ {
+ // 1 dummy aura for dismiss rune blade
+ if (effIndex!=2)
+ return false;
+ // TODO: wite script for this "fights on its own, doing the same attacks"
+ // NOTE: Trigger here on every attack and spell cast
+ return false;
+ }
+ // Mark of Blood
+ if (dummySpell->Id == 49005)
+ {
+ // TODO: need more info (cooldowns/PPM)
+ triggered_spell_id = 61607;
+ break;
+ }
+ // Vendetta
+ if (dummySpell->SpellFamilyFlags[0] & 0x10000)
+ {
+ basepoints0 = triggerAmount * GetMaxHealth() / 100;
+ triggered_spell_id = 50181;
+ target = this;
+ break;
+ }
+ // Necrosis
+ if (dummySpell->SpellIconID == 2709)
+ {
+ basepoints0 = triggerAmount * damage / 100;
+ triggered_spell_id = 51460;
+ break;
+ }
+ // Runic Power Back on Snare/Root
+ if (dummySpell->Id == 61257)
+ {
+ // only for spells and hit/crit (trigger start always) and not start from self casted spells
+ if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim)
+ return false;
+ // Need snare or root mechanic
+ if (!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_SNARE))))
+ return false;
+ triggered_spell_id = 61258;
+ target = this;
+ break;
+ }
+ // Wandering Plague
+ if (dummySpell->SpellIconID == 1614)
+ {
+ if (!roll_chance_f(GetUnitCriticalChance(BASE_ATTACK, pVictim)))
+ return false;
+ basepoints0 = triggerAmount * damage / 100;
+ triggered_spell_id = 50526;
+ break;
+ }
+ // Death Strike healing effect
+ if (dummySpell->Id == 45469)
+ {
+ uint8 n=0;
+ Unit::AuraEffectList const& decSpeedList = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ for(Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
+ {
+ if((*iter)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DEATHKNIGHT
+ && (*iter)->GetCasterGUID() == GetGUID()
+ && (*iter)->GetSpellProto()->Dispel == DISPEL_DISEASE)
+ {
+ n++;
+ }
+ }
+ int32 heal=0.5f*n*damage+damage;
+ CastCustomSpell(this,45470,&heal,NULL,NULL,true);
+ return true;
+ }
break;
}
case SPELLFAMILY_POTION:
{
+ // alchemist's stone
if (dummySpell->Id == 17619)
{
if (procSpell->SpellFamilyName == SPELLFAMILY_POTION)
@@ -6174,13 +6659,35 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
{
triggered_spell_id = 21400;
}
- else continue;
+ else
+ continue;
+
basepoints0 = CalculateSpellDamage(procSpell,i,procSpell->EffectBasePoints[i],this) * 0.4f;
- CastCustomSpell(this,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ CastCustomSpell(this,triggered_spell_id,&basepoints0,NULL,NULL,true,NULL,triggeredByAura);
}
return true;
}
}
+ break;
+ }
+ case SPELLFAMILY_PET:
+ {
+ // improved cower
+ if (dummySpell->SpellIconID == 958 && procSpell->SpellIconID == 958)
+ {
+ triggered_spell_id = dummySpell->Id == 53180 ? 54200 : 54201;
+ target = this;
+ break;
+ }
+ // guard dog
+ if (dummySpell->SpellIconID == 201 && procSpell->SpellIconID == 201)
+ {
+ triggered_spell_id = 54445;
+ target = this;
+ pVictim->AddThreat(this,procSpell->EffectBasePoints[0]*triggerAmount/100);
+ break;
+ }
+ break;
}
default:
break;
@@ -6215,1184 +6722,649 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return true;
}
-/*
-bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attackType, uint32 cooldown)
+
+bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
- SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
+ SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
+ uint32 effIndex = triggeredByAura->GetEffIndex();
+ int32 triggerAmount = triggeredByAura->GetAmount();
- Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
- ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
+ Item* castItem = triggeredByAura->GetParentAura()->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
+ ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetParentAura()->GetCastItemGUID()) : NULL;
- uint32 triggered_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
- Unit* target = !(procFlags & PROC_FLAG_HEAL) && IsPositiveSpell(triggered_spell_id) ? this : pVictim;
+ uint32 triggered_spell_id = 0;
+ Unit* target = pVictim;
int32 basepoints0 = 0;
- switch(auraSpellInfo->SpellFamilyName)
+ switch(dummySpell->SpellFamilyName)
{
- case SPELLFAMILY_GENERIC:
+ case SPELLFAMILY_HUNTER:
{
- switch(auraSpellInfo->Id)
+ // Aspect of the Viper
+ if ( dummySpell->SpellFamilyFlags[1] & 0x40000 )
{
- // Aegis of Preservation
- case 23780:
- //Aegis Heal (instead non-existed triggered spell)
- triggered_spell_id = 23781;
- target = this;
- break;
- // Elune's Touch (moonkin mana restore)
- case 24905:
- {
- // Elune's Touch (instead non-existed triggered spell)
- triggered_spell_id = 33926;
- basepoints0 = int32(0.3f * GetTotalAttackPowerValue(BASE_ATTACK));
- target = this;
- break;
- }
- // Enlightenment
- case 29601:
+ uint32 maxmana = GetMaxPower(POWER_MANA);
+ basepoints0 = maxmana* GetAttackTime(RANGED_ATTACK)/1000.0f/100.0f;
+
+ target = this;
+ triggered_spell_id = 34075;
+ break;
+ }
+ break;
+ }
+ }
+ // processed charge only counting case
+ if(!triggered_spell_id)
+ return true;
+
+ SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
+
+ if(!triggerEntry)
+ {
+ sLog.outError("Unit::HandleObsModEnergyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id);
+ return false;
+ }
+
+ // default case
+ if(!target || target!=this && !target->isAlive())
+ return false;
+
+ if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
+ return false;
+
+ if(basepoints0)
+ CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ else
+ CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
+
+ if( cooldown && GetTypeId()==TYPEID_PLAYER )
+ ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
+
+ return true;
+}
+
+bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
+{
+ SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
+ uint32 effIndex = triggeredByAura->GetEffIndex();
+ int32 triggerAmount = triggeredByAura->GetAmount();
+
+ Item* castItem = triggeredByAura->GetParentAura()->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
+ ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetParentAura()->GetCastItemGUID()) : NULL;
+
+ uint32 triggered_spell_id = 0;
+ Unit* target = pVictim;
+ int32 basepoints0 = 0;
+
+ switch(dummySpell->SpellFamilyName)
+ {
+ case SPELLFAMILY_PALADIN:
+ {
+ // Blessing of Sanctuary
+ if ( dummySpell->SpellFamilyFlags[0] & 0x10000000 )
+ {
+ switch (getPowerType())
{
- // only for cast with mana price
- if(!procSpell || procSpell->powerType!=POWER_MANA || procSpell->manaCost==0 && procSpell->ManaCostPercentage==0 && procSpell->manaCostPerlevel==0)
+ case POWER_MANA: triggered_spell_id = 57319; break;
+ case POWER_RAGE: triggered_spell_id = 57320; break;
+ case POWER_RUNIC_POWER: triggered_spell_id = 57321; break;
+ default:
return false;
- break; // fall through to normal cast
}
- // Health Restore
- case 33510:
- {
- // at melee hit call std triggered spell
- if(procFlags & PROC_FLAG_HIT_MELEE)
- break; // fall through to normal cast
+ }
+ break;
+ }
+ }
+ // processed charge only counting case
+ if(!triggered_spell_id)
+ return true;
- // Mark of Conquest - else (at range hit) called custom case
- triggered_spell_id = 39557;
- target = this;
+ SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
+
+ if(!triggerEntry)
+ {
+ sLog.outError("Unit::HandleModDamagePctTakenAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id);
+ return false;
+ }
+
+ // default case
+ if(!target || target!=this && !target->isAlive())
+ return false;
+
+ if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
+ return false;
+
+ if(basepoints0)
+ CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ else
+ CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
+
+ if( cooldown && GetTypeId()==TYPEID_PLAYER )
+ ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
+
+ return true;
+}
+
+bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown)
+{
+ // Get triggered aura spell info
+ SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
+
+ // Basepoints of trigger aura
+ int32 triggerAmount = triggeredByAura->GetAmount();
+
+ // Set trigger spell id, target, custom basepoints
+ uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
+
+ Unit* target = NULL;
+ int32 basepoints0 = 0;
+
+ if(triggeredByAura->GetAuraName() == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE)
+ basepoints0 = triggerAmount;
+
+ Item* castItem = triggeredByAura->GetParentAura()->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
+ ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetParentAura()->GetCastItemGUID()) : NULL;
+
+ AuraMap::iterator i,next;
+ for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
+ {
+ next = i;
+ ++next;
+ if (!(*i).second) continue;
+ if ( (*i).second->GetSpellProto()->Id == trigger_spell_id) continue;
+ if (spellmgr.IsNoStackSpellDueToSpell(trigger_spell_id, (*i).second->GetSpellProto()->Id, (pVictim == this)))
+ return false;
+ }
+
+ // Try handle unknown trigger spells
+ if (sSpellStore.LookupEntry(trigger_spell_id)==NULL)
+ {
+ switch (auraSpellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ //if (auraSpellInfo->Id==59532) // Abandon Passengers on Poly
+ //if (auraSpellInfo->Id==54775) // Abandon Vehicle on Poly
+ //if (auraSpellInfo->Id==34082) // Advantaged State (DND)
+ if (auraSpellInfo->Id == 23780) // Aegis of Preservation (Aegis of Preservation trinket)
+ trigger_spell_id = 23781;
+ //else if (auraSpellInfo->Id==43504) // Alterac Valley OnKill Proc Aura
+ //else if (auraSpellInfo->Id == 48876) // Beast's Mark
+ //{
+ // trigger_spell_id = 48877;
+ //}
+ //else if (auraSpellInfo->Id == 59237) // Beast's Mark
+ //{
+ // trigger_spell_id = 59233;
+ //}
+ //else if (auraSpellInfo->Id==46939) // Black Bow of the Betrayer
+ //{
+ // trigger_spell_id = 29471; // gain mana
+ // 27526; // drain mana if possible
+ //}
+ //else if (auraSpellInfo->Id==50844) // Blood Mirror
+ //else if (auraSpellInfo->Id==54476) // Blood Presence
+ //else if (auraSpellInfo->Id==50689) // Blood Presence (Rank 1)
+ //else if (auraSpellInfo->Id==37030) // Chaotic Temperament
+ //else if (auraSpellInfo->Id==52856) // Charge
+ else if (auraSpellInfo->Id==43820) // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket)
+ {
+ // Pct value stored in dummy
+ basepoints0 = pVictim->GetCreateHealth() * auraSpellInfo->EffectBasePoints[1] / 100;
+ target = pVictim;
break;
}
- // Shaleskin
- case 36576:
- return true; // nothing to do
- // Forgotten Knowledge (Blade of Wizardry)
- case 38319:
- // only for harmful enemy targeted spell
- if(!pVictim || pVictim==this || !procSpell || IsPositiveSpell(procSpell->Id))
- return false;
- break; // fall through to normal cast
- // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
- case 39442:
- {
- // proc only at non-crit hits
- if(procFlags & (PROC_FLAG_CRIT_MELEE|PROC_FLAG_CRIT_RANGED|PROC_FLAG_CRIT_SPELL))
- return false;
- break; // fall through to normal cast
+ //else if (auraSpellInfo->Id==41248) // Consuming Strikes
+ // trigger_spell_id = 41249;
+ //else if (auraSpellInfo->Id==45205) // Copy Offhand Weapon
+ //else if (auraSpellInfo->Id==57594) // Copy Ranged Weapon
+ //else if (auraSpellInfo->Id==41054) // Copy Weapon
+ // trigger_spell_id = 41055;
+ //else if (auraSpellInfo->Id==45343) // Dark Flame Aura
+ //else if (auraSpellInfo->Id==47300) // Dark Flame Aura
+ else if (auraSpellInfo->Id==57345) // Darkmoon Card: Greatness
+ {
+ float stat = 0.0f;
+ // strength
+ if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 60229;stat = GetStat(STAT_STRENGTH); }
+ // agility
+ if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 60233;stat = GetStat(STAT_AGILITY); }
+ // intellect
+ if (GetStat(STAT_INTELLECT)> stat) { trigger_spell_id = 60234;stat = GetStat(STAT_INTELLECT);}
+ // spirit
+ if (GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235;stat = GetStat(STAT_SPIRIT); }
}
- // Augment Pain (Timbal's Focusing Crystal trinket bonus)
- case 45054:
+ //else if (auraSpellInfo->Id==31255) // Deadly Swiftness (Rank 1)
+ //else if (auraSpellInfo->Id==5301) // Defensive State (DND)
+ //else if (auraSpellInfo->Id==13358) // Defensive State (DND)
+ //else if (auraSpellInfo->Id==16092) // Defensive State (DND)
+ //else if (auraSpellInfo->Id==24949) // Defensive State 2 (DND)
+ //else if (auraSpellInfo->Id==40329) // Demo Shout Sensor
+ else if (auraSpellInfo->Id == 33896) // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher)
+ trigger_spell_id = 33898;
+ //else if (auraSpellInfo->Id==18943) // Double Attack
+ //else if (auraSpellInfo->Id==19194) // Double Attack
+ //else if (auraSpellInfo->Id==19817) // Double Attack
+ //else if (auraSpellInfo->Id==19818) // Double Attack
+ //else if (auraSpellInfo->Id==22835) // Drunken Rage
+ // trigger_spell_id = 14822;
+ /*
+ else if (auraSpellInfo->SpellIconID==191) // Elemental Response
{
- if(!procSpell)
- return false;
-
- //only periodic damage can trigger spell
- bool found = false;
- for(int j = 0; j < 3; ++j)
+ switch (auraSpellInfo->Id && auraSpellInfo->AttributesEx==0)
{
- if( procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE ||
- procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT ||
- procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_LEECH )
- {
- found = true;
+ case 34191:
+ case 34329:
+ case 34524:
+ case 34582:
+ case 36733:
break;
- }
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Elemental Response",auraSpellInfo->Id);
+ return false;
}
- if(!found)
- return false;
-
- break; // fall through to normal cast
+ //This generic aura self-triggers a different spell for each school of magic that lands on the wearer:
+ switch (procSpell->School)
+ {
+ case SPELL_SCHOOL_FIRE: trigger_spell_id = 34192; break;
+ case SPELL_SCHOOL_FROST: trigger_spell_id = 34193; break;
+ case SPELL_SCHOOL_ARCANE:trigger_spell_id = 34194; break;
+ case SPELL_SCHOOL_NATURE:trigger_spell_id = 34195; break;
+ case SPELL_SCHOOL_SHADOW:trigger_spell_id = 34196; break;
+ case SPELL_SCHOOL_HOLY: trigger_spell_id = 34197; break;
+ case SPELL_SCHOOL_NORMAL:trigger_spell_id = 34198; break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u Elemental Response wrong school",auraSpellInfo->Id);
+ return false;
+ }
+ }
+ */
+ //else if (auraSpellInfo->Id==40364) // Entangling Roots Sensor
+ //else if (auraSpellInfo->Id==33207) // Gossip NPC Periodic - Fidget
+ //else if (auraSpellInfo->Id==50051) // Ethereal Pet Aura
+ //else if (auraSpellInfo->Id==35321) // Gushing Wound
+ //else if (auraSpellInfo->Id==38363) // Gushing Wound
+ //else if (auraSpellInfo->Id==39215) // Gushing Wound
+ //else if (auraSpellInfo->Id==44527) // Hate Monster (Spar Buddy) (30 sec)
+ //else if (auraSpellInfo->Id==44819) // Hate Monster (Spar Buddy) (>30% Health)
+ //else if (auraSpellInfo->Id==44526) // Hate Monster (Spar) (30 sec)
+ //else if (auraSpellInfo->Id==44820) // Hate Monster (Spar) (<30%)
+ //else if (auraSpellInfo->Id==49059) // Horde, Hate Monster (Spar Buddy) (>30% Health)
+ //else if (auraSpellInfo->Id==40250) // Improved Duration
+ //else if (auraSpellInfo->Id==59288) // Infra-Green Shield
+ //else if (auraSpellInfo->Id==54072) // Knockback Ball Passive
+ else if (auraSpellInfo->Id==27522 || auraSpellInfo->Id==40336)
+ // Mana Drain Trigger
+ {
+ // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target.
+ if (this && this->isAlive())
+ CastSpell(this, 29471, true, castItem, triggeredByAura);
+ if (pVictim && pVictim->isAlive())
+ CastSpell(pVictim, 27526, true, castItem, triggeredByAura);
+ return true;
}
- // Evasive Maneuvers (Commendation of Kael'thas)
- case 45057:
+ //else if (auraSpellInfo->Id==55580) // Mana Link
+ //else if (auraSpellInfo->Id==45903) // Offensive State
+ //else if (auraSpellInfo->Id==44326) // Pure Energy Passive
+ //else if (auraSpellInfo->Id==43453) // Rune Ward
+ //else if (auraSpellInfo->Id== 7137) // Shadow Charge (Rank 1)
+ //else if (auraSpellInfo->Id==36576) // Shaleskin (Shaleskin Flayer, Shaleskin Ripper) 30023 trigger
+ //else if (auraSpellInfo->Id==34783) // Spell Reflection
+ //else if (auraSpellInfo->Id==36096) // Spell Reflection
+ //else if (auraSpellInfo->Id==57587) // Steal Ranged ()
+ //else if (auraSpellInfo->Id==36207) // Steal Weapon
+ //else if (auraSpellInfo->Id== 7377) // Take Immune Periodic Damage <Not Working>
+ //else if (auraSpellInfo->Id==35205) // Vanish
+ //else if (auraSpellInfo->Id==42730) // Woe Strike
+ //else if (auraSpellInfo->Id==59735) // Woe Strike
+ //else if (auraSpellInfo->Id==46146) // [PH] Ahune Spanky Hands
+ break;
+ case SPELLFAMILY_MAGE:
+ if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed
{
- // damage taken that reduces below 35% health
- // does NOT mean you must have been >= 35% before
- if (int32(GetHealth())-int32(damage) >= int32(GetMaxHealth()*0.35f))
- return false;
- break; // fall through to normal cast
+ switch (auraSpellInfo->Id)
+ {
+ case 31641: // Rank 1
+ case 31642: // Rank 2
+ trigger_spell_id = 31643;
+ break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blazing Speed",auraSpellInfo->Id);
+ return false;
+ }
}
- }
-
- switch(triggered_spell_id)
+ break;
+ case SPELLFAMILY_WARRIOR:
+ if (auraSpellInfo->Id == 50421) // Scent of Blood
+ trigger_spell_id = 50422;
+ // Sword and Board
+ else if (trigger_spell_id == 50227)
+ // remove cooldown of Shield Slam
+ if (GetTypeId()==TYPEID_PLAYER)
+ ((Player*)this)->RemoveCategoryCooldown(1209);
+ break;
+ case SPELLFAMILY_WARLOCK:
{
- // Setup
- case 15250:
+ // Pyroclasm
+ if (auraSpellInfo->SpellIconID == 1137)
{
- // applied only for main target
- if(!pVictim || pVictim != getVictim())
+ if(!pVictim || !pVictim->isAlive() || pVictim == this || procSpell == NULL)
+ return false;
+ // Calculate spell tick count for spells
+ uint32 tick = 1; // Default tick = 1
+
+ // Hellfire have 15 tick
+ if (procSpell->SpellFamilyFlags[0]&0x40)
+ tick = 15;
+ // Rain of Fire have 4 tick
+ else if (procSpell->SpellFamilyFlags[0]&0x20)
+ tick = 4;
+ else
return false;
- // continue normal case
- break;
- }
- // Shamanistic Rage triggered spell
- case 30824:
- basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100);
- break;
- }
- break;
- }
- case SPELLFAMILY_MAGE:
- {
- switch(auraSpellInfo->SpellIconID)
- {
- // Blazing Speed
- case 2127:
- //Blazing Speed (instead non-existed triggered spell)
- triggered_spell_id = 31643;
- target = this;
- break;
- }
- switch(auraSpellInfo->Id)
- {
- // Persistent Shield (Scarab Brooch)
- case 26467:
- basepoints0 = int32(damage * 0.15f);
- break;
- }
- break;
- }
- case SPELLFAMILY_WARRIOR:
- {
- //Rampage
- if((auraSpellInfo->SpellFamilyFlags & 0x100000) && auraSpellInfo->SpellIconID==2006)
- {
- //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
- //and effect[1]==TriggerSpell
- if(auraSpellInfo->Effect[1]!=SPELL_EFFECT_TRIGGER_SPELL)
- {
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura->GetSpellProto()->Id);
- return false;
- }
- triggered_spell_id = auraSpellInfo->EffectTriggerSpell[1];
- break; // fall through to normal cast
- }
- break;
- }
- case SPELLFAMILY_WARLOCK:
- {
- // Pyroclasm
- if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000 && auraSpellInfo->SpellIconID==1137)
- {
- // last case for Hellfire that damage caster also but don't must stun caster
- if( pVictim == this )
- return false;
+ // Calculate chance = baseChance / tick
+ float chance = 0;
+ switch (auraSpellInfo->Id)
+ {
+ case 18096: chance = 13.0f / tick; break;
+ case 18073: chance = 26.0f / tick; break;
+ }
+ // Roll chance
+ if (!roll_chance_f(chance))
+ return false;
- // custom chance
- float chance = 0;
- switch (triggeredByAura->GetId())
- {
- case 18096: chance = 13.0f; break;
- case 18073: chance = 26.0f; break;
+ trigger_spell_id = 18093;
}
- if (!roll_chance_f(chance))
- return false;
-
- // Pyroclasm (instead non-existed triggered spell)
- triggered_spell_id = 18093;
- target = pVictim;
- break;
- }
- // Drain Soul
- if(auraSpellInfo->SpellFamilyFlags & 0x0000000000004000)
- {
- bool found = false;
- Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
- for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
+ // Drain Soul
+ else if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000)
{
- //Improved Drain Soul
- if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
+ Unit::AuraEffectList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
+ for(Unit::AuraEffectList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
{
- int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this);
- basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100;
- // Drain Soul
- CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- break;
+ if ((*i)->GetMiscValue() == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
+ {
+ int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this);
+ // Drain Soul
+ CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
+ break;
+ }
}
+ // Not remove charge (aura removed on death in any cases)
+ // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
+ return false;
}
- // Not remove charge (aura removed on death in any cases)
- // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
- return false;
- }
- break;
- }
- case SPELLFAMILY_PRIEST:
- {
- //Blessed Recovery
- if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL && auraSpellInfo->SpellIconID==1875)
- {
- switch (triggeredByAura->GetSpellProto()->Id)
+ // Nether Protection
+ else if (auraSpellInfo->SpellIconID == 1985)
{
- case 27811: triggered_spell_id = 27813; break;
- case 27815: triggered_spell_id = 27817; break;
- case 27816: triggered_spell_id = 27818; break;
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id);
+ if (!procSpell)
return false;
+ switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
+ {
+ case SPELL_SCHOOL_NORMAL:
+ return false; // ignore
+ case SPELL_SCHOOL_HOLY: trigger_spell_id = 54370; break;
+ case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break;
+ case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break;
+ case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break;
+ case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break;
+ case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break;
+ default:
+ return false;
+ }
}
-
- int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100;
- basepoints0 = heal_amount/3;
- target = this;
break;
}
- // Shadowguard
- if((auraSpellInfo->SpellFamilyFlags & 0x80000000LL) && auraSpellInfo->SpellVisual==7958)
- {
- switch(triggeredByAura->GetSpellProto()->Id)
- {
- case 18137:
- triggered_spell_id = 28377; break; // Rank 1
- case 19308:
- triggered_spell_id = 28378; break; // Rank 2
- case 19309:
- triggered_spell_id = 28379; break; // Rank 3
- case 19310:
- triggered_spell_id = 28380; break; // Rank 4
- case 19311:
- triggered_spell_id = 28381; break; // Rank 5
- case 19312:
- triggered_spell_id = 28382; break; // Rank 6
- case 25477:
- triggered_spell_id = 28385; break; // Rank 7
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id);
+ case SPELLFAMILY_PRIEST:
+ {
+ // Greater Heal Refund
+ if (auraSpellInfo->Id==37594)
+ trigger_spell_id = 37595;
+ // Blessed Recovery
+ else if (auraSpellInfo->SpellIconID == 1875)
+ {
+ switch (auraSpellInfo->Id)
+ {
+ case 27811: trigger_spell_id = 27813; break;
+ case 27815: trigger_spell_id = 27817; break;
+ case 27816: trigger_spell_id = 27818; break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR", auraSpellInfo->Id);
return false;
+ }
+ basepoints0 = damage * triggerAmount / 100 / 3;
+ target = this;
}
- target = pVictim;
break;
}
- break;
- }
- case SPELLFAMILY_DRUID:
- {
- switch(auraSpellInfo->Id)
+ case SPELLFAMILY_DRUID:
{
- // Leader of the Pack (triggering Improved Leader of the Pack heal)
- case 24932:
- {
- if (triggeredByAura->GetModifier()->m_amount == 0)
- return false;
- basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
- triggered_spell_id = 34299;
- break;
- };
- // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
- case 37336:
+ // Druid Forms Trinket
+ if (auraSpellInfo->Id==37336)
{
switch(m_form)
{
+ case FORM_NONE: trigger_spell_id = 37344;break;
+ case FORM_CAT: trigger_spell_id = 37341;break;
case FORM_BEAR:
- case FORM_DIREBEAR:
- triggered_spell_id=37340; break;// Ursine Blessing
- case FORM_CAT:
- triggered_spell_id=37341; break;// Feline Blessing
- case FORM_TREE:
- triggered_spell_id=37342; break;// Slyvan Blessing
- case FORM_MOONKIN:
- triggered_spell_id=37343; break;// Lunar Blessing
- case FORM_NONE:
- triggered_spell_id=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
+ case FORM_DIREBEAR: trigger_spell_id = 37340;break;
+ case FORM_TREE: trigger_spell_id = 37342;break;
+ case FORM_MOONKIN: trigger_spell_id = 37343;break;
default:
return false;
}
-
- target = this;
- break;
}
+ //else if (auraSpellInfo->Id==40363)// Entangling Roots ()
+ // trigger_spell_id = ????;
+ break;
}
- break;
- }
- case SPELLFAMILY_ROGUE:
- {
- if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000LL)
+ case SPELLFAMILY_HUNTER:
+ break;
+ case SPELLFAMILY_PALADIN:
{
- switch(auraSpellInfo->SpellIconID)
+ /*
+ // Blessed Life
+ if (auraSpellInfo->SpellIconID == 2137)
{
- // Combat Potency
- case 2260:
+ switch (auraSpellInfo->Id)
{
- // skip non offhand attacks
- if(attackType!=OFF_ATTACK)
+ case 31828: // Rank 1
+ case 31829: // Rank 2
+ case 31830: // Rank 3
+ break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blessed Life", auraSpellInfo->Id);
return false;
- break; // fall through to normal cast
}
}
- }
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL)
- {
- switch(auraSpellInfo->Id)
+ */
+ // Healing Discount
+ if (auraSpellInfo->Id==37705)
{
- // Lightning Capacitor
- case 37657:
- {
- // trinket ProcTriggerSpell but for safe checks for player
- if(!castItem || !pVictim || !pVictim->isAlive() || GetTypeId()!=TYPEID_PLAYER)
- return false;
-
- if(((Player*)this)->HasSpellCooldown(37657))
- return false;
-
- // stacking
- CastSpell(this, 37658, true, castItem, triggeredByAura);
- // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
- ((Player*)this)->AddSpellCooldown(37657,0,time(NULL)+(roll_chance_i(50) ? 2 : 3));
-
- // counting
- Aura * dummy = GetDummyAura(37658);
- if (!dummy)
- return false;
-
- // release at 3 aura in stack
- if(dummy->GetStackAmount() <= 2)
- return true; // main triggered spell casted anyway
-
- RemoveAurasDueToSpell(37658);
- CastSpell(pVictim, 37661, true, castItem, triggeredByAura);
- return true;
- }
- // Healing Discount
- case 37705:
- // Healing Trance (instead non-existed triggered spell)
- triggered_spell_id = 37706;
- target = this;
- break;
- // HoTs on Heals (Fel Reaver's Piston trinket)
- case 38299:
- {
- // at direct heal effect
- if(!procSpell || !IsSpellHaveEffect(procSpell,SPELL_EFFECT_HEAL))
- return false;
-
- // single proc at time
- AuraList const& scAuras = GetSingleCastAuras();
- for(AuraList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr)
- if((*itr)->GetId()==triggered_spell_id)
- return false;
-
- // positive cast at victim instead self
- target = pVictim;
- break;
- }
+ trigger_spell_id = 37706;
+ target = this;
}
- switch(auraSpellInfo->SpellIconID)
+ // Soul Preserver
+ if (auraSpellInfo->Id==60510)
{
- case 241:
- {
- switch(auraSpellInfo->EffectTriggerSpell[0])
- {
- //Illumination
- case 18350:
- {
- if(!procSpell)
- return false;
-
- // procspell is triggered spell but we need mana cost of original casted spell
- uint32 originalSpellId = procSpell->Id;
-
- // Holy Shock
- if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN)
- {
- if(procSpell->SpellFamilyFlags & 0x0001000000000000LL)
- {
- switch(procSpell->Id)
- {
- case 25914: originalSpellId = 20473; break;
- case 25913: originalSpellId = 20929; break;
- case 25903: originalSpellId = 20930; break;
- case 27175: originalSpellId = 27174; break;
- case 33074: originalSpellId = 33072; break;
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
- return false;
- }
- }
- }
-
- SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId);
- if(!originalSpell)
- {
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId);
- return false;
- }
-
- // percent stored in effect 1 (class scripts) base points
- int32 percent = auraSpellInfo->EffectBasePoints[1]+1;
-
- basepoints0 = originalSpell->manaCost*percent/100;
- triggered_spell_id = 20272;
- target = this;
- break;
- }
- }
- break;
- }
+ trigger_spell_id = 60515;
+ target = this;
}
- }
- if(auraSpellInfo->SpellFamilyFlags & 0x00080000)
- {
- switch(auraSpellInfo->SpellIconID)
+ // Illumination
+ else if (auraSpellInfo->SpellIconID==241)
{
- //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
- case 206:
+ if(!procSpell)
+ return false;
+ // procspell is triggered spell but we need mana cost of original casted spell
+ uint32 originalSpellId = procSpell->Id;
+ // Holy Shock heal
+ if(procSpell->SpellFamilyFlags[1] & 0x00010000)
{
- if(!pVictim || !pVictim->isAlive())
- return false;
-
- switch(triggeredByAura->GetSpellProto()->Id)
+ switch(procSpell->Id)
{
- case 20186:
- triggered_spell_id = 20268; // Rank 1
- break;
- case 20354:
- triggered_spell_id = 20352; // Rank 2
- break;
- case 20355:
- triggered_spell_id = 20353; // Rank 3
- break;
- case 27164:
- triggered_spell_id = 27165; // Rank 4
- break;
+ case 25914: originalSpellId = 20473; break;
+ case 25913: originalSpellId = 20929; break;
+ case 25903: originalSpellId = 20930; break;
+ case 27175: originalSpellId = 27174; break;
+ case 33074: originalSpellId = 33072; break;
+ case 48820: originalSpellId = 48824; break;
+ case 48821: originalSpellId = 48825; break;
default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura->GetSpellProto()->Id);
- return false;
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
+ return false;
}
-
- pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID());
- return true; // no hidden cooldown
}
- //Judgement of Light
- case 299:
+ SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId);
+ if(!originalSpell)
{
- if(!pVictim || !pVictim->isAlive())
- return false;
-
- // overwrite non existing triggered spell call in spell.dbc
- switch(triggeredByAura->GetSpellProto()->Id)
- {
- case 20185:
- triggered_spell_id = 20267; // Rank 1
- break;
- case 20344:
- triggered_spell_id = 20341; // Rank 2
- break;
- case 20345:
- triggered_spell_id = 20342; // Rank 3
- break;
- case 20346:
- triggered_spell_id = 20343; // Rank 4
- break;
- case 27162:
- triggered_spell_id = 27163; // Rank 5
- break;
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura->GetSpellProto()->Id);
- return false;
- }
- pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID());
- return true; // no hidden cooldown
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId);
+ return false;
}
+ // percent stored in effect 1 (class scripts) base points
+ int32 cost = originalSpell->manaCost + originalSpell->ManaCostPercentage * GetCreateMana() / 100;
+ basepoints0 = cost*auraSpellInfo->CalculateSimpleValue(1)/100;
+ trigger_spell_id = 20272;
+ target = this;
}
- }
- // custom check for proc spell
- switch(auraSpellInfo->Id)
- {
- // Bonus Healing (item spell)
- case 40971:
+ // Lightning Capacitor
+ else if (auraSpellInfo->Id==37657)
{
if(!pVictim || !pVictim->isAlive())
return false;
+ // stacking
+ CastSpell(this, 37658, true, NULL, triggeredByAura);
- // bonus if health < 50%
- if(pVictim->GetHealth() >= pVictim->GetMaxHealth()*triggeredByAura->GetModifier()->m_amount/100)
+ AuraEffect * dummy = GetDummyAura(37658);
+ // release at 3 aura in stack (cont contain in basepoint of trigger aura)
+ if(!dummy || dummy->GetParentAura()->GetStackAmount() < triggerAmount)
return false;
- // cast at target positive spell
+ RemoveAurasDueToSpell(37658);
+ trigger_spell_id = 37661;
target = pVictim;
- break;
}
- }
- switch(triggered_spell_id)
- {
- // Seal of Command
- case 20424:
- // prevent chain of triggered spell from same triggered spell
- if(procSpell && procSpell->Id==20424)
+ // Thunder Capacitor
+ else if (auraSpellInfo->Id == 54841)
+ {
+ if(!pVictim || !pVictim->isAlive())
return false;
- break;
+ // stacking
+ CastSpell(this, 54842, true, NULL, triggeredByAura);
+
+ // counting
+ AuraEffect * dummy = GetDummyAura(54842);
+ // release at 3 aura in stack (cont contain in basepoint of trigger aura)
+ if(!dummy || dummy->GetParentAura()->GetStackAmount() < triggerAmount)
+ return false;
+
+ RemoveAurasDueToSpell(54842);
+ trigger_spell_id = 54843;
+ target = pVictim;
+ }
+ break;
}
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000)
+ case SPELLFAMILY_SHAMAN:
{
- switch(auraSpellInfo->SpellIconID)
+ // Lightning Shield (overwrite non existing triggered spell call in spell.dbc
+ if(auraSpellInfo->SpellFamilyFlags[0] & 0x400)
{
- case 19:
- {
- switch(auraSpellInfo->Id)
- {
- case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
- {
- // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
- triggered_spell_id = 23552;
- target = pVictim;
- break;
- }
- case 23552: // Lightning Shield - trigger shield damage
- {
- // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
- triggered_spell_id = 27635;
- target = pVictim;
- break;
- }
- }
- break;
- }
- // Mana Surge (Shaman T1 bonus)
- case 87:
+ switch(auraSpellInfo->Id)
{
- if(!procSpell)
- return false;
-
- basepoints0 = procSpell->manaCost * 35/100;
- triggered_spell_id = 23571;
- target = this;
- break;
+ case 324: // Rank 1
+ trigger_spell_id = 26364; break;
+ case 325: // Rank 2
+ trigger_spell_id = 26365; break;
+ case 905: // Rank 3
+ trigger_spell_id = 26366; break;
+ case 945: // Rank 4
+ trigger_spell_id = 26367; break;
+ case 8134: // Rank 5
+ trigger_spell_id = 26369; break;
+ case 10431: // Rank 6
+ trigger_spell_id = 26370; break;
+ case 10432: // Rank 7
+ trigger_spell_id = 26363; break;
+ case 25469: // Rank 8
+ trigger_spell_id = 26371; break;
+ case 25472: // Rank 9
+ trigger_spell_id = 26372; break;
+ case 49280: // Rank 10
+ trigger_spell_id = 49278; break;
+ case 49281: // Rank 11
+ trigger_spell_id = 49279; break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield", auraSpellInfo->Id);
+ return false;
}
- //Nature's Guardian
- case 2013:
- {
- if(GetTypeId()!=TYPEID_PLAYER)
- return false;
-
- // damage taken that reduces below 30% health
- // does NOT mean you must have been >= 30% before
- if (10*(int32(GetHealth())-int32(damage)) >= 3*GetMaxHealth())
- return false;
-
- triggered_spell_id = 31616;
+ }
+ // Lightning Shield (The Ten Storms set)
+ else if (auraSpellInfo->Id == 23551)
+ {
+ trigger_spell_id = 23552;
+ target = pVictim;
+ }
+ // Damage from Lightning Shield (The Ten Storms set)
+ else if (auraSpellInfo->Id == 23552)
+ trigger_spell_id = 27635;
+ // Mana Surge (The Earthfury set)
+ else if (auraSpellInfo->Id == 23572)
+ {
+ if(!procSpell)
+ return false;
+ basepoints0 = procSpell->manaCost * 35 / 100;
+ trigger_spell_id = 23571;
+ target = this;
+ }
+ // Nature's Guardian
+ else if (auraSpellInfo->SpellIconID == 2013)
+ {
+ // Check health condition - should drop to less 30% (damage deal after this!)
+ if (!(10*(int32(GetHealth() - damage)) < 3 * GetMaxHealth()))
+ return false;
- // need check cooldown now
- if( cooldown && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
- return false;
+ if(pVictim && pVictim->isAlive())
+ pVictim->getThreatManager().modifyThreatPercent(this,-10);
- basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
- target = this;
- if(pVictim && pVictim->isAlive())
- pVictim->getThreatManager().modifyThreatPercent(this,-10);
- break;
- }
+ basepoints0 = triggerAmount * GetMaxHealth() / 100;
+ trigger_spell_id = 31616;
+ target = this;
}
- }
-
- // Water Shield (we can't set cooldown for main spell - it's player casted spell
- if((auraSpellInfo->SpellFamilyFlags & 0x0000002000000000LL) && auraSpellInfo->SpellVisual==7358)
- {
- target = this;
break;
}
-
- // Lightning Shield
- if((auraSpellInfo->SpellFamilyFlags & 0x00000400) && auraSpellInfo->SpellVisual==37)
- {
- // overwrite non existing triggered spell call in spell.dbc
- switch(triggeredByAura->GetSpellProto()->Id)
- {
- case 324:
- triggered_spell_id = 26364; break; // Rank 1
- case 325:
- triggered_spell_id = 26365; break; // Rank 2
- case 905:
- triggered_spell_id = 26366; break; // Rank 3
- case 945:
- triggered_spell_id = 26367; break; // Rank 4
- case 8134:
- triggered_spell_id = 26369; break; // Rank 5
- case 10431:
- triggered_spell_id = 26370; break; // Rank 6
- case 10432:
- triggered_spell_id = 26363; break; // Rank 7
- case 25469:
- triggered_spell_id = 26371; break; // Rank 8
- case 25472:
- triggered_spell_id = 26372; break; // Rank 9
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id);
+ case SPELLFAMILY_DEATHKNIGHT:
+ {
+ // Acclimation
+ if (auraSpellInfo->SpellIconID == 1930)
+ {
+ if (!procSpell)
return false;
+ switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
+ {
+ case SPELL_SCHOOL_NORMAL:
+ return false; // ignore
+ case SPELL_SCHOOL_HOLY: trigger_spell_id = 50490; break;
+ case SPELL_SCHOOL_FIRE: trigger_spell_id = 50362; break;
+ case SPELL_SCHOOL_NATURE: trigger_spell_id = 50488; break;
+ case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break;
+ case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; break;
+ case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break;
+ default:
+ return false;
+ }
+ }
+ // Blood Presence
+ else if (auraSpellInfo->Id == 48266)
+ {
+ if (GetTypeId() != TYPEID_PLAYER)
+ return false;
+ if (!((Player*)this)->isHonorOrXPTarget(pVictim))
+ return false;
+ trigger_spell_id = 50475;
+ basepoints0 = damage * triggerAmount / 100;
}
-
- target = pVictim;
break;
}
- break;
- }
- }
-
- // standard non-dummy case
- if(!triggered_spell_id)
- {
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
- return false;
- }
-
- SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
-
- if(!triggerEntry)
- {
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex(),triggered_spell_id);
- return false;
- }
-
- // not allow proc extra attack spell at extra attack
- if( m_extraAttacks && IsSpellHaveEffect(triggerEntry,SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
- return false;
-
- if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
- return false;
-
- // default case
- if(!target || target!=this && !target->isAlive())
- return false;
-
- if(basepoints0)
- CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
- else
- CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
-
- if( cooldown && GetTypeId()==TYPEID_PLAYER )
- ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
-
- return true;
-}
-*/
-
-bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown)
-{
- // Get triggered aura spell info
- SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
-
- // Basepoints of trigger aura
- int32 triggerAmount = triggeredByAura->GetModifier()->m_amount;
-
- // Set trigger spell id, target, custom basepoints
- uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
- Unit* target = NULL;
- int32 basepoints0 = 0;
-
- Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
- ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
-
- // check if triggering spell can stack with current target's auras (if not - don't proc)
- AuraMap::iterator i,next;
- for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
- {
- next = i;
- ++next;
- if (!(*i).second) continue;
- if ( (*i).second->GetSpellProto()->Id == trigger_spell_id) continue;
- if (spellmgr.IsNoStackSpellDueToSpell(trigger_spell_id, (*i).second->GetSpellProto()->Id, (pVictim == this)))
- return false;
- }
-
- // Try handle uncnown trigger spells
- if (sSpellStore.LookupEntry(trigger_spell_id)==NULL)
- switch (auraSpellInfo->SpellFamilyName)
- {
- //=====================================================================
- // Generic class
- // ====================================================================
- // .....
- //=====================================================================
- case SPELLFAMILY_GENERIC:
-// if (auraSpellInfo->Id==34082) // Advantaged State (DND)
-// trigger_spell_id = ???;
- if (auraSpellInfo->Id == 23780) // Aegis of Preservation (Aegis of Preservation trinket)
- trigger_spell_id = 23781;
-// else if (auraSpellInfo->Id==43504) // Alterac Valley OnKill Proc Aura
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==37030) // Chaotic Temperament
-// trigger_spell_id = ;
- else if (auraSpellInfo->Id==43820) // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket)
- {
- // Pct value stored in dummy
- basepoints0 = pVictim->GetCreateHealth() * auraSpellInfo->EffectBasePoints[1] / 100;
- target = pVictim;
- break;
- }
-// else if (auraSpellInfo->Id==41248) // Consuming Strikes
-// trigger_spell_id = 41249;
-// else if (auraSpellInfo->Id==41054) // Copy Weapon
-// trigger_spell_id = 41055;
-// else if (auraSpellInfo->Id==31255) // Deadly Swiftness (Rank 1)
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==5301) // Defensive State (DND)
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==13358) // Defensive State (DND)
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==16092) // Defensive State (DND)
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==24949) // Defensive State 2 (DND)
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==40329) // Demo Shout Sensor
-// trigger_spell_id = ;
- // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher)
- else if (auraSpellInfo->Id == 33896)
- trigger_spell_id = 33898;
-// else if (auraSpellInfo->Id==18943) // Double Attack
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==19194) // Double Attack
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==19817) // Double Attack
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==19818) // Double Attack
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==22835) // Drunken Rage
-// trigger_spell_id = 14822;
- /*
- else if (auraSpellInfo->SpellIconID==191) // Elemental Response
- {
- switch (auraSpellInfo->Id && auraSpellInfo->AttributesEx==0)
- {
- case 34191:
- case 34329:
- case 34524:
- case 34582:
- case 36733:break;
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Elemental Response",auraSpellInfo->Id);
- return false;
- }
- //This generic aura self-triggers a different spell for each school of magic that lands on the wearer:
- switch (procSpell->School)
- {
- case SPELL_SCHOOL_FIRE: trigger_spell_id = 34192;break;//Fire: 34192
- case SPELL_SCHOOL_FROST: trigger_spell_id = 34193;break;//Frost: 34193
- case SPELL_SCHOOL_ARCANE: trigger_spell_id = 34194;break;//Arcane: 34194
- case SPELL_SCHOOL_NATURE: trigger_spell_id = 34195;break;//Nature: 34195
- case SPELL_SCHOOL_SHADOW: trigger_spell_id = 34196;break;//Shadow: 34196
- case SPELL_SCHOOL_HOLY: trigger_spell_id = 34197;break;//Holy: 34197
- case SPELL_SCHOOL_NORMAL: trigger_spell_id = 34198;break;//Physical: 34198
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u Elemental Response wrong school",auraSpellInfo->Id);
- return false;
- }
- }*/
-// else if (auraSpellInfo->Id==6542) // Enraged Defense
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==40364) // Entangling Roots Sensor
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==33207) // Gossip NPC Periodic - Fidget
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==35321) // Gushing Wound
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==38363) // Gushing Wound
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==39215) // Gushing Wound
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==40250) // Improved Duration
-// trigger_spell_id = ;
- else if (auraSpellInfo->Id==27522) // Mana Drain Trigger
- {
- // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target.
- if (this && this->isAlive())
- CastSpell(this, 29471, true, castItem, triggeredByAura);
- if (pVictim && pVictim->isAlive())
- CastSpell(pVictim, 27526, true, castItem, triggeredByAura);
- return true;
- }
- else if (auraSpellInfo->Id==24905) // Moonkin Form (Passive)
- {
- // Elune's Touch (instead non-existed triggered spell) 30% from AP
- trigger_spell_id = 33926;
- basepoints0 = GetTotalAttackPowerValue(BASE_ATTACK) * 30 / 100;
- target = this;
- }
-// else if (auraSpellInfo->Id==43453) // Rune Ward
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==7137) // Shadow Charge (Rank 1)
-// trigger_spell_id = ;
- // Shaleskin (Shaleskin Flayer, Shaleskin Ripper) 30023 trigger
-// else if (auraSpellInfo->Id==36576)
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==34783) // Spell Reflection
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==36096) // Spell Reflection
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==36207) // Steal Weapon
-// trigger_spell_id = ;
-// else if (auraSpellInfo->Id==35205) // Vanish
- break;
- //=====================================================================
- // Mage
- //=====================================================================
- // Blazing Speed (Rank 1,2) trigger = 18350
- //=====================================================================
- case SPELLFAMILY_MAGE:
- // Blazing Speed
- if (auraSpellInfo->SpellIconID == 2127)
- {
- switch (auraSpellInfo->Id)
- {
- case 31641: // Rank 1
- case 31642: // Rank 2
- trigger_spell_id = 31643;
- break;
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blazing Speed",auraSpellInfo->Id);
- return false;
- }
- }
- break;
- //=====================================================================
- // Warrior
- //=====================================================================
- // Rampage (Rank 1-3) trigger = 18350
- //=====================================================================
- case SPELLFAMILY_WARRIOR:
- // Rampage
- if (auraSpellInfo->SpellIconID == 2006 && auraSpellInfo->SpellFamilyFlags==0x100000)
- {
- switch(auraSpellInfo->Id)
- {
- case 29801: trigger_spell_id = 30029; break; // Rank 1
- case 30030: trigger_spell_id = 30031; break; // Rank 2
- case 30033: trigger_spell_id = 30032; break; // Rank 3
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in Rampage",auraSpellInfo->Id);
- return false;
- }
- }
- break;
- //=====================================================================
- // Warlock
- //=====================================================================
- // Pyroclasm trigger = 18350
- // Drain Soul (Rank 1-5) trigger = 0
- //=====================================================================
- case SPELLFAMILY_WARLOCK:
- {
- // Pyroclasm
- if (auraSpellInfo->SpellIconID == 1137)
- {
- if(!pVictim || !pVictim->isAlive() || pVictim == this || procSpell == NULL)
- return false;
- // Calculate spell tick count for spells
- uint32 tick = 1; // Default tick = 1
-
- // Hellfire have 15 tick
- if (procSpell->SpellFamilyFlags&0x0000000000000040LL)
- tick = 15;
- // Rain of Fire have 4 tick
- else if (procSpell->SpellFamilyFlags&0x0000000000000020LL)
- tick = 4;
- else
- return false;
-
- // Calculate chance = baseChance / tick
- float chance = 0;
- switch (auraSpellInfo->Id)
- {
- case 18096: chance = 13.0f / tick; break;
- case 18073: chance = 26.0f / tick; break;
- }
- // Roll chance
- if (!roll_chance_f(chance))
- return false;
-
- trigger_spell_id = 18093;
- }
- // Drain Soul
- else if (auraSpellInfo->SpellFamilyFlags & 0x0000000000004000LL)
- {
- Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
- for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
- {
- if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
- {
- int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this);
- basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100;
- }
- }
- if ( basepoints0 == 0 )
- return false;
- trigger_spell_id = 18371;
- }
- break;
- }
- //=====================================================================
- // Priest
- //=====================================================================
- // Greater Heal Refund trigger = 18350
- // Blessed Recovery (Rank 1-3) trigger = 18350
- // Shadowguard (1-7) trigger = 28376
- //=====================================================================
- case SPELLFAMILY_PRIEST:
- {
- // Greater Heal Refund
- if (auraSpellInfo->Id==37594)
- trigger_spell_id = 37595;
- // Shadowguard
- else if(auraSpellInfo->SpellFamilyFlags==0x100080000000LL && auraSpellInfo->SpellVisual==7958)
- {
- switch(auraSpellInfo->Id)
- {
- case 18137: trigger_spell_id = 28377; break; // Rank 1
- case 19308: trigger_spell_id = 28378; break; // Rank 2
- case 19309: trigger_spell_id = 28379; break; // Rank 3
- case 19310: trigger_spell_id = 28380; break; // Rank 4
- case 19311: trigger_spell_id = 28381; break; // Rank 5
- case 19312: trigger_spell_id = 28382; break; // Rank 6
- case 25477: trigger_spell_id = 28385; break; // Rank 7
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG", auraSpellInfo->Id);
- return false;
- }
- }
- // Blessed Recovery
- else if (auraSpellInfo->SpellIconID == 1875)
- {
- switch (auraSpellInfo->Id)
- {
- case 27811: trigger_spell_id = 27813; break;
- case 27815: trigger_spell_id = 27817; break;
- case 27816: trigger_spell_id = 27818; break;
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR", auraSpellInfo->Id);
- return false;
- }
- basepoints0 = damage * triggerAmount / 100 / 3;
- target = this;
- }
- break;
- }
- //=====================================================================
- // Druid
- // ====================================================================
- // Druid Forms Trinket trigger = 18350
- // Entangling Roots trigger = 30023
- // Leader of the Pack trigger = 18350
- //=====================================================================
- case SPELLFAMILY_DRUID:
- {
- // Druid Forms Trinket
- if (auraSpellInfo->Id==37336)
- {
- switch(m_form)
- {
- case 0: trigger_spell_id = 37344;break;
- case FORM_CAT: trigger_spell_id = 37341;break;
- case FORM_BEAR:
- case FORM_DIREBEAR: trigger_spell_id = 37340;break;
- case FORM_TREE: trigger_spell_id = 37342;break;
- case FORM_MOONKIN: trigger_spell_id = 37343;break;
- default:
- return false;
- }
- }
-// else if (auraSpellInfo->Id==40363)// Entangling Roots ()
-// trigger_spell_id = ????;
- // Leader of the Pack
- else if (auraSpellInfo->Id == 24932)
- {
- if (triggerAmount == 0)
- return false;
- basepoints0 = triggerAmount * GetMaxHealth() / 100;
- trigger_spell_id = 34299;
- }
- break;
- }
- //=====================================================================
- // Hunter
- // ====================================================================
- // ......
- //=====================================================================
- case SPELLFAMILY_HUNTER:
- break;
- //=====================================================================
- // Paladin
- // ====================================================================
- // Blessed Life trigger = 31934
- // Healing Discount trigger = 18350
- // Illumination (Rank 1-5) trigger = 18350
- // Judgement of Light (Rank 1-5) trigger = 5373
- // Judgement of Wisdom (Rank 1-4) trigger = 1826
- // Lightning Capacitor trigger = 18350
- //=====================================================================
- case SPELLFAMILY_PALADIN:
- {
- /* // Blessed Life
- if (auraSpellInfo->SpellIconID == 2137)
- {
- switch (auraSpellInfo->Id)
- {
- case 31828: // Rank 1
- case 31829: // Rank 2
- case 31830: // Rank 3
+ default:
break;
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blessed Life", auraSpellInfo->Id);
- return false;
- }
- }*/
- // Healing Discount
- if (auraSpellInfo->Id==37705)
- {
- trigger_spell_id = 37706;
- target = this;
- }
- // Judgement of Light and Judgement of Wisdom
- else if (auraSpellInfo->SpellFamilyFlags & 0x0000000000080000LL)
- {
- switch (auraSpellInfo->Id)
- {
- // Judgement of Light
- case 20185: trigger_spell_id = 20267;break; // Rank 1
- case 20344: trigger_spell_id = 20341;break; // Rank 2
- case 20345: trigger_spell_id = 20342;break; // Rank 3
- case 20346: trigger_spell_id = 20343;break; // Rank 4
- case 27162: trigger_spell_id = 27163;break; // Rank 5
- // Judgement of Wisdom
- case 20186: trigger_spell_id = 20268;break; // Rank 1
- case 20354: trigger_spell_id = 20352;break; // Rank 2
- case 20355: trigger_spell_id = 20353;break; // Rank 3
- case 27164: trigger_spell_id = 27165;break; // Rank 4
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Judgement of Light/Wisdom", auraSpellInfo->Id);
- return false;
- }
- pVictim->CastSpell(pVictim, trigger_spell_id, true, castItem, triggeredByAura);
- return true; // no hidden cooldown
- }
- // Illumination
- else if (auraSpellInfo->SpellIconID==241)
- {
- if(!procSpell)
- return false;
- // procspell is triggered spell but we need mana cost of original casted spell
- uint32 originalSpellId = procSpell->Id;
- // Holy Shock
- if(procSpell->SpellFamilyFlags & 0x00200000)
- {
- switch(procSpell->Id)
- {
- case 25914: originalSpellId = 20473; break;
- case 25913: originalSpellId = 20929; break;
- case 25903: originalSpellId = 20930; break;
- case 27175: originalSpellId = 27174; break;
- case 33074: originalSpellId = 33072; break;
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
- return false;
- }
- }
- SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId);
- if(!originalSpell)
- {
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId);
- return false;
- }
- // percent stored in effect 1 (class scripts) base points
- basepoints0 = originalSpell->manaCost*(auraSpellInfo->EffectBasePoints[1]+1)/100;
- trigger_spell_id = 20272;
- target = this;
- }
- // Lightning Capacitor
- else if (auraSpellInfo->Id==37657)
- {
- if(!pVictim || !pVictim->isAlive())
- return false;
- // stacking
- CastSpell(this, 37658, true, NULL, triggeredByAura);
- // counting
- Aura * dummy = GetDummyAura(37658);
- if (!dummy)
- return false;
- // release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(dummy->GetStackAmount() <= 2)
- return false;
-
- RemoveAurasDueToSpell(37658);
- trigger_spell_id = 37661;
- target = pVictim;
- }
- break;
- }
- //=====================================================================
- // Shaman
- //====================================================================
- // Lightning Shield trigger = 18350
- // Mana Surge trigger = 18350
- // Nature's Guardian (Rank 1-5) trigger = 18350
- //=====================================================================
- case SPELLFAMILY_SHAMAN:
- {
- //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
- if(auraSpellInfo->SpellFamilyFlags==0x00000400 && auraSpellInfo->SpellVisual==37)
- {
- switch(auraSpellInfo->Id)
- {
- case 324: trigger_spell_id = 26364; break; // Rank 1
- case 325: trigger_spell_id = 26365; break; // Rank 2
- case 905: trigger_spell_id = 26366; break; // Rank 3
- case 945: trigger_spell_id = 26367; break; // Rank 4
- case 8134: trigger_spell_id = 26369; break; // Rank 5
- case 10431: trigger_spell_id = 26370; break; // Rank 6
- case 10432: trigger_spell_id = 26363; break; // Rank 7
- case 25469: trigger_spell_id = 26371; break; // Rank 8
- case 25472: trigger_spell_id = 26372; break; // Rank 9
- default:
- sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield", auraSpellInfo->Id);
- return false;
- }
- }
- // Lightning Shield (The Ten Storms set)
- else if (auraSpellInfo->Id == 23551)
- {
- trigger_spell_id = 23552;
- target = pVictim;
- }
- // Damage from Lightning Shield (The Ten Storms set)
- else if (auraSpellInfo->Id == 23552)
- trigger_spell_id = 27635;
- // Mana Surge (The Earthfury set)
- else if (auraSpellInfo->Id == 23572)
- {
- if(!procSpell)
- return false;
- basepoints0 = procSpell->manaCost * 35 / 100;
- trigger_spell_id = 23571;
- target = this;
- }
- else if (auraSpellInfo->SpellIconID == 2013) //Nature's Guardian
- {
- // Check health condition - should drop to less 30% (damage deal after this!)
- if (!(10*(int32(GetHealth() - damage)) < 3 * GetMaxHealth()))
- return false;
-
- if(pVictim && pVictim->isAlive())
- pVictim->getThreatManager().modifyThreatPercent(this,-10);
-
- basepoints0 = triggerAmount * GetMaxHealth() / 100;
- trigger_spell_id = 31616;
- target = this;
- }
- break;
- }
- // default
- default:
- break;
+ }
}
// All ok. Check current trigger spell
@@ -7466,6 +7438,15 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return false;
break;
}
+ // Rapid Recuperation
+ case 53228:
+ case 53232:
+ {
+ // This effect only from Rapid Fire (ability cast)
+ if (!(procSpell->SpellFamilyFlags[0] & 0x20))
+ return false;
+ break;
+ }
}
// Costum basepoints/target for exist spell
@@ -7495,11 +7476,16 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
// Need add combopoint AFTER finish movie (or they dropped in finish phase)
break;
}
+ // Bloodthirst (($m/100)% of max health)
+ case 23880:
+ {
+ basepoints0 = int32(GetMaxHealth() * triggerAmount / 100);
+ break;
+ }
// Shamanistic Rage triggered spell
case 30824:
{
basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100);
- trigger_spell_id = 30824;
break;
}
// Enlightenment (trigger only from mana cost spells)
@@ -7509,6 +7495,59 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return false;
break;
}
+ // Brain Freeze
+ case 57761:
+ {
+ if(!procSpell)
+ return false;
+ // For trigger from Blizzard need exist Improved Blizzard
+ if (procSpell->SpellFamilyName==SPELLFAMILY_MAGE && procSpell->SpellFamilyFlags[0] & 0x80)
+ {
+ bool found = false;
+ AuraEffectList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
+ {
+ int32 script = (*i)->GetMiscValue();
+ if(script==836 || script==988 || script==989)
+ {
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ return false;
+ }
+ break;
+ }
+ // Astral Shift
+ case 52179:
+ {
+ if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim)
+ return false;
+
+ // Need stun, fear or silence mechanic
+ if (!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_SILENCE)|(1<<MECHANIC_STUN)|(1<<MECHANIC_FEAR))))
+ return false;
+ break;
+ }
+ // Burning Determination
+ case 54748:
+ {
+ if(!procSpell)
+ return false;
+ // Need Interrupt or Silenced mechanic
+ if (!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_INTERRUPT)|(1<<MECHANIC_SILENCE))))
+ return false;
+ break;
+ }
+ // Lock and Load
+ case 56453:
+ {
+ // Proc only from trap activation (from periodic proc another aura of this spell)
+ if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION) || !roll_chance_i(triggerAmount))
+ return false;
+ break;
+ }
}
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
@@ -7535,15 +7574,15 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return true;
}
-bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown)
+bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, AuraEffect *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown)
{
- int32 scriptId = triggeredByAura->GetModifier()->m_miscvalue;
+ int32 scriptId = triggeredByAura->GetMiscValue();
if(!pVictim || !pVictim->isAlive())
return false;
- Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
- ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
+ Item* castItem = triggeredByAura->GetParentAura()->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
+ ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetParentAura()->GetCastItemGUID()) : NULL;
uint32 triggered_spell_id = 0;
@@ -7551,21 +7590,21 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAur
{
case 836: // Improved Blizzard (Rank 1)
{
- if (!procSpell || procSpell->SpellVisual!=9487)
+ if (!procSpell || procSpell->SpellVisual[0]!=9487)
return false;
triggered_spell_id = 12484;
break;
}
case 988: // Improved Blizzard (Rank 2)
{
- if (!procSpell || procSpell->SpellVisual!=9487)
+ if (!procSpell || procSpell->SpellVisual[0]!=9487)
return false;
triggered_spell_id = 12485;
break;
}
case 989: // Improved Blizzard (Rank 3)
{
- if (!procSpell || procSpell->SpellVisual!=9487)
+ if (!procSpell || procSpell->SpellVisual[0]!=9487)
return false;
triggered_spell_id = 12486;
break;
@@ -7602,6 +7641,29 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAur
case 5497: // Improved Mana Gems (Serpent-Coil Braid)
triggered_spell_id = 37445; // Mana Surge
break;
+ case 8152: // Serendipity
+ {
+ // if heal your target over maximum health
+ if (pVictim->GetHealth() + damage < pVictim->GetMaxHealth())
+ return false;
+ int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
+ int32 basepoints0 = cost * triggeredByAura->GetAmount()/100;
+ CastCustomSpell(this, 47762, &basepoints0, 0, 0, true, 0, triggeredByAura);
+ return true;
+ }
+ // Rapture
+ case 7556: // Rank 1
+ case 7555: // Rank 2
+ case 7554: // Rank 3
+ case 7553: // Rank 4
+ case 7552: // Rank 5
+ {
+ int32 basepoints0 = ((getLevel() * (-0.2) + 18) / 1000000) * damage * GetMaxPower(POWER_MANA);
+ if(basepoints0 > (GetMaxPower(POWER_MANA) / 100) * (triggeredByAura->GetAmount() / 10))
+ basepoints0 = (GetMaxPower(POWER_MANA) / 100) * (triggeredByAura->GetAmount() / 10);
+ CastCustomSpell(this, 47755, &basepoints0, 0, 0, true, 0, triggeredByAura);
+ return true;
+ }
}
// not processed
@@ -7693,6 +7755,8 @@ FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
bool Unit::IsHostileTo(Unit const* unit) const
{
+ if(!unit)
+ return false;
// always non-hostile to self
if(unit==this)
return false;
@@ -7743,11 +7807,11 @@ bool Unit::IsHostileTo(Unit const* unit) const
return false;
// Sanctuary
- if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY))
+ if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY))
return false;
// PvP FFA state
- if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP))
+ if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
return true;
//= PvP states
@@ -7772,28 +7836,31 @@ bool Unit::IsHostileTo(Unit const* unit) const
if(tester->GetTypeId()==TYPEID_PLAYER)
{
// forced reaction
- ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
- if(forceItr!=((Player*)tester)->m_forcedReactions.end())
- return forceItr->second <= REP_HOSTILE;
-
- // if faction have reputation then hostile state for tester at 100% dependent from at_war state
- if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
- if(raw_target_faction->reputationListID >=0)
- if(FactionState const* factionState = ((Player*)tester)->GetFactionState(raw_target_faction))
+ if(target_faction->faction)
+ {
+ if(ReputationRank const* force =((Player*)tester)->GetReputationMgr().GetForcedRankIfAny(target_faction))
+ return *force <= REP_HOSTILE;
+
+ // if faction have reputation then hostile state for tester at 100% dependent from at_war state
+ if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
+ if(FactionState const* factionState = ((Player*)tester)->GetReputationMgr().GetState(raw_target_faction))
return (factionState->Flags & FACTION_FLAG_AT_WAR);
+ }
}
// CvP forced reaction and reputation case
else if(target->GetTypeId()==TYPEID_PLAYER)
{
// forced reaction
- ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction);
- if(forceItr!=((Player const*)target)->m_forcedReactions.end())
- return forceItr->second <= REP_HOSTILE;
+ if(tester_faction->faction)
+ {
+ if(ReputationRank const* force = ((Player*)target)->GetReputationMgr().GetForcedRankIfAny(tester_faction))
+ return *force <= REP_HOSTILE;
- // apply reputation state
- FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
- if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
- return ((Player const*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE;
+ // apply reputation state
+ FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
+ if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
+ return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) <= REP_HOSTILE;
+ }
}
// common faction based case (CvC,PvC,CvP)
@@ -7852,11 +7919,11 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
return true;
// Sanctuary
- if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY))
+ if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY))
return true;
// PvP FFA state
- if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP))
+ if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
return false;
//= PvP states
@@ -7881,28 +7948,31 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
if(tester->GetTypeId()==TYPEID_PLAYER)
{
// forced reaction
- ForcedReactions::const_iterator forceItr = ((Player const*)tester)->m_forcedReactions.find(target_faction->faction);
- if(forceItr!=((Player const*)tester)->m_forcedReactions.end())
- return forceItr->second >= REP_FRIENDLY;
+ if(target_faction->faction)
+ {
+ if(ReputationRank const* force =((Player*)tester)->GetReputationMgr().GetForcedRankIfAny(target_faction))
+ return *force >= REP_FRIENDLY;
- // if faction have reputation then friendly state for tester at 100% dependent from at_war state
- if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
- if(raw_target_faction->reputationListID >=0)
- if(FactionState const* FactionState = ((Player*)tester)->GetFactionState(raw_target_faction))
- return !(FactionState->Flags & FACTION_FLAG_AT_WAR);
+ // if faction have reputation then friendly state for tester at 100% dependent from at_war state
+ if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
+ if(FactionState const* factionState = ((Player*)tester)->GetReputationMgr().GetState(raw_target_faction))
+ return !(factionState->Flags & FACTION_FLAG_AT_WAR);
+ }
}
// CvP forced reaction and reputation case
else if(target->GetTypeId()==TYPEID_PLAYER)
{
// forced reaction
- ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction);
- if(forceItr!=((Player const*)target)->m_forcedReactions.end())
- return forceItr->second >= REP_FRIENDLY;
+ if(tester_faction->faction)
+ {
+ if(ReputationRank const* force =((Player*)target)->GetReputationMgr().GetForcedRankIfAny(tester_faction))
+ return *force >= REP_FRIENDLY;
- // apply reputation state
- if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction))
- if(raw_tester_faction->reputationListID >=0 )
- return ((Player const*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY;
+ // apply reputation state
+ if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction))
+ if(raw_tester_faction->reputationListID >=0 )
+ return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) >= REP_FRIENDLY;
+ }
}
// common faction based case (CvC,PvC,CvP)
@@ -7912,7 +7982,7 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
bool Unit::IsHostileToPlayers() const
{
FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
- if(!my_faction)
+ if(!my_faction || !my_faction->faction)
return false;
FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
@@ -7925,7 +7995,7 @@ bool Unit::IsHostileToPlayers() const
bool Unit::IsNeutralToAll() const
{
FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
- if(!my_faction)
+ if(!my_faction || !my_faction->faction)
return true;
FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
@@ -7962,7 +8032,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
// remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE))
- RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE);
+ RemoveAurasByType(SPELL_AURA_MOD_UNATTACKABLE);
if (m_attacking)
{
@@ -7977,34 +8047,43 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
}
return false;
}
- AttackStop();
+
+ //switch target
+ InterruptSpell(CURRENT_MELEE_SPELL);
+ if(!meleeAttack)
+ clearUnitState(UNIT_STAT_MELEE_ATTACKING);
}
+ if(m_attacking)
+ m_attacking->_removeAttacker(this);
+
+ m_attacking = victim;
+ m_attacking->_addAttacker(this);
+
//Set our target
SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
if(meleeAttack)
addUnitState(UNIT_STAT_MELEE_ATTACKING);
- m_attacking = victim;
- m_attacking->_addAttacker(this);
- //if(m_attacking->GetTypeId()==TYPEID_UNIT && ((Creature*)m_attacking)->IsAIEnabled)
- // ((Creature*)m_attacking)->AI()->AttackedBy(this);
+ // set position before any AI calls/assistance
+ //if(GetTypeId()==TYPEID_UNIT)
+ // ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
- if(GetTypeId()==TYPEID_UNIT)
+ if(GetTypeId()==TYPEID_UNIT && !IsControlledByPlayer())
{
+ // should not let player enter combat by right clicking target
+ SetInCombatWith(victim);
+ if(victim->GetTypeId() == TYPEID_PLAYER)
+ victim->SetInCombatWith(this);
+ AddThreat(victim, 0.0f);
+
WorldPacket data(SMSG_AI_REACTION, 12);
data << uint64(GetGUID());
data << uint32(AI_REACTION_AGGRO); // Aggro sound
((WorldObject*)this)->SendMessageToSet(&data, true);
((Creature*)this)->CallAssistance();
-
- // should not let player enter combat by right clicking target
- SetInCombatWith(victim);
- if(victim->GetTypeId() == TYPEID_PLAYER)
- victim->SetInCombatWith(this);
- AddThreat(victim, 0.0f);
}
// delay offhand weapon attack to next attack time
@@ -8034,10 +8113,11 @@ bool Unit::AttackStop()
InterruptSpell(CURRENT_MELEE_SPELL);
- if( GetTypeId()==TYPEID_UNIT )
+ // reset only at real combat stop
+ if(GetTypeId()==TYPEID_UNIT )
{
- // reset call assistance
((Creature*)this)->SetNoCallAssistance(false);
+ ((Creature*)this)->SetNoSearchAssistance(false);
}
SendAttackStop(victim);
@@ -8045,9 +8125,9 @@ bool Unit::AttackStop()
return true;
}
-void Unit::CombatStop(bool cast)
+void Unit::CombatStop(bool includingCast)
{
- if(cast && IsNonMeleeSpellCasted(false))
+ if (includingCast && IsNonMeleeSpellCasted(false))
InterruptNonMeleeSpells(false);
AttackStop();
@@ -8057,20 +8137,12 @@ void Unit::CombatStop(bool cast)
ClearInCombat();
}
-void Unit::CombatStopWithPets(bool cast)
+void Unit::CombatStopWithPets(bool includingCast)
{
- CombatStop(cast);
- if(Pet* pet = GetPet())
- pet->CombatStop(cast);
- if(Unit* charm = GetCharm())
- charm->CombatStop(cast);
- if(GetTypeId()==TYPEID_PLAYER)
- {
- GuardianPetList const& guardians = ((Player*)this)->GetGuardians();
- for(GuardianPetList::const_iterator itr = guardians.begin(); itr != guardians.end(); ++itr)
- if(Unit* guardian = Unit::GetUnit(*this,*itr))
- guardian->CombatStop(cast);
- }
+ CombatStop(includingCast);
+
+ for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
+ (*itr)->CombatStop(includingCast);
}
bool Unit::isAttackingPlayer() const
@@ -8078,23 +8150,15 @@ bool Unit::isAttackingPlayer() const
if(hasUnitState(UNIT_STAT_ATTACK_PLAYER))
return true;
- Pet* pet = GetPet();
- if(pet && pet->isAttackingPlayer())
- return true;
-
- Unit* charmed = GetCharm();
- if(charmed && charmed->isAttackingPlayer())
- return true;
+ for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
+ if((*itr)->isAttackingPlayer())
+ return true;
- for (int8 i = 0; i < MAX_TOTEM; i++)
- {
- if(m_TotemSlot[i])
- {
- Creature *totem = ObjectAccessor::GetCreature(*this, m_TotemSlot[i]);
- if(totem && totem->isAttackingPlayer())
- return true;
- }
- }
+ for(int8 i = 0; i < MAX_SUMMON_SLOT; ++i)
+ if(m_SummonSlot[i])
+ if(Creature *summon = GetMap()->GetCreature(m_SummonSlot[i]))
+ if(summon->isAttackingPlayer())
+ return true;
return false;
}
@@ -8138,35 +8202,50 @@ void Unit::ModifyAuraState(AuraState flag, bool apply)
if (HasFlag(UNIT_FIELD_AURASTATE,1<<(flag-1)))
{
RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
- Unit::AuraMap& tAuras = GetAuras();
- for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
+
+ if (flag != AURA_STATE_ENRAGE) // enrage aura state triggering continues auras
{
- SpellEntry const* spellProto = (*itr).second->GetSpellProto();
- if (spellProto->CasterAuraState == flag)
+ Unit::AuraMap& tAuras = GetAuras();
+ for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
{
- // exceptions (applied at state but not removed at state change)
- // Rampage
- if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags==0x100000)
+ SpellEntry const* spellProto = (*itr).second->GetSpellProto();
+ if (spellProto->CasterAuraState == flag)
{
- ++itr;
- continue;
- }
+ // exceptions (applied at state but not removed at state change)
+ // Rampage
+ if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags[0]==0x100000)
+ {
+ ++itr;
+ continue;
+ }
- RemoveAura(itr);
+ RemoveAura(itr);
+ }
+ else
+ ++itr;
}
- else
- ++itr;
}
}
}
}
+bool Unit::HasAuraState(AuraState flag, SpellEntry const *spellProto, Unit * Caster) const
+{
+ if (Caster && spellProto)
+ {
+ AuraEffectList const& stateAuras = Caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
+ for(AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j)
+ if((*j)->isAffectedOnSpell(spellProto))
+ return true;
+ }
+ return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
+}
+
Unit *Unit::GetOwner() const
{
- uint64 ownerid = GetOwnerGUID();
- if(!ownerid)
- return NULL;
- return ObjectAccessor::GetUnit(*this, ownerid);
+ if(uint64 ownerid = GetOwnerGUID())
+ return ObjectAccessor::GetUnit(*this, ownerid);
+ return NULL;
}
Unit *Unit::GetCharmer() const
@@ -8185,15 +8264,31 @@ Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const
return GetTypeId()==TYPEID_PLAYER ? (Player*)this : NULL;
}
-Pet* Unit::GetPet() const
+Minion *Unit::GetFirstMinion() const
+{
+ if(uint64 pet_guid = GetMinionGUID())
+ {
+ if(Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
+ if(pet->HasSummonMask(SUMMON_MASK_MINION))
+ return (Minion*)pet;
+
+ sLog.outError("Unit::GetFirstMinion: Minion %u not exist.",GUID_LOPART(pet_guid));
+ const_cast<Unit*>(this)->SetMinionGUID(0);
+ }
+
+ return NULL;
+}
+
+Guardian* Unit::GetGuardianPet() const
{
if(uint64 pet_guid = GetPetGUID())
{
- if(Pet* pet = ObjectAccessor::GetPet(pet_guid))
- return pet;
+ if(Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
+ if(pet->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ return (Guardian*)pet;
- sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
- const_cast<Unit*>(this)->SetPet(0);
+ sLog.outError("Unit::GetGuardianPet: Guardian %u not exist.",GUID_LOPART(pet_guid));
+ const_cast<Unit*>(this)->SetPetGUID(0);
}
return NULL;
@@ -8207,28 +8302,351 @@ Unit* Unit::GetCharm() const
return pet;
sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid));
- const_cast<Unit*>(this)->SetCharm(0);
+ const_cast<Unit*>(this)->SetUInt64Value(UNIT_FIELD_CHARM, 0);
}
return NULL;
}
-void Unit::SetPet(Pet* pet)
+void Unit::SetMinion(Minion *minion, bool apply)
+{
+ sLog.outDebug("SetMinion %u for %u, apply %u", minion->GetEntry(), GetEntry(), apply);
+
+ if(apply)
+ {
+ if(!minion->AddUInt64Value(UNIT_FIELD_SUMMONEDBY, GetGUID()))
+ {
+ sLog.outCrash("SetMinion: Minion %u is not the minion of owner %u", minion->GetEntry(), GetEntry());
+ return;
+ }
+
+ m_Controlled.insert(minion);
+
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ minion->m_ControlledByPlayer = true;
+ minion->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+ }
+
+ // Can only have one pet. If a new one is summoned, dismiss the old one.
+ if(minion->isPet() || minion->m_Properties && minion->m_Properties->Category == SUMMON_CATEGORY_PET)
+ {
+ if(Guardian* oldPet = GetGuardianPet())
+ {
+ if(oldPet != minion && (oldPet->isPet() || minion->isPet() || oldPet->GetEntry() != minion->GetEntry()))
+ {
+ // remove existing minion pet
+ if(oldPet->isPet())
+ ((Pet*)oldPet)->Remove(PET_SAVE_AS_CURRENT);
+ else
+ oldPet->UnSummon();
+ SetPetGUID(minion->GetGUID());
+ SetMinionGUID(0);
+ }
+ }
+ else
+ {
+ SetPetGUID(minion->GetGUID());
+ SetMinionGUID(0);
+ }
+ }
+
+ //if(minion->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ {
+ if(AddUInt64Value(UNIT_FIELD_SUMMON, minion->GetGUID()))
+ {
+ }
+ }
+ //else if(minion->m_Properties && minion->m_Properties->Type == SUMMON_TYPE_MINIPET)
+ // AddUInt64Value(UNIT_FIELD_CRITTER, minion->GetGUID());
+
+ // PvP, FFAPvP
+ minion->SetByteValue(UNIT_FIELD_BYTES_2, 1, GetByteValue(UNIT_FIELD_BYTES_2, 1));
+
+ // FIXME: hack, speed must be set only at follow
+ if(GetTypeId() == TYPEID_PLAYER && minion->HasSummonMask(SUMMON_MASK_PET))
+ for(int i = 0; i < MAX_MOVE_TYPE; ++i)
+ minion->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
+ }
+ else
+ {
+ if(minion->GetOwnerGUID() != GetGUID())
+ {
+ sLog.outCrash("SetMinion: Minion %u is not the minion of owner %u", minion->GetEntry(), GetEntry());
+ return;
+ }
+
+ m_Controlled.erase(minion);
+
+ if(minion->isPet() || minion->m_Properties && minion->m_Properties->Category == SUMMON_CATEGORY_PET)
+ {
+ if(GetPetGUID() == minion->GetGUID())
+ SetPetGUID(0);
+ }
+
+ //if(minion->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ {
+ if(RemoveUInt64Value(UNIT_FIELD_SUMMON, minion->GetGUID()))
+ {
+ //Check if there is another minion
+ for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
+ {
+ if(GetCharmGUID() == (*itr)->GetGUID())
+ continue;
+
+ assert((*itr)->GetOwnerGUID() == GetGUID());
+ assert((*itr)->GetTypeId() == TYPEID_UNIT);
+
+ if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ continue;
+
+ if(AddUInt64Value(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))
+ {
+ //show another pet bar if there is no charm bar
+ if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ {
+ if(((Creature*)(*itr))->isPet())
+ ((Player*)this)->PetSpellInitialize();
+ else
+ ((Player*)this)->CharmSpellInitialize();
+ }
+ }
+ break;
+ }
+ }
+ }
+ //else if(minion->m_Properties && minion->m_Properties->Type == SUMMON_TYPE_MINIPET)
+ // RemoveUInt64Value(UNIT_FIELD_CRITTER, minion->GetGUID());
+ }
+}
+
+void Unit::SetCharm(Unit* charm, bool apply)
+{
+ if(apply)
+ {
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ if(!AddUInt64Value(UNIT_FIELD_CHARM, charm->GetGUID()))
+ sLog.outCrash("Player %s is trying to charm unit %u, but it already has a charmed unit %u", GetName(), charm->GetEntry(), GetCharmGUID());
+
+ charm->m_ControlledByPlayer = true;
+ // TODO: maybe we can use this flag to check if controlled by player
+ charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+ }
+ else
+ charm->m_ControlledByPlayer = false;
+
+ // PvP, FFAPvP
+ charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, GetByteValue(UNIT_FIELD_BYTES_2, 1));
+
+ if(!charm->AddUInt64Value(UNIT_FIELD_CHARMEDBY, GetGUID()))
+ sLog.outCrash("Unit %u is being charmed, but it already has a charmer %u", charm->GetEntry(), charm->GetCharmerGUID());
+
+ if(charm->HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE))
+ {
+ charm->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ charm->SendMovementFlagUpdate();
+ }
+
+ m_Controlled.insert(charm);
+ }
+ else
+ {
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ if(!RemoveUInt64Value(UNIT_FIELD_CHARM, charm->GetGUID()))
+ sLog.outCrash("Player %s is trying to uncharm unit %u, but it has another charmed unit %u", GetName(), charm->GetEntry(), GetCharmGUID());
+ }
+
+ if(charm->GetTypeId() == TYPEID_PLAYER)
+ {
+ charm->m_ControlledByPlayer = true;
+ charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+ ((Player*)charm)->UpdatePvPState();
+ }
+ else if(Player *player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
+ {
+ charm->m_ControlledByPlayer = true;
+ charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+ charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, player->GetByteValue(UNIT_FIELD_BYTES_2, 1));
+ }
+ else
+ {
+ charm->m_ControlledByPlayer = false;
+ charm->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+ charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, 0);
+ }
+
+ if(!charm->RemoveUInt64Value(UNIT_FIELD_CHARMEDBY, GetGUID()))
+ sLog.outCrash("Unit %u is being uncharmed, but it has another charmer %u", charm->GetEntry(), charm->GetCharmerGUID());
+
+ m_Controlled.erase(charm);
+ }
+}
+
+int32 Unit::DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical)
+{
+ int32 gain = pVictim->ModifyHealth(int32(addhealth));
+
+ if (GetTypeId()==TYPEID_PLAYER)
+ {
+ SendHealSpellLog(pVictim, spellProto->Id, addhealth, critical, gain);
+
+ if (BattleGround *bg = ((Player*)this)->GetBattleGround())
+ bg->UpdatePlayerScore((Player*)this, SCORE_HEALING_DONE, gain);
+
+ // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
+ if (gain)
+ ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim);
+
+ ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth);
+ }
+
+ if (pVictim->GetTypeId()==TYPEID_PLAYER)
+ {
+ ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain);
+ ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth);
+ }
+
+ return gain;
+}
+
+Unit* Unit::SelectMagnetTarget(Unit *victim, SpellEntry const *spellInfo)
{
- SetUInt64Value(UNIT_FIELD_SUMMON, pet ? pet->GetGUID() : 0);
+ if(!victim)
+ return NULL;
- // FIXME: hack, speed must be set only at follow
- if(pet)
- for(int i = 0; i < MAX_MOVE_TYPE; ++i)
- pet->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
+ // Magic case
+ if(spellInfo && (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE || spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC))
+ {
+ //I am not sure if this should be redirected.
+ if(spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE)
+ return victim;
+
+ Unit::AuraEffectList const& magnetAuras = victim->GetAurasByType(SPELL_AURA_SPELL_MAGNET);
+ for(Unit::AuraEffectList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr)
+ if(Unit* magnet = (*itr)->IsAreaAura() ? ((AreaAuraEffect*)(*itr))->GetSource():(*itr)->GetCaster() )
+ if(magnet->isAlive())
+ {
+ return magnet;
+ }
+ }
+ // Melee && ranged case
+ else
+ {
+ AuraEffectList const& hitTriggerAuras = victim->GetAurasByType(SPELL_AURA_ADD_CASTER_HIT_TRIGGER);
+ for(AuraEffectList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.end(); ++i)
+ if(Unit* magnet = (*i)->IsAreaAura() ? ((AreaAuraEffect*)(*i))->GetSource():(*i)->GetCaster() )
+ if(magnet->isAlive() && magnet->IsWithinLOSInMap(this))
+ if(roll_chance_i((*i)->GetAmount()))
+ {
+ (*i)->GetParentAura()->DropAuraCharge();
+ return magnet;
+ }
+ }
+
+ return victim;
+}
+
+Unit* Unit::GetFirstControlled() const
+{
+ //Sequence: charmed, pet, other guardians
+ Unit *unit = GetCharm();
+ if(!unit)
+ {
+ if(uint64 guid = GetUInt64Value(UNIT_FIELD_SUMMON))
+ unit = ObjectAccessor::GetUnit(*this, guid);
+ }
+ return unit;
+}
+
+void Unit::RemoveAllControlled()
+{
+ //possessed pet and vehicle
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player*)this)->StopCastingCharm();
+
+ while(!m_Controlled.empty())
+ {
+ Unit *target = *m_Controlled.begin();
+ m_Controlled.erase(m_Controlled.begin());
+ if(target->GetCharmerGUID() == GetGUID())
+ {
+ target->RemoveCharmAuras();
+ }
+ else if(target->GetOwnerGUID() == GetGUID()
+ && target->GetTypeId() == TYPEID_UNIT
+ && ((Creature*)target)->HasSummonMask(SUMMON_MASK_SUMMON))
+ {
+
+ if(!((TempSummon*)target)->isPet())
+ ((TempSummon*)target)->UnSummon();
+ }
+ else
+ {
+ sLog.outError("Unit %u is trying to release unit %u which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
+ }
+ }
+ if(GetPetGUID() != GetMinionGUID())
+ sLog.outCrash("Unit %u is not able to release its summon " I64FMT, GetEntry(), GetMinionGUID());
+ if(GetCharmGUID())
+ sLog.outCrash("Unit %u is not able to release its charm " I64FMT, GetEntry(), GetCharmGUID());
}
-void Unit::SetCharm(Unit* pet)
+Unit* Unit::GetNextRandomRaidMemberOrPet(float radius)
{
+ Player* player = NULL;
if(GetTypeId() == TYPEID_PLAYER)
- SetUInt64Value(UNIT_FIELD_CHARM, pet ? pet->GetGUID() : 0);
+ player = (Player*)this;
+ // Should we enable this also for charmed units?
+ else if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
+ player=(Player*)GetOwner();
+
+ if (!player)
+ return NULL;
+ Group *pGroup = player->GetGroup();
+ //When there is no group check pet presence
+ if (!pGroup)
+ {
+ // We are pet now, return owner
+ if(player!=this)
+ return IsWithinDistInMap(player, radius) ? player : NULL;
+ Unit * pet = GetGuardianPet();
+ //No pet, no group, nothing to return
+ if (!pet)
+ return NULL;
+ // We are owner now, return pet
+ return IsWithinDistInMap(pet, radius) ? pet : NULL;
+ }
+
+ std::vector<Unit*> nearMembers;
+ //reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
+ nearMembers.reserve(pGroup->GetMembersCount()*2);
+
+ for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player* Target = itr->getSource();
+
+ // IsHostileTo check duel and controlled by enemy
+ if( Target && Target !=this && Target->isAlive() && IsWithinDistInMap(Target, radius) &&
+ !IsHostileTo(Target) )
+ nearMembers.push_back(Target);
+
+ // Push player's pet to vector
+ Unit * pet = Target->GetGuardianPet();
+ if (pet && pet !=this && pet->isAlive() && IsWithinDistInMap(pet, radius) &&
+ !IsHostileTo(pet) )
+ nearMembers.push_back(pet);
+ }
+
+ if (nearMembers.empty())
+ return NULL;
+
+ uint32 randTarget = urand(0,nearMembers.size()-1);
+ return nearMembers[randTarget];
}
+//only called in Player::SetSeer
void Unit::AddPlayerToVision(Player* plr)
{
if(m_sharedVision.empty())
@@ -8237,9 +8655,9 @@ void Unit::AddPlayerToVision(Player* plr)
SetWorldObject(true);
}
m_sharedVision.push_back(plr);
- plr->SetFarsightTarget(this);
}
+//only called in Player::SetSeer
void Unit::RemovePlayerFromVision(Player* plr)
{
m_sharedVision.remove(plr);
@@ -8248,35 +8666,34 @@ void Unit::RemovePlayerFromVision(Player* plr)
setActive(false);
SetWorldObject(false);
}
- plr->ClearFarsight();
}
void Unit::RemoveBindSightAuras()
{
- RemoveSpellsCausingAura(SPELL_AURA_BIND_SIGHT);
+ RemoveAurasByType(SPELL_AURA_BIND_SIGHT);
}
void Unit::RemoveCharmAuras()
{
- RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM);
- RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS_PET);
- RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS);
+ RemoveAurasByType(SPELL_AURA_MOD_CHARM);
+ RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET);
+ RemoveAurasByType(SPELL_AURA_MOD_POSSESS);
}
void Unit::UnsummonAllTotems()
{
- for (int8 i = 0; i < MAX_TOTEM; ++i)
+ for (int8 i = 0; i < MAX_SUMMON_SLOT; ++i)
{
- if(!m_TotemSlot[i])
+ if(!m_SummonSlot[i])
continue;
- Creature *OldTotem = ObjectAccessor::GetCreature(*this, m_TotemSlot[i]);
- if (OldTotem && OldTotem->isTotem())
- ((Totem*)OldTotem)->UnSummon();
+ Creature *OldTotem = GetMap()->GetCreature(m_SummonSlot[i]);
+ if(OldTotem && OldTotem->isSummon())
+ ((TempSummon*)OldTotem)->UnSummon();
}
}
-void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical)
+void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical, int32 gain)
{
// we guess size
WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+1));
@@ -8284,6 +8701,7 @@ void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool c
data.append(GetPackGUID());
data << uint32(SpellID);
data << uint32(Damage);
+ data << uint32((int32)Damage > gain ? (int32)Damage - gain : 0); // overheal
data << uint8(critical ? 1 : 0);
data << uint8(0); // unused in client?
SendMessageToSet(&data, true);
@@ -8300,426 +8718,336 @@ void Unit::SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, Po
SendMessageToSet(&data, true);
}
-uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype)
+uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack)
{
if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
return pdamage;
- //if(spellProto->SchoolMask == SPELL_SCHOOL_MASK_NORMAL)
- // return pdamage;
- //damage = CalcArmorReducedDamage(pVictim, damage);
-
- int32 BonusDamage = 0;
- if( GetTypeId()==TYPEID_UNIT )
+ // For totems get damage bonus from owner (statue isn't totem in fact)
+ if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem())
{
- // Pets just add their bonus damage to their spell damage
- // note that their spell damage is just gain of their own auras
- if (((Creature*)this)->isPet())
- {
- BonusDamage = ((Pet*)this)->GetBonusDamage();
- }
- // For totems get damage bonus from owner (statue isn't totem in fact)
- else if (((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE)
- {
- if(Unit* owner = GetOwner())
- return owner->SpellDamageBonus(pVictim, spellProto, pdamage, damagetype);
- }
- }
-
- // Damage Done
- uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
-
- // Taken/Done fixed damage bonus auras
- int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto))+BonusDamage;
- int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
-
- // Damage over Time spells bonus calculation
- float DotFactor = 1.0f;
- if(damagetype == DOT)
- {
- int32 DotDuration = GetSpellDuration(spellProto);
- // 200% limit
- if(DotDuration > 0)
- {
- if(DotDuration > 30000) DotDuration = 30000;
- if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
- int x = 0;
- for(int j = 0; j < 3; j++)
- {
- if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
- spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
- spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
- {
- x = j;
- break;
- }
- }
- int DotTicks = 6;
- if(spellProto->EffectAmplitude[x] != 0)
- DotTicks = DotDuration / spellProto->EffectAmplitude[x];
- if(DotTicks)
- {
- DoneAdvertisedBenefit /= DotTicks;
- TakenAdvertisedBenefit /= DotTicks;
- }
- }
+ if(Unit* owner = GetOwner())
+ return owner->SpellDamageBonus(pVictim, spellProto, pdamage, damagetype);
}
// Taken/Done total percent damage auras
float DoneTotalMod = 1.0f;
float TakenTotalMod = 1.0f;
+ int32 DoneTotal = 0;
+ int32 TakenTotal = 0;
// ..done
- AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
+ // Pet damage
+ if( GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() )
+ DoneTotalMod *= ((Creature*)this)->GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->rank);
+
+ AuraEffectList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
+ for(AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
{
- if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) &&
+ if( ((*i)->GetMiscValue() & GetSpellSchoolMask(spellProto)) &&
(*i)->GetSpellProto()->EquippedItemClass == -1 &&
// -1 == any item class (not wand then)
(*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
// 0 == any inventory type (not wand then)
{
- DoneTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
}
}
uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
- AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
- for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- DoneTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
-
- // ..taken
- AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
- for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
- if( (*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto) )
- TakenTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
-
- // .. taken pct: scripted (increases damage of * against targets *)
- AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
- {
- switch((*i)->GetModifier()->m_miscvalue)
- {
- //Molten Fury
- case 4920: case 4919:
- if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT))
- TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f; break;
- }
- }
-
- bool hasmangle=false;
- // .. taken pct: dummy auras
- AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
- for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
- {
- switch((*i)->GetSpellProto()->SpellIconID)
+ // Add flat bonus from spell damage versus
+ DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask);
+ AuraEffectList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
+ for(AuraEffectList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
+ if(creatureTypeMask & uint32((*i)->GetMiscValue()))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+
+ // done scripted mod (take it from owner)
+ Unit *owner = GetOwner();
+ if (!owner) owner = this;
+ AuraEffectList const& mOverrideClassScript= owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
+ {
+ if (!(*i)->isAffectedOnSpell(spellProto))
+ continue;
+ switch((*i)->GetMiscValue())
{
- //Cheat Death
- case 2109:
- if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) )
- {
- if(pVictim->GetTypeId() != TYPEID_PLAYER)
- continue;
- float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4;
- if (mod < (*i)->GetModifier()->m_amount)
- mod = (*i)->GetModifier()->m_amount;
- TakenTotalMod *= (mod+100.0f)/100.0f;
- }
+ case 4920: // Molten Fury
+ case 4919:
+ case 6917: // Death's Embrace
+ case 6926:
+ case 6928:
+ {
+ if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
+ DoneTotalMod *= (100.0f+(*i)->GetAmount())/100.0f;
break;
- //This is changed in WLK, using aura 255
- //Mangle
- case 2312:
- case 44955:
- // don't apply mod twice
- if (hasmangle)
- break;
- hasmangle=true;
- for(int j=0;j<3;j++)
- {
- if(GetEffectMechanic(spellProto, j)==MECHANIC_BLEED)
+ }
+ // Soul Siphon
+ case 4992:
+ case 4993:
+ {
+ // effect 1 m_amount
+ int32 maxPercent = (*i)->GetAmount();
+ // effect 0 m_amount
+ int32 stepPercent = CalculateSpellDamage((*i)->GetSpellProto(), 0, (*i)->GetSpellProto()->EffectBasePoints[0], this);
+ // count affliction effects and calc additional damage in percentage
+ int32 modPercent = 0;
+ AuraMap const& victimAuras = pVictim->GetAuras();
+ for (AuraMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
+ {
+ SpellEntry const* m_spell = itr->second->GetSpellProto();
+ if (m_spell->SpellFamilyName != SPELLFAMILY_WARLOCK || !(m_spell->SpellFamilyFlags[1] & 0x0004071B || m_spell->SpellFamilyFlags[0] & 0x8044C402))
+ continue;
+ modPercent += stepPercent * itr->second->GetStackAmount();
+ if (modPercent >= maxPercent)
{
- TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f;
+ modPercent = maxPercent;
break;
}
}
+ DoneTotalMod *= (modPercent+100.0f)/100.0f;
break;
- }
- }
-
- // Distribute Damage over multiple effects, reduce by AoE
- CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
-
- // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
- for(int j = 0; j < 3; ++j)
- {
- if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
- spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
- {
- CastingTime /= 2;
- break;
- }
- }
-
- switch(spellProto->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- // Siphon Essence - 0%
- if(spellProto->AttributesEx == 268435456 && spellProto->SpellIconID == 2027)
- {
- CastingTime = 0;
- }
- // Goblin Rocket Launcher - 0%
- else if (spellProto->SpellIconID == 184 && spellProto->Attributes == 4259840)
- {
- CastingTime = 0;
- }
- // Darkmoon Card: Vengeance - 0.1%
- else if (spellProto->SpellVisual == 9850 && spellProto->SpellIconID == 2230)
- {
- CastingTime = 3.5;
- }
- case SPELLFAMILY_MAGE:
- // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
- if(spellProto->Id==12654)
- {
- return pdamage;
- }
- // Ice Lance
- else if((spellProto->SpellFamilyFlags & 0x20000LL) && spellProto->SpellIconID == 186)
- {
- CastingTime /= 3; // applied 1/3 bonuses in case generic target
- if(pVictim->isFrozen()) // and compensate this for frozen target.
- TakenTotalMod *= 3.0f;
- }
- // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
- else if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 184 )
- {
- DotFactor = damagetype == DOT ? 0.2f : 1.0f;
- CastingTime = damagetype == DOT ? 3500 : 4025;
- }
- // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
- else if((spellProto->SpellFamilyFlags & 0x1LL) && spellProto->SpellIconID == 185)
- {
- CastingTime = 3500;
- DotFactor = damagetype == DOT ? 0.0f : 1.0f;
- }
- // Molten armor
- else if (spellProto->SpellFamilyFlags & 0x0000000800000000LL)
- {
- CastingTime = 0;
- }
- // Arcane Missiles triggered spell
- else if ((spellProto->SpellFamilyFlags & 0x200000LL) && spellProto->SpellIconID == 225)
- {
- CastingTime = 1000;
- }
- // Blizzard triggered spell
- else if ((spellProto->SpellFamilyFlags & 0x80080LL) && spellProto->SpellIconID == 285)
- {
- CastingTime = 500;
- }
- break;
- case SPELLFAMILY_WARLOCK:
- // Life Tap
- if((spellProto->SpellFamilyFlags & 0x40000LL) && spellProto->SpellIconID == 208)
- {
- CastingTime = 2800; // 80% from +shadow damage
- DoneTotalMod = 1.0f;
- TakenTotalMod = 1.0f;
}
- // Dark Pact
- else if((spellProto->SpellFamilyFlags & 0x80000000LL) && spellProto->SpellIconID == 154 && GetPetGUID())
- {
- CastingTime = 3360; // 96% from +shadow damage
- DoneTotalMod = 1.0f;
- TakenTotalMod = 1.0f;
- }
- // Soul Fire - 115% of Fire Damage
- else if((spellProto->SpellFamilyFlags & 0x8000000000LL) && spellProto->SpellIconID == 184)
- {
- CastingTime = 4025;
- }
- // Curse of Agony - 120% of Shadow Damage
- else if((spellProto->SpellFamilyFlags & 0x0000000400LL) && spellProto->SpellIconID == 544)
- {
- DotFactor = 1.2f;
- }
- // Drain Mana - 0% of Shadow Damage
- else if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 548)
+ case 6916: // Death's Embrace
+ case 6925:
+ case 6927:
+ if (HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, spellProto, this))
+ DoneTotalMod *= (100.0f+(*i)->GetAmount())/100.0f;
+ break;
+ case 5481: // Starfire Bonus
{
- CastingTime = 0;
+ if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x200002, 0))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ break;
}
- // Drain Soul 214.3%
- else if ((spellProto->SpellFamilyFlags & 0x4000LL) && spellProto->SpellIconID == 113 )
+ case 4418: // Increased Shock Damage
+ case 4554: // Increased Lightning Damage
+ case 4555: // Improved Moonfire
+ case 5142: // Increased Lightning Damage
+ case 5147: // Improved Consecration / Libram of Resurgence
+ case 5148: // Idol of the Shooting Star
+ case 6008: // Increased Lightning Damage / Totem of Hex
{
- CastingTime = 7500;
+ DoneTotal+=(*i)->GetAmount();
+ break;
}
- // Hellfire
- else if ((spellProto->SpellFamilyFlags & 0x40LL) && spellProto->SpellIconID == 937)
+ // Tundra Stalker
+ // Merciless Combat
+ case 7277:
{
- CastingTime = damagetype == DOT ? 5000 : 500; // self damage seems to be so
+ // Merciless Combat
+ if ((*i)->GetSpellProto()->SpellIconID == 2656)
+ {
+ if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
+ DoneTotalMod *= (100.0f+(*i)->GetAmount())/100.0f;
+ }
+ else // Tundra Stalker
+ {
+ if (pVictim->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_DEATHKNIGHT,0, 0x04000000,0))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ break;
+ }
+ break;
}
- // Unstable Affliction - 180%
- else if (spellProto->Id == 31117 && spellProto->SpellIconID == 232)
+ case 7293: // Rage of Rivendare
{
- CastingTime = 6300;
+ if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0,0x02000000,0))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ break;
}
- // Corruption 93%
- else if ((spellProto->SpellFamilyFlags & 0x2LL) && spellProto->SpellIconID == 313)
+ // Twisted Faith
+ case 7377:
{
- DotFactor = 0.93f;
+ if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0,0, GetGUID()))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ break;
}
- break;
- case SPELLFAMILY_PALADIN:
- // Consecration - 95% of Holy Damage
- if((spellProto->SpellFamilyFlags & 0x20LL) && spellProto->SpellIconID == 51)
+ // Marked for Death
+ case 7598:
+ case 7599:
+ case 7600:
+ case 7601:
+ case 7602:
{
- DotFactor = 0.95f;
- CastingTime = 3500;
+ if (pVictim->GetAura(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ break;
}
- // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
- else if((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 25)
- {
- Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
- float wspeed = GetAttackTime(BASE_ATTACK)/1000.0f;
+ }
+ }
- if( item && item->GetProto()->InventoryType == INVTYPE_2HWEAPON)
- CastingTime = uint32(wspeed*3500*0.102f);
- else
- CastingTime = uint32(wspeed*3500*0.098f);
- }
- // Judgement of Righteousness - 73%
- else if ((spellProto->SpellFamilyFlags & 1024) && spellProto->SpellIconID == 25)
- {
- CastingTime = 2555;
- }
- // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
- else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2292)
- {
- DotFactor = 0.85f;
- CastingTime = 3500;
- }
- // Holy shield - 5% of Holy Damage
- else if ((spellProto->SpellFamilyFlags & 0x4000000000LL) && spellProto->SpellIconID == 453)
- {
- CastingTime = 175;
- }
- // Blessing of Sanctuary - 0%
- else if ((spellProto->SpellFamilyFlags & 0x10000000LL) && spellProto->SpellIconID == 29)
- {
- CastingTime = 0;
- }
- // Seal of Righteousness trigger - already computed for parent spell
- else if ( spellProto->SpellFamilyName==SPELLFAMILY_PALADIN && spellProto->SpellIconID==25 && spellProto->AttributesEx4 & 0x00800000LL )
- {
- return pdamage;
- }
- break;
- case SPELLFAMILY_SHAMAN:
- // totem attack
- if (spellProto->SpellFamilyFlags & 0x000040000000LL)
- {
- if (spellProto->SpellIconID == 33) // Fire Nova totem attack must be 21.4%(untested)
- CastingTime = 749; // ignore CastingTime and use as modifier
- else if (spellProto->SpellIconID == 680) // Searing Totem attack 8%
- CastingTime = 280; // ignore CastingTime and use as modifier
- else if (spellProto->SpellIconID == 37) // Magma totem attack must be 6.67%(untested)
- CastingTime = 234; // ignore CastingTimePenalty and use as modifier
- }
- // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
- else if( (spellProto->SpellFamilyFlags & 0x00000000400LL) || spellProto->Id == 23552)
- CastingTime = 1155; // ignore CastingTimePenalty and use as modifier
- break;
- case SPELLFAMILY_PRIEST:
- // Mana Burn - 0% of Shadow Damage
- if((spellProto->SpellFamilyFlags & 0x10LL) && spellProto->SpellIconID == 212)
- {
- CastingTime = 0;
- }
- // Mind Flay - 59% of Shadow Damage
- else if((spellProto->SpellFamilyFlags & 0x800000LL) && spellProto->SpellIconID == 548)
- {
- CastingTime = 2065;
- }
- // Holy Fire - 86.71%, DoT - 16.5%
- else if ((spellProto->SpellFamilyFlags & 0x100000LL) && spellProto->SpellIconID == 156)
- {
- DotFactor = damagetype == DOT ? 0.165f : 1.0f;
- CastingTime = damagetype == DOT ? 3500 : 3035;
- }
- // Shadowguard - 28% per charge
- else if ((spellProto->SpellFamilyFlags & 0x2000000LL) && spellProto->SpellIconID == 19)
- {
- CastingTime = 980;
- }
- // Touch of Weakeness - 10%
- else if ((spellProto->SpellFamilyFlags & 0x80000LL) && spellProto->SpellIconID == 1591)
- {
- CastingTime = 350;
- }
- // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
- else if (spellProto->SpellFamilyFlags == 0 && spellProto->SpellIconID == 566)
- {
- CastingTime = 0;
- }
- // Holy Nova - 14%
- else if ((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 1874)
+ // Custom scripted damage
+ // Judgement of Vengeance/ Judgement of Corruption
+ if((spellProto->SpellFamilyFlags[1] & 0x400000) && spellProto->SpellIconID==2292)
+ {
+ // Get stack of Holy Vengeance/Blood Corruption on the target added by caster
+ uint32 stacks = 0;
+ Unit::AuraEffectList const& auras = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
+ if(((*itr)->GetId() == 31803 || (*itr)->GetId() == 53742) && (*itr)->GetCasterGUID()==GetGUID())
{
- CastingTime = 500;
+ stacks = (*itr)->GetParentAura()->GetStackAmount();
+ break;
}
- break;
- case SPELLFAMILY_DRUID:
- // Hurricane triggered spell
- if((spellProto->SpellFamilyFlags & 0x400000LL) && spellProto->SpellIconID == 220)
+ // + 10% for each application of Holy Vengeance/Blood Corruption on the target
+ if(stacks)
+ DoneTotalMod *= (1.0f + (float)stacks / 10.0f) ;
+ }
+
+ // Ice Lance
+ if (spellProto->SpellFamilyName == SPELLFAMILY_MAGE && spellProto->SpellIconID == 186)
+ {
+ if (pVictim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
+ DoneTotalMod *= 3.0f;
+ }
+
+ // Torment the weak
+ if (spellProto->SpellFamilyName== SPELLFAMILY_MAGE && (spellProto->SpellFamilyFlags[0]&0x20200021 || spellProto->SpellFamilyFlags[1]& 0x9000))
+ {
+ if(pVictim->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED))
+ {
+ AuraEffectList const& mDumyAuras = GetAurasByType(SPELL_AURA_DUMMY);
+ for(AuraEffectList::const_iterator i = mDumyAuras.begin(); i != mDumyAuras.end(); ++i)
{
- CastingTime = 500;
+ if ((*i)->GetSpellProto()->SpellIconID == 3263)
+ {
+ DoneTotalMod *=float((*i)->GetAmount() + 100.f) / 100.f;
+ break;
+ }
}
- break;
- case SPELLFAMILY_WARRIOR:
- case SPELLFAMILY_HUNTER:
- case SPELLFAMILY_ROGUE:
- CastingTime = 0;
- break;
- default:
- break;
+ }
}
- float LvlPenalty = CalculateLevelPenalty(spellProto);
-
- // Spellmod SpellDamage
- //float SpellModSpellDamage = 100.0f;
- float CoefficientPtc = DotFactor * 100.0f;
- if(spellProto->SchoolMask != SPELL_SCHOOL_MASK_NORMAL)
- CoefficientPtc *= ((float)CastingTime/3500.0f);
+ // ..taken
+ AuraEffectList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
+ for(AuraEffectList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
+ if( (*i)->GetMiscValue() & GetSpellSchoolMask(spellProto) )
+ TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
- if(Player* modOwner = GetSpellModOwner())
- //modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage);
- modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,CoefficientPtc);
+ // .. taken pct: dummy auras
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
+ {
+ //Cheat Death
+ if (AuraEffect *dummy = pVictim->GetDummyAura(45182))
+ {
+ float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4;
+ if (mod < dummy->GetAmount())
+ mod = dummy->GetAmount();
+ TakenTotalMod *= (mod+100.0f)/100.0f;
+ }
+ }
- //SpellModSpellDamage /= 100.0f;
- CoefficientPtc /= 100.0f;
+ // From caster spells
+ AuraEffectList const& mOwnerTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER);
+ for(AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i)
+ if( (*i)->GetCasterGUID() == GetGUID() && (*i)->isAffectedOnSpell(spellProto))
+ TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
- //float DoneActualBenefit = DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty;
+ // Mod damage from spell mechanic
+ uint32 mechanicMask = GetAllSpellMechanicMask(spellProto);
+ if (mechanicMask)
+ {
+ AuraEffectList const& mDamageDoneMechanic = pVictim->GetAurasByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
+ for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin();i != mDamageDoneMechanic.end(); ++i)
+ if(mechanicMask & uint32(1<<((*i)->GetMiscValue())))
+ TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ }
- float DoneActualBenefit = DoneAdvertisedBenefit * CoefficientPtc * LvlPenalty;
- float TakenActualBenefit = TakenAdvertisedBenefit * DotFactor * LvlPenalty;
- if(spellProto->SpellFamilyName && spellProto->SchoolMask != SPELL_SCHOOL_MASK_NORMAL)
- TakenActualBenefit *= ((float)CastingTime / 3500.0f);
+ // Taken/Done fixed damage bonus auras
+ int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto));
+ int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
+ // Pets just add their bonus damage to their spell damage
+ // note that their spell damage is just gain of their own auras
+ if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage();
+
+ // Check for table values
+ float coeff;
+ SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id);
+ if (bonus)
+ {
+ if (damagetype == DOT)
+ coeff = bonus->dot_damage;
+ else
+ coeff = bonus->direct_damage;
+ if (bonus->ap_bonus)
+ DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack;
+ }
+ // Default calculation
+ if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
+ {
+ if(!bonus)
+ {
+ // Damage Done from spell damage bonus
+ int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
+ // Damage over Time spells bonus calculation
+ float DotFactor = 1.0f;
+ if(damagetype == DOT)
+ {
+ int32 DotDuration = GetSpellDuration(spellProto);
+ // 200% limit
+ if(DotDuration > 0)
+ {
+ if(DotDuration > 30000) DotDuration = 30000;
+ if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
+ int x = 0;
+ for(int j = 0; j < 3; j++)
+ {
+ if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
+ spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
+ spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
+ {
+ x = j;
+ break;
+ }
+ }
+ int32 DotTicks = 6;
+ if(spellProto->EffectAmplitude[x] != 0)
+ DotTicks = DotDuration / spellProto->EffectAmplitude[x];
+ if(DotTicks)
+ {
+ DoneAdvertisedBenefit /= DotTicks;
+ TakenAdvertisedBenefit /= DotTicks;
+ }
+ }
+ }
+ // Distribute Damage over multiple effects, reduce by AoE
+ CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
- float tmpDamage = (float(pdamage)+DoneActualBenefit)*DoneTotalMod;
+ // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
+ for(int j = 0; j < 3; ++j)
+ {
+ if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
+ spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
+ {
+ CastingTime /= 2;
+ break;
+ }
+ }
+ if(spellProto->SchoolMask != SPELL_SCHOOL_MASK_NORMAL)
+ coeff = (CastingTime / 3500.0f) * DotFactor;
+ else
+ coeff = DotFactor;
+ }
- // Add flat bonus from spell damage versus
- tmpDamage += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask);
+ float coeff2 = CalculateLevelPenalty(spellProto) * stack;
+ if(spellProto->SpellFamilyName) //TODO: fix this
+ TakenTotal+= TakenAdvertisedBenefit * coeff * coeff2;
+ if(Player* modOwner = GetSpellModOwner())
+ {
+ coeff *= 100.0f;
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_SPELL_BONUS_DAMAGE, coeff);
+ coeff /= 100.0f;
+ }
+ DoneTotal += DoneAdvertisedBenefit * coeff * coeff2;
+ }
- // apply spellmod to Done damage
+ float tmpDamage = (pdamage + DoneTotal) * DoneTotalMod;
+ // apply spellmod to Done damage (flat and pct)
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
- tmpDamage = (tmpDamage+TakenActualBenefit)*TakenTotalMod;
-
- if( GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() )
- tmpDamage *= ((Creature*)this)->GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->rank);
+ tmpDamage = (tmpDamage + TakenTotal) * TakenTotalMod;
return tmpDamage > 0 ? uint32(tmpDamage) : 0;
}
@@ -8729,39 +9057,36 @@ int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
int32 DoneAdvertisedBenefit = 0;
// ..done
- AuraList const& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
- for(AuraList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
- if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0 &&
+ AuraEffectList const& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
+ for(AuraEffectList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
+ if(((*i)->GetMiscValue() & schoolMask) != 0 &&
(*i)->GetSpellProto()->EquippedItemClass == -1 &&
// -1 == any item class (not wand then)
(*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
// 0 == any inventory type (not wand then)
- DoneAdvertisedBenefit += (*i)->GetModifierValue();
+ DoneAdvertisedBenefit += (*i)->GetAmount();
if (GetTypeId() == TYPEID_PLAYER)
{
+ // Base value
+ DoneAdvertisedBenefit +=((Player*)this)->GetBaseSpellDamageBonus();
+
// Damage bonus from stats
- AuraList const& mDamageDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
- for(AuraList::const_iterator i = mDamageDoneOfStatPercent.begin();i != mDamageDoneOfStatPercent.end(); ++i)
+ AuraEffectList const& mDamageDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
+ for(AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin();i != mDamageDoneOfStatPercent.end(); ++i)
{
- if((*i)->GetModifier()->m_miscvalue & schoolMask)
+ if((*i)->GetMiscValue() & schoolMask)
{
- SpellEntry const* iSpellProto = (*i)->GetSpellProto();
- uint8 eff = (*i)->GetEffIndex();
-
- // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
- Stats usedStat = STAT_INTELLECT;
- if(eff < 2 && iSpellProto->EffectApplyAuraName[eff+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT)
- usedStat = Stats(iSpellProto->EffectMiscValue[eff+1]);
-
- DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifierValue() / 100.0f);
+ // stat used stored in miscValueB for this aura
+ Stats usedStat = Stats((*i)->GetMiscBValue());
+ DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetAmount() / 100.0f);
}
}
// ... and attack power
- AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
- for(AuraList::const_iterator i =mDamageDonebyAP.begin();i != mDamageDonebyAP.end(); ++i)
- if ((*i)->GetModifier()->m_miscvalue & schoolMask)
- DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifierValue() / 100.0f);
+ AuraEffectList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
+ for(AuraEffectList::const_iterator i =mDamageDonebyAP.begin();i != mDamageDonebyAP.end(); ++i)
+ if ((*i)->GetMiscValue() & schoolMask)
+ DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetAmount() / 100.0f);
}
return DoneAdvertisedBenefit;
@@ -8773,16 +9098,16 @@ int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVic
int32 TakenAdvertisedBenefit = 0;
// ..done (for creature type by mask) in taken
- AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
- for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- TakenAdvertisedBenefit += (*i)->GetModifierValue();
+ AuraEffectList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
+ for(AuraEffectList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
+ if(creatureTypeMask & uint32((*i)->GetMiscValue()))
+ TakenAdvertisedBenefit += (*i)->GetAmount();
// ..taken
- AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
- for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
- if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- TakenAdvertisedBenefit += (*i)->GetModifierValue();
+ AuraEffectList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
+ for(AuraEffectList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
+ if(((*i)->GetMiscValue() & schoolMask) != 0)
+ TakenAdvertisedBenefit += (*i)->GetAmount();
return TakenAdvertisedBenefit;
}
@@ -8811,30 +9136,86 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
}
// taken
- if (pVictim && !IsPositiveSpell(spellProto->Id))
- {
- // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
- crit_chance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
- // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
- crit_chance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
- // Modify by player victim resilience
- if (pVictim->GetTypeId() == TYPEID_PLAYER)
- crit_chance -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL);
+ if (pVictim)
+ {
+ if (!IsPositiveSpell(spellProto->Id))
+ {
+ // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
+ crit_chance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
+ // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
+ crit_chance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
+ // Modify by player victim resilience
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
+ crit_chance -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL);
+ }
// scripted (increase crit chance ... against ... target by x%
- if(pVictim->isFrozen()) // Shatter
+ AuraEffectList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
{
- AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
+ if (!((*i)->isAffectedOnSpell(spellProto)))
+ continue;
+ int32 modChance=0;
+ switch((*i)->GetMiscValue())
{
- switch((*i)->GetModifier()->m_miscvalue)
+ // Shatter
+ case 911: modChance+= 16.0f;
+ case 910: modChance+= 17.0f;
+ case 849: modChance+= 17.0f;
+ if (!pVictim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
+ break;
+ crit_chance+=modChance;
+ // Fingers of Frost
+ // TODO: Change this code to less hacky
+ if (Aura * aur = GetAura(44544))
+ aur->DropAuraCharge();
+ break;
+ case 7917: // Glyph of Shadowburn
+ if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
+ crit_chance+=(*i)->GetAmount();
+ break;
+ case 7997: // Renewed Hope
+ case 7998:
+ if (pVictim->HasAura(6788))
+ crit_chance+=(*i)->GetAmount();
+ break;
+ case 21: // Test of Faith
+ case 6935:
+ case 6918:
+ if (pVictim->GetHealth() < pVictim->GetMaxHealth()/2)
+ crit_chance+=(*i)->GetAmount();
+ break;
+ default:
+ break;
+ }
+ }
+ // Custom crit by class
+ switch(spellProto->SpellFamilyName)
+ {
+ case SPELLFAMILY_PALADIN:
+ // Sacred Shield
+ if (spellProto->SpellFamilyFlags[0] & 0x40000000)
{
- case 849: crit_chance+= 10.0f; break; //Shatter Rank 1
- case 910: crit_chance+= 20.0f; break; //Shatter Rank 2
- case 911: crit_chance+= 30.0f; break; //Shatter Rank 3
- case 912: crit_chance+= 40.0f; break; //Shatter Rank 4
- case 913: crit_chance+= 50.0f; break; //Shatter Rank 5
+ AuraEffect *aura = pVictim->GetDummyAura(58597);
+ if (aura && aura->GetCasterGUID() == GetGUID())
+ crit_chance+=aura->GetAmount();
+ break;
}
- }
+ break;
+ case SPELLFAMILY_SHAMAN:
+ // Lava Burst
+ if (spellProto->SpellFamilyFlags[1] & 0x00001000)
+ {
+ if (AuraEffect *flameShock = pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 10000000, 0,0, GetGUID()))
+ {
+ // Consume shock aura if not have Glyph of Flame Shock
+ if (!GetAuraEffect(55447, 0))
+ pVictim->RemoveAurasDueToSpell(flameShock->GetId(), GetGUID());
+ return true;
+ }
+ break;
+ }
+ break;
+
}
}
break;
@@ -8845,7 +9226,6 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
if (pVictim)
{
crit_chance = GetUnitCriticalChance(attackType, pVictim);
- crit_chance+= (int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetDefenseSkillValue(this))) * 0.04f;
crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
}
break;
@@ -8864,7 +9244,7 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
return false;
}
-uint32 Unit::SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim)
+uint32 Unit::SpellCriticalDamageBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim)
{
// Calculate critical bonus
int32 crit_bonus;
@@ -8896,238 +9276,327 @@ uint32 Unit::SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Uni
return damage;
}
-uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim)
+uint32 Unit::SpellCriticalHealingBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim)
+{
+ // Calculate critical bonus
+ int32 crit_bonus;
+ switch(spellProto->DmgClass)
+ {
+ case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
+ case SPELL_DAMAGE_CLASS_RANGED:
+ // TODO: write here full calculation for melee/ranged spells
+ crit_bonus = damage;
+ break;
+ default:
+ crit_bonus = damage / 2; // for spells is 50%
+ break;
+ }
+
+
+ if(pVictim)
+ {
+ uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
+ crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
+ }
+
+ if(crit_bonus > 0)
+ damage += crit_bonus;
+
+ damage = int32(float(damage) * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
+
+ return damage;
+}
+
+uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack)
{
// For totems get healing bonus from owner (statue isn't totem in fact)
- if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE)
+ if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem())
if(Unit* owner = GetOwner())
- return owner->SpellHealingBonus(spellProto, healamount, damagetype, pVictim);
+ return owner->SpellHealingBonus(pVictim, spellProto, healamount, damagetype, stack);
// Healing Done
+ // Taken/Done total percent damage auras
+ float DoneTotalMod = 1.0f;
+ float TakenTotalMod = 1.0f;
+ int32 DoneTotal = 0;
+ int32 TakenTotal = 0;
- // These Spells are doing fixed amount of healing (TODO found less hack-like check)
- if (spellProto->Id == 15290 || spellProto->Id == 39373 ||
- spellProto->Id == 33778 || spellProto->Id == 379 ||
- spellProto->Id == 38395 || spellProto->Id == 40972 ||
- spellProto->Id == 22845 || spellProto->Id == 33504 ||
- spellProto->Id == 34299 || spellProto->Id == 27813 ||
- spellProto->Id == 27817 || spellProto->Id == 27818)
- return healamount;
-
- int32 AdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto));
- uint32 CastingTime = GetSpellCastTime(spellProto);
-
- // Healing Taken
- AdvertisedBenefit += SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
+ // Healing done percent
+ AuraEffectList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
+ for(AuraEffectList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
+ DoneTotalMod *= (100.0f + (*i)->GetAmount()) / 100.0f;
- // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
- if (spellProto->SpellFamilyName == SPELLFAMILY_PALADIN && (spellProto->SpellFamilyFlags & 0x00000000C0000000LL))
+ // done scripted mod (take it from owner)
+ Unit *owner = GetOwner();
+ if (!owner) owner = this;
+ AuraEffectList const& mOverrideClassScript= owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
{
- AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
- for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
+ if (!(*i)->isAffectedOnSpell(spellProto))
+ continue;
+ switch((*i)->GetMiscValue())
{
- if((*i)->GetSpellProto()->SpellVisual == 9180)
+ case 4415: // Increased Rejuvenation Healing
+ case 4953:
+ case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
+ DoneTotal+=(*i)->GetAmount();
+ break;
+ case 7997: // Renewed Hope
+ case 7998:
+ if (pVictim->HasAura(6788))
+ DoneTotalMod *=((*i)->GetAmount() + 100.0f)/100.0f;
+ break;
+ case 21: // Test of Faith
+ case 6935:
+ case 6918:
+ if (pVictim->GetHealth() < pVictim->GetMaxHealth()/2)
+ DoneTotalMod *=((*i)->GetAmount() + 100.0f)/100.0f;
+ break;
+ case 7798: // Glyph of Regrowth
{
- // Flash of Light
- if ((spellProto->SpellFamilyFlags & 0x0000000040000000LL) && (*i)->GetEffIndex() == 1)
- AdvertisedBenefit += (*i)->GetModifier()->m_amount;
- // Holy Light
- else if ((spellProto->SpellFamilyFlags & 0x0000000080000000LL) && (*i)->GetEffIndex() == 0)
- AdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ if (pVictim->GetAura(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x40, 0))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ break;
}
+ case 8477: // Nourish Heal Boost
+ {
+ int32 stepPercent = (*i)->GetAmount();
+ int32 modPercent = 0;
+ AuraMap const& victimAuras = pVictim->GetAuras();
+ for (AuraMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
+ {
+ if (itr->second->GetCasterGUID()!=GetGUID())
+ continue;
+ SpellEntry const* m_spell = itr->second->GetSpellProto();
+ if ( m_spell->SpellFamilyName != SPELLFAMILY_DRUID ||
+ !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50))
+ continue;
+ modPercent += stepPercent * itr->second->GetStackAmount();
+ }
+ DoneTotalMod *= (modPercent+100.0f)/100.0f;
+ break;
+ }
+ case 7871: // Glyph of Lesser Healing Wave
+ {
+ if (pVictim->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0 , 0x00000400, 0, GetGUID()))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ break;
+ }
+ default:
+ break;
}
}
- float ActualBenefit = 0.0f;
+ // Taken/Done fixed damage bonus auras
+ int32 DoneAdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto));
+ int32 TakenAdvertisedBenefit = SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
- if (AdvertisedBenefit != 0)
+ bool scripted = false;
+
+ for (uint8 i=0;i<3;++i)
{
- // Healing over Time spells
- float DotFactor = 1.0f;
- if(damagetype == DOT)
+ switch (spellProto->EffectApplyAuraName[i])
{
- int32 DotDuration = GetSpellDuration(spellProto);
- if(DotDuration > 0)
- {
- // 200% limit
- if(DotDuration > 30000) DotDuration = 30000;
- if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
- int x = 0;
- for(int j = 0; j < 3; j++)
- {
- if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
- spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_HEAL ||
- spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
- {
- x = j;
- break;
- }
- }
- int DotTicks = 6;
- if(spellProto->EffectAmplitude[x] != 0)
- DotTicks = DotDuration / spellProto->EffectAmplitude[x];
- if(DotTicks)
- AdvertisedBenefit /= DotTicks;
- }
+ // These auras do not use healing coeff
+ case SPELL_AURA_PERIODIC_LEECH:
+ case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
+ scripted = true;
+ break;
}
+ }
- // distribute healing to all effects, reduce AoE damage
- CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
-
- // 0% bonus for damage and healing spells for leech spells from healing bonus
- for(int j = 0; j < 3; ++j)
+ // Check for table values
+ SpellBonusEntry const* bonus = !scripted ? spellmgr.GetSpellBonusData(spellProto->Id) : NULL;
+ float coeff;
+ float factorMod = 1.0f;
+ if (bonus)
+ {
+ if (damagetype == DOT)
+ coeff = bonus->dot_damage;
+ else
+ coeff = bonus->direct_damage;
+ if (bonus->ap_bonus)
+ DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack;
+ }
+ else // scripted bonus
+ {
+ // Gift of the Naaru
+ if (spellProto->Id==59547)
{
- if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
- spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
+ scripted = true;
+ uint32 apBonus = GetTotalAttackPowerValue(BASE_ATTACK);
+ if (apBonus > DoneAdvertisedBenefit)
{
- CastingTime = 0;
- break;
+ DoneTotal+=apBonus * stack;
+ coeff = 0.0f;
}
+ else
+ coeff = 1.0f;
+ }
+ // Earthliving - 0.45% of normal hot coeff
+ else if (spellProto->SpellFamilyName==SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags[1] & 0x80000)
+ {
+ factorMod *= 0.45f;
}
+ // Already set to scripted? so not uses healing bonus coefficient
+ // No heal coeff for SPELL_DAMAGE_CLASS_NONE class spells by default
+ else if (scripted || spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
+ {
+ coeff = 0.0f;
+ }
+ }
- // Exception
- switch (spellProto->SpellFamilyName)
+ // Default calculation
+ if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
+ {
+ if(!bonus && !scripted)
{
- case SPELLFAMILY_SHAMAN:
- // Healing stream from totem (add 6% per tick from hill bonus owner)
- if (spellProto->SpellFamilyFlags & 0x000000002000LL)
- CastingTime = 210;
- // Earth Shield 30% per charge
- else if (spellProto->SpellFamilyFlags & 0x40000000000LL)
- CastingTime = 1050;
- break;
- case SPELLFAMILY_DRUID:
- // Lifebloom
- if (spellProto->SpellFamilyFlags & 0x1000000000LL)
- {
- CastingTime = damagetype == DOT ? 3500 : 1200;
- DotFactor = damagetype == DOT ? 0.519f : 1.0f;
- }
- // Tranquility triggered spell
- else if (spellProto->SpellFamilyFlags & 0x80LL)
- CastingTime = 667;
- // Rejuvenation
- else if (spellProto->SpellFamilyFlags & 0x10LL)
- DotFactor = 0.845f;
- // Regrowth
- else if (spellProto->SpellFamilyFlags & 0x40LL)
+ // Damage Done from spell damage bonus
+ int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
+ // Damage over Time spells bonus calculation
+ float DotFactor = 1.0f;
+ if(damagetype == DOT)
+ {
+ int32 DotDuration = GetSpellDuration(spellProto);
+ // 200% limit
+ if(DotDuration > 0)
{
- DotFactor = damagetype == DOT ? 0.705f : 1.0f;
- CastingTime = damagetype == DOT ? 3500 : 1010;
+ if(DotDuration > 30000) DotDuration = 30000;
+ if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
+ int x = 0;
+ for(int j = 0; j < 3; j++)
+ {
+ if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
+ spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
+ spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
+ {
+ x = j;
+ break;
+ }
+ }
+ int32 DotTicks = 6;
+ if(spellProto->EffectAmplitude[x] != 0)
+ DotTicks = DotDuration / spellProto->EffectAmplitude[x];
+ if(DotTicks)
+ {
+ DoneAdvertisedBenefit = DoneAdvertisedBenefit * int32(stack) / DotTicks;
+ TakenAdvertisedBenefit = TakenAdvertisedBenefit * int32(stack) / DotTicks;
+ }
}
- // Improved Leader of the Pack
- else if (spellProto->AttributesEx2 == 536870912 && spellProto->SpellIconID == 312
- && spellProto->AttributesEx3 == 33554432)
+ }
+ // Distribute Damage over multiple effects, reduce by AoE
+ CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
+ // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
+ for(int j = 0; j < 3; ++j)
+ {
+ if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
+ spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
{
- CastingTime = 0;
+ CastingTime /= 2;
+ break;
}
- break;
- case SPELLFAMILY_PRIEST:
- // Holy Nova - 14%
- if ((spellProto->SpellFamilyFlags & 0x8000000LL) && spellProto->SpellIconID == 1874)
- CastingTime = 500;
- break;
- case SPELLFAMILY_PALADIN:
- // Seal and Judgement of Light
- if ( spellProto->SpellFamilyFlags & 0x100040000LL )
- CastingTime = 0;
- break;
- case SPELLFAMILY_WARRIOR:
- case SPELLFAMILY_ROGUE:
- case SPELLFAMILY_HUNTER:
- CastingTime = 0;
- break;
+ }
+ // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells)
+ coeff = (CastingTime / 3500.0f) * DotFactor * 1.88f;
}
- float LvlPenalty = CalculateLevelPenalty(spellProto);
-
- // Spellmod SpellDamage
- //float SpellModSpellDamage = 100.0f;
- float CoefficientPtc = ((float)CastingTime/3500.0f)*DotFactor*100.0f;
-
+ factorMod *= CalculateLevelPenalty(spellProto)* stack;
+ TakenTotal += TakenAdvertisedBenefit * coeff * factorMod;
if(Player* modOwner = GetSpellModOwner())
- //modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage);
- modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,CoefficientPtc);
-
- //SpellModSpellDamage /= 100.0f;
- CoefficientPtc /= 100.0f;
-
- //ActualBenefit = (float)AdvertisedBenefit * ((float)CastingTime / 3500.0f) * DotFactor * SpellModSpellDamage * LvlPenalty;
- ActualBenefit = (float)AdvertisedBenefit * CoefficientPtc * LvlPenalty;
+ {
+ coeff *= 100.0f;
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_SPELL_BONUS_DAMAGE, coeff);
+ coeff /= 100.0f;
+ }
+ DoneTotal += DoneAdvertisedBenefit * coeff * factorMod;
}
// use float as more appropriate for negative values and percent applying
- float heal = healamount + ActualBenefit;
-
- // TODO: check for ALL/SPELLS type
- // Healing done percent
- AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
- for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
- heal *= (100.0f + (*i)->GetModifierValue()) / 100.0f;
-
+ float heal = (healamount + DoneTotal)*DoneTotalMod;
// apply spellmod to Done amount
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
+ // Nourish cast
+ if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
+ {
+ // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
+ if (pVictim->GetAura(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x50, 0x4000010, 0))
+ //increase healing by 20%
+ TakenTotalMod *= 1.2f;
+ }
+
+ // Taken mods
// Healing Wave cast
- if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags & 0x0000000000000040LL)
+ if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags[0] & 0x40)
{
- // Search for Healing Way on Victim (stack up to 3 time)
- int32 pctMod = 0;
- Unit::AuraList const& auraDummy = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr!=auraDummy.end(); ++itr)
- {
+ // Search for Healing Way on Victim
+ Unit::AuraEffectList const& auraDummy = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator itr = auraDummy.begin(); itr!=auraDummy.end(); ++itr)
if((*itr)->GetId() == 29203)
- {
- pctMod = (*itr)->GetModifier()->m_amount * (*itr)->GetStackAmount();
- break;
- }
- }
- // Apply bonus
- if (pctMod)
- heal = heal * (100 + pctMod) / 100;
+ TakenTotalMod *= ((*itr)->GetAmount()+100.0f) / 100.0f;
}
// Healing taken percent
float minval = pVictim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
if(minval)
- heal *= (100.0f + minval) / 100.0f;
+ TakenTotalMod *= (100.0f + minval) / 100.0f;
float maxval = pVictim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
if(maxval)
- heal *= (100.0f + maxval) / 100.0f;
+ TakenTotalMod *= (100.0f + maxval) / 100.0f;
+
+ if(damagetype==DOT)
+ {
+ // Healing over time taken percent
+ float minval_hot = pVictim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT);
+ if(minval_hot)
+ TakenTotalMod *= (100.0f + minval_hot) / 100.0f;
+
+ float maxval_hot = pVictim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT);
+ if(maxval_hot)
+ TakenTotalMod *= (100.0f + maxval_hot) / 100.0f;
+ }
+
+ AuraEffectList const& mHealingGet= pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING_RECEIVED);
+ for(AuraEffectList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i)
+ if (GetGUID()==(*i)->GetCasterGUID() && (*i)->isAffectedOnSpell(spellProto) )
+ TakenTotalMod *= ((*i)->GetAmount() + 100.0f) / 100.0f;
- if (heal < 0) heal = 0;
+ heal = (heal + TakenTotal) * TakenTotalMod;
- return uint32(heal);
+ return heal < 0 ? 0 : uint32(heal);
}
int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
{
int32 AdvertisedBenefit = 0;
- AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
- for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
- if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetModifierValue();
+ AuraEffectList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
+ for(AuraEffectList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
+ if(((*i)->GetMiscValue() & schoolMask) != 0)
+ AdvertisedBenefit += (*i)->GetAmount();
// Healing bonus of spirit, intellect and strength
if (GetTypeId() == TYPEID_PLAYER)
{
+ // Base value
+ AdvertisedBenefit +=((Player*)this)->GetBaseSpellHealingBonus();
+
// Healing bonus from stats
- AuraList const& mHealingDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
- for(AuraList::const_iterator i = mHealingDoneOfStatPercent.begin();i != mHealingDoneOfStatPercent.end(); ++i)
+ AuraEffectList const& mHealingDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
+ for(AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin();i != mHealingDoneOfStatPercent.end(); ++i)
{
// stat used dependent from misc value (stat index)
Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]);
- AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifierValue() / 100.0f);
+ AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetAmount() / 100.0f);
}
// ... and attack power
- AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
- for(AuraList::const_iterator i = mHealingDonebyAP.begin();i != mHealingDonebyAP.end(); ++i)
- if ((*i)->GetModifier()->m_miscvalue & schoolMask)
- AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifierValue() / 100.0f);
+ AuraEffectList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
+ for(AuraEffectList::const_iterator i = mHealingDonebyAP.begin();i != mHealingDonebyAP.end(); ++i)
+ if ((*i)->GetMiscValue() & schoolMask)
+ AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetAmount() / 100.0f);
}
return AdvertisedBenefit;
}
@@ -9135,14 +9604,14 @@ int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim)
{
int32 AdvertisedBenefit = 0;
- AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING);
- for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
- if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetModifierValue();
+ AuraEffectList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING);
+ for(AuraEffectList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
+ if(((*i)->GetMiscValue() & schoolMask) != 0)
+ AdvertisedBenefit += (*i)->GetAmount();
return AdvertisedBenefit;
}
-bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask, bool useCharges)
+bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask)
{
//If m_immuneToSchool type contain this school type, IMMUNE damage.
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
@@ -9159,60 +9628,100 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask, bool useCharges)
return false;
}
-bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
+bool Unit::IsImmunedToDamage(SpellEntry const* spellInfo)
+{
+ uint32 shoolMask = GetSpellSchoolMask(spellInfo);
+ if(spellInfo->Id != 42292 && spellInfo->Id !=59752)
+ {
+ //If m_immuneToSchool type contain this school type, IMMUNE damage.
+ SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ if(itr->type & shoolMask &&!IsDispelableBySpell(spellInfo, itr->spellId))
+ return true;
+ }
+
+ //If m_immuneToDamage type contain magic, IMMUNE damage.
+ SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
+ for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
+ if(itr->type & shoolMask)
+ return true;
+
+ return false;
+}
+
+bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo)
{
if (!spellInfo)
return false;
- SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
- for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
- if(itr->type == spellInfo->Dispel)
+ // Single spell immunity.
+ SpellImmuneList const& idList = m_spellImmune[IMMUNITY_ID];
+ for(SpellImmuneList::const_iterator itr = idList.begin(); itr != idList.end(); ++itr)
+ if(itr->type == spellInfo->Id)
return true;
- if( !(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE) && // unaffected by school immunity
- !(spellInfo->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY) // can remove immune (by dispell or immune it)
- && (spellInfo->Id != 42292))
+ if(spellInfo->Dispel)
{
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if( !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) &&
- (itr->type & GetSpellSchoolMask(spellInfo)) )
+ SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
+ for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
+ if(itr->type == spellInfo->Dispel)
return true;
}
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
+ if(spellInfo->Mechanic)
{
- if(itr->type == spellInfo->Mechanic)
- {
- return true;
- }
+ SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
+ for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
+ if(itr->type == spellInfo->Mechanic)
+ return true;
}
- SpellImmuneList const& idList = m_spellImmune[IMMUNITY_ID];
- for(SpellImmuneList::const_iterator itr = idList.begin(); itr != idList.end(); ++itr)
+ if(spellInfo->Id != 42292 && spellInfo->Id !=59752)
{
- if(itr->type == spellInfo->Id)
- {
- return true;
- }
+ SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ if((itr->type & GetSpellSchoolMask(spellInfo))
+ && !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id))
+ && !IsDispelableBySpell(spellInfo, itr->spellId))
+ return true;
}
return false;
}
-bool Unit::IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const
+bool Unit::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
{
+ if (!spellInfo)
+ return false;
//If m_immuneToEffect type contain this effect type, IMMUNE effect.
+ uint32 effect = spellInfo->Effect[index];
SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
if(itr->type == effect)
return true;
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- if(itr->type == mechanic)
- return true;
+ if(uint32 mechanic = spellInfo->EffectMechanic[index])
+ {
+ SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
+ for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
+ if(itr->type == spellInfo->EffectMechanic[index])
+ return true;
+ }
+
+ if(uint32 aura = spellInfo->EffectApplyAuraName[index])
+ {
+ SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
+ for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
+ if(itr->type == aura)
+ return true;
+ // Check for immune to application of harmful magical effects
+ AuraEffectList const& immuneAuraApply = GetAurasByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
+ for(AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
+ if (spellInfo->Dispel == DISPEL_MAGIC && // Magic debuff
+ ((*iter)->GetMiscValue() & GetSpellSchoolMask(spellInfo)) && // Check school
+ !IsPositiveEffect(spellInfo->Id, index)) // Harmful
+ return true;
+ }
return false;
}
@@ -9247,10 +9756,10 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
int32 TakenFlatBenefit = 0;
// ..done (for creature type by mask) in taken
- AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
- for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- DoneFlatBenefit += (*i)->GetModifierValue();
+ AuraEffectList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
+ for(AuraEffectList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
+ if(creatureTypeMask & uint32((*i)->GetMiscValue()))
+ DoneFlatBenefit += (*i)->GetAmount();
// ..done
// SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
@@ -9262,20 +9771,20 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
// ..done (base at attack power and creature type)
- AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
- for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- APbonus += (*i)->GetModifierValue();
+ AuraEffectList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
+ for(AuraEffectList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
+ if(creatureTypeMask & uint32((*i)->GetMiscValue()))
+ APbonus += (*i)->GetAmount();
}
else
{
APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS);
// ..done (base at attack power and creature type)
- AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
- for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- APbonus += (*i)->GetModifierValue();
+ AuraEffectList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
+ for(AuraEffectList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
+ if(creatureTypeMask & uint32((*i)->GetMiscValue()))
+ APbonus += (*i)->GetAmount();
}
if (APbonus!=0) // Can be negative
@@ -9297,10 +9806,10 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
}
// ..taken
- AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
- for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
- if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
- TakenFlatBenefit += (*i)->GetModifierValue();
+ AuraEffectList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
+ for(AuraEffectList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
+ if((*i)->GetMiscValue() & GetMeleeDamageSchoolMask())
+ TakenFlatBenefit += (*i)->GetAmount();
if(attType!=RANGED_ATTACK)
TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
@@ -9308,39 +9817,39 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
// Done/Taken total percent damage auras
- float DoneTotalMod = 1;
- float TakenTotalMod = 1;
+ float DoneTotalMod = 1.0f;
+ float TakenTotalMod = 1.0f;
// ..done
// SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
// SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
- AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
- for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- DoneTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
+ AuraEffectList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
+ for(AuraEffectList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
+ if(creatureTypeMask & uint32((*i)->GetMiscValue()))
+ DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
// ..taken
- AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
- for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
- if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
- TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
+ AuraEffectList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
+ for(AuraEffectList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
+ if((*i)->GetMiscValue() & GetMeleeDamageSchoolMask())
+ TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
// .. taken pct: dummy auras
- AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
- for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
+ AuraEffectList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
+ for(AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
{
switch((*i)->GetSpellProto()->SpellIconID)
{
//Cheat Death
case 2109:
- if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
+ if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
{
if(pVictim->GetTypeId() != TYPEID_PLAYER)
continue;
float mod = ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*(-8.0f);
- if (mod < (*i)->GetModifier()->m_amount)
- mod = (*i)->GetModifier()->m_amount;
+ if (mod < (*i)->GetAmount())
+ mod = (*i)->GetAmount();
TakenTotalMod *= (mod+100.0f)/100.0f;
}
break;
@@ -9349,22 +9858,22 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
if(spellProto==NULL)
break;
// Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
- if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && (spellProto->SpellFamilyFlags==0x00008000LL))
- TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f;
+ if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags.IsEqual (0x00008000,0,0))
+ TakenTotalMod *= (100.0f+(*i)->GetAmount())/100.0f;
break;
}
}
// .. taken pct: class scripts
- AuraList const& mclassScritAuras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i)
+ AuraEffectList const& mclassScritAuras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(AuraEffectList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i)
{
switch((*i)->GetMiscValue())
{
case 6427: case 6428: // Dirty Deeds
- if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
+ if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
{
- Aura* eff0 = GetAura((*i)->GetId(),0);
+ AuraEffect* eff0 = (*i)->GetParentAura()->GetPartAura(0);
if(!eff0 || (*i)->GetEffIndex()!=1)
{
sLog.outError("Spell structure of DD (%u) changed.",(*i)->GetId());
@@ -9372,7 +9881,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
}
// effect 0 have expected value but in negative state
- TakenTotalMod *= (-eff0->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= (-eff0->GetAmount()+100.0f)/100.0f;
}
break;
}
@@ -9380,15 +9889,15 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
if(attType != RANGED_ATTACK)
{
- AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
- for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
- TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
+ AuraEffectList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
+ for(AuraEffectList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
+ TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
}
else
{
- AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
- for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
- TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
+ AuraEffectList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
+ for(AuraEffectList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
+ TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
}
float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod;
@@ -9443,7 +9952,23 @@ void Unit::ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType ty
ApplySpellImmune(spellProto->Id,IMMUNITY_DISPEL, type, apply);
if (apply && spellProto->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
- RemoveAurasWithDispelType(type);
+ {
+ // Create dispel mask by dispel type
+ uint32 dispelMask = GetDispellMask(type);
+ // Dispel all existing auras vs current dispel type
+ AuraMap& auras = GetAuras();
+ for(AuraMap::iterator itr = auras.begin(); itr != auras.end(); )
+ {
+ SpellEntry const* spell = itr->second->GetSpellProto();
+ if( (1<<spell->Dispel) & dispelMask )
+ {
+ // Dispel aura
+ RemoveAura(itr);
+ }
+ else
+ ++itr;
+ }
+ }
}
float Unit::GetWeaponProcChance() const
@@ -9457,42 +9982,31 @@ float Unit::GetWeaponProcChance() const
return 0;
}
-float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const
+float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellEntry * spellProto) const
{
// proc per minute chance calculation
if (PPM <= 0) return 0.0f;
+ // Apply chance modifer aura
+ if (spellProto)
+ if(Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_PROC_PER_MINUTE,PPM);
+
uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
return result;
}
void Unit::Mount(uint32 mount)
{
- if(!mount)
- return;
-
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNT);
- SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
+ if(mount)
+ SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT );
// unsummon pet
if(GetTypeId() == TYPEID_PLAYER)
- {
- Pet* pet = GetPet();
- if(pet)
- {
- if(pet->isControlled())
- {
- ((Player*)this)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
- ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
- }
-
- ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
- }
- else
- ((Player*)this)->SetTemporaryUnsummonedPetNumber(0);
- }
+ ((Player*)this)->UnsummonPetTemporaryIfAny();
}
void Unit::Unmount()
@@ -9508,14 +10022,8 @@ void Unit::Unmount()
// only resummon old pet if the player is already added to a map
// this prevents adding a pet to a not created map which would otherwise cause a crash
// (it could probably happen when logging in after a previous crash)
- if(GetTypeId() == TYPEID_PLAYER && IsInWorld() && ((Player*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
- {
- Pet* NewPet = new Pet;
- if(!NewPet->LoadPetFromDB(this, 0, ((Player*)this)->GetTemporaryUnsummonedPetNumber(), true))
- delete NewPet;
-
- ((Player*)this)->SetTemporaryUnsummonedPetNumber(0);
- }
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny();
}
void Unit::SetInCombatWith(Unit* enemy)
@@ -9523,7 +10031,7 @@ void Unit::SetInCombatWith(Unit* enemy)
Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf();
if(eOwner->IsPvP())
{
- SetInCombatState(true);
+ SetInCombatState(true,enemy);
return;
}
@@ -9533,27 +10041,22 @@ void Unit::SetInCombatWith(Unit* enemy)
Unit const* myOwner = GetCharmerOrOwnerOrSelf();
if(((Player const*)eOwner)->duel->opponent == myOwner)
{
- SetInCombatState(true);
+ SetInCombatState(true,enemy);
return;
}
}
- SetInCombatState(false);
+ SetInCombatState(false,enemy);
}
void Unit::CombatStart(Unit* target)
{
if(!target->IsStandState()/* && !target->hasUnitState(UNIT_STAT_STUNNED)*/)
- target->SetStandState(PLAYER_STATE_NONE);
+ target->SetStandState(UNIT_STAND_STATE_STAND);
if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
&& !((Creature*)target)->HasReactState(REACT_PASSIVE) && ((Creature*)target)->IsAIEnabled)
{
((Creature*)target)->AI()->AttackStart(this);
- if(((Creature*)target)->GetFormation())
- {
- ((Creature*)target)->GetFormation()->MemberAttackStart((Creature*)target, this);
- sLog.outDebug("Unit::CombatStart() calls CreatureGroups::MemberHasAttacked(this);");
- }
}
SetInCombatWith(target);
@@ -9571,10 +10074,9 @@ void Unit::CombatStart(Unit* target)
me->UpdatePvP(true);
me->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
}
-
}
-void Unit::SetInCombatState(bool PvP)
+void Unit::SetInCombatState(bool PvP, Unit* enemy)
{
// only alive units can be in combat
if(!isAlive())
@@ -9588,8 +10090,18 @@ void Unit::SetInCombatState(bool PvP)
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- if(GetTypeId() != TYPEID_PLAYER && GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != IDLE_MOTION_TYPE)
- ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
+ if(GetTypeId() != TYPEID_PLAYER)
+ {
+ //if(GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != IDLE_MOTION_TYPE)
+ ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
+ if(enemy)
+ {
+ if(((Creature*)this)->IsAIEnabled)
+ ((Creature*)this)->AI()->EnterCombat(enemy);
+ if(((Creature*)this)->GetFormation())
+ ((Creature*)this)->GetFormation()->MemberAttackStart((Creature*)this, enemy);
+ }
+ }
if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
{
@@ -9611,6 +10123,8 @@ void Unit::ClearInCombat()
// Player's state will be cleared in Player::UpdateContestedPvP
if(GetTypeId()!=TYPEID_PLAYER)
clearUnitState(UNIT_STAT_ATTACK_PLAYER);
+ else
+ ((Player*)this)->UpdatePotionCooldown();
if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
{
@@ -9668,7 +10182,7 @@ bool Unit::isAttackableByAOE() const
if(GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
return false;
- return !isInFlight();
+ return !hasUnitState(UNIT_STAT_UNATTACKABLE);
}
int32 Unit::ModifyHealth(int32 dVal)
@@ -9703,6 +10217,35 @@ int32 Unit::ModifyHealth(int32 dVal)
return gain;
}
+int32 Unit::GetHealthGain(int32 dVal)
+{
+ int32 gain = 0;
+
+ if(dVal==0)
+ return 0;
+
+ int32 curHealth = (int32)GetHealth();
+
+ int32 val = dVal + curHealth;
+ if(val <= 0)
+ {
+ return -curHealth;
+ }
+
+ int32 maxHealth = (int32)GetMaxHealth();
+
+ if(val < maxHealth)
+ {
+ gain = dVal;
+ }
+ else if(curHealth != maxHealth)
+ {
+ gain = maxHealth - curHealth;
+ }
+
+ return gain;
+}
+
int32 Unit::ModifyPower(Powers power, int32 dVal)
{
int32 gain = 0;
@@ -9752,8 +10295,8 @@ bool Unit::canDetectInvisibilityOf(Unit const* u) const
{
if(m_invisibilityMask & u->m_invisibilityMask) // same group
return true;
- AuraList const& auras = u->GetAurasByType(SPELL_AURA_MOD_STALKED); // Hunter mark
- for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
+ AuraEffectList const& auras = u->GetAurasByType(SPELL_AURA_MOD_STALKED); // Hunter mark
+ for(AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
if((*iter)->GetCasterGUID()==GetGUID())
return true;
@@ -9766,10 +10309,10 @@ bool Unit::canDetectInvisibilityOf(Unit const* u) const
// find invisibility level
uint32 invLevel = 0;
- Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
- for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
- if(((*itr)->GetModifier()->m_miscvalue)==i && invLevel < (*itr)->GetModifier()->m_amount)
- invLevel = (*itr)->GetModifier()->m_amount;
+ Unit::AuraEffectList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
+ for(Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
+ if(((*itr)->GetMiscValue())==i && invLevel < (*itr)->GetAmount())
+ invLevel = (*itr)->GetAmount();
// find invisibility detect level
uint32 detectLevel = 0;
@@ -9779,10 +10322,10 @@ bool Unit::canDetectInvisibilityOf(Unit const* u) const
}
else
{
- Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
- for(Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr)
- if(((*itr)->GetModifier()->m_miscvalue)==i && detectLevel < (*itr)->GetModifier()->m_amount)
- detectLevel = (*itr)->GetModifier()->m_amount;
+ Unit::AuraEffectList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
+ for(Unit::AuraEffectList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr)
+ if(((*itr)->GetMiscValue())==i && detectLevel < (*itr)->GetAmount())
+ detectLevel = (*itr)->GetAmount();
}
if(invLevel <= detectLevel)
@@ -9804,8 +10347,8 @@ bool Unit::canDetectStealthOf(Unit const* target, float distance) const
if(HasAuraType(SPELL_AURA_DETECT_STEALTH))
return true;
- AuraList const& auras = target->GetAurasByType(SPELL_AURA_MOD_STALKED); // Hunter mark
- for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
+ AuraEffectList const& auras = target->GetAurasByType(SPELL_AURA_MOD_STALKED); // Hunter mark
+ for(AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
if((*iter)->GetCasterGUID()==GetGUID())
return true;
@@ -9827,7 +10370,7 @@ void Unit::DestroyForNearbyPlayers()
std::list<Unit*> targets;
Trinity::AnyUnitInObjectRangeCheck check(this, World::GetMaxVisibleDistance());
- Trinity::UnitListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(targets, check);
+ Trinity::UnitListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(this, targets, check);
VisitNearbyWorldObject(World::GetMaxVisibleDistance(), searcher);
for(std::list<Unit*>::iterator iter = targets.begin(); iter != targets.end(); ++iter)
if(*iter != this && (*iter)->GetTypeId() == TYPEID_PLAYER
@@ -9886,12 +10429,33 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
return;
case MOVE_FLIGHT:
{
- if (IsMounted()) // Use on mount auras
- main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED);
+ if (GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isVehicle())
+ {
+ main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED);
+ stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS);
+
+ // for some spells this mod is applied on vehicle owner
+ uint32 owner_speed_mod = 0;
+
+ if (Unit * owner = ((Vehicle*)this)->GetCharmer())
+ uint32 owner_speed_mod = owner->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED);
+
+ main_speed_mod = main_speed_mod>owner_speed_mod ? main_speed_mod : owner_speed_mod;
+ }
+ else if (IsMounted())
+ {
+ main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED);
+ stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS);
+ }
else // Use not mount (shapeshift for example) auras (should stack)
- main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT);
- stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS);
+ main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED);
+
non_stack_bonus = (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK))/100.0f;
+
+ // Update speed for vehicle if avalible
+ if (GetTypeId()==TYPEID_PLAYER)
+ if (Unit * vehicle = ((Player*)this)->m_Vehicle)
+ vehicle->UpdateSpeed(MOVE_FLIGHT, true);
break;
}
case MOVE_FLIGHT_BACK:
@@ -9951,38 +10515,37 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
propagateSpeedChange();
- // Send speed change packet only for player
- if (GetTypeId()!=TYPEID_PLAYER)
- return;
-
WorldPacket data;
if(!forced)
{
switch(mtype)
{
case MOVE_WALK:
- data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+1+4+4+4+4+4+4+4);
+ data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+2+4+4+4+4+4+4+4);
break;
case MOVE_RUN:
- data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+1+4+4+4+4+4+4+4);
+ data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+2+4+4+4+4+4+4+4);
break;
case MOVE_RUN_BACK:
- data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4);
+ data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4);
break;
case MOVE_SWIM:
- data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+1+4+4+4+4+4+4+4);
+ data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+2+4+4+4+4+4+4+4);
break;
case MOVE_SWIM_BACK:
- data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4);
+ data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4);
break;
case MOVE_TURN_RATE:
- data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+1+4+4+4+4+4+4+4);
+ data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+2+4+4+4+4+4+4+4);
break;
case MOVE_FLIGHT:
- data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+1+4+4+4+4+4+4+4);
+ data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+2+4+4+4+4+4+4+4);
break;
case MOVE_FLIGHT_BACK:
- data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4);
+ data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4);
+ break;
+ case MOVE_PITCH_RATE:
+ data.Initialize(MSG_MOVE_SET_PITCH_RATE, 8+4+2+4+4+4+4+4+4+4);
break;
default:
sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
@@ -9990,22 +10553,30 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
}
data.append(GetPackGUID());
- data << uint32(0); //movement flags
- data << uint8(0); //unk
+ data << uint32(0); // movement flags
+ data << uint16(0); // unk flags
data << uint32(getMSTime());
data << float(GetPositionX());
data << float(GetPositionY());
data << float(GetPositionZ());
data << float(GetOrientation());
- data << uint32(0); //flag unk
+ data << uint32(0); // fall time
data << float(GetSpeed(mtype));
SendMessageToSet( &data, true );
}
else
{
- // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
- // and do it only for real sent packets and use run for run/mounted as client expected
- ++((Player*)this)->m_forced_speed_changes[mtype];
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
+ // and do it only for real sent packets and use run for run/mounted as client expected
+ ++((Player*)this)->m_forced_speed_changes[mtype];
+
+ if(!isInCombat())
+ if(Pet* pet = ((Player*)this)->GetPet())
+ pet->SetSpeed(mtype, m_speed_rate[mtype], forced);
+ }
+
switch(mtype)
{
case MOVE_WALK:
@@ -10032,6 +10603,9 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
case MOVE_FLIGHT_BACK:
data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16);
break;
+ case MOVE_PITCH_RATE:
+ data.Initialize(SMSG_FORCE_PITCH_RATE_CHANGE, 16);
+ break;
default:
sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
return;
@@ -10043,9 +10617,6 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
data << float(GetSpeed(mtype));
SendMessageToSet( &data, true );
}
- if(GetPetGUID() && !isInCombat())
- if(Pet* pet = GetPet())
- pet->SetSpeed(mtype, m_speed_rate[mtype], forced);
}
void Unit::SetHover(bool on)
@@ -10067,13 +10638,15 @@ void Unit::setDeathState(DeathState s)
if(IsNonMeleeSpellCasted(false))
InterruptNonMeleeSpells(false);
+
+ UnsummonAllTotems();
+ RemoveAllControlled();
+ RemoveAllAurasOnDeath();
+ ExitVehicle();
}
if (s == JUST_DIED)
{
- RemoveAllAurasOnDeath();
- UnsummonAllTotems();
-
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false);
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false);
// remove aurastates allowing special moves
@@ -10116,6 +10689,10 @@ bool Unit::CanHaveThreatList() const
if( ((Creature*)this)->isTotem() )
return false;
+ // vehicles can not have threat list
+ //if( ((Creature*)this)->isVehicle() )
+ // return false;
+
// pets can not have a threat list, unless they are controlled by a creature
if( ((Creature*)this)->isPet() && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) )
return false;
@@ -10163,6 +10740,9 @@ void Unit::TauntApply(Unit* taunter)
if(!CanHaveThreatList())
return;
+ if(((Creature*)this)->HasReactState(REACT_PASSIVE))
+ return;
+
Unit *target = getVictim();
if(target && target == taunter)
return;
@@ -10186,6 +10766,9 @@ void Unit::TauntFadeOut(Unit *taunter)
if(!CanHaveThreatList())
return;
+ if(((Creature*)this)->HasReactState(REACT_PASSIVE))
+ return;
+
Unit *target = getVictim();
if(!target || target != taunter)
return;
@@ -10221,17 +10804,41 @@ Unit* Creature::SelectVictim()
//otherwise enterevademode every update
Unit* target = NULL;
-
- if(!m_ThreatManager.isThreatListEmpty())
+ // First checking if we have some taunt on us
+ const AuraEffectList& tauntAuras = GetAurasByType(SPELL_AURA_MOD_TAUNT);
+ if ( !tauntAuras.empty() )
{
- if(!HasAuraType(SPELL_AURA_MOD_TAUNT))
+ Unit* caster;
+
+ // The last taunt aura caster is alive an we are happy to attack him
+ if ( (caster = tauntAuras.back()->GetCaster()) && caster->isAlive() )
+ return getVictim();
+ else if (tauntAuras.size() > 1)
{
- target = m_ThreatManager.getHostilTarget();
+ // We do not have last taunt aura caster but we have more taunt auras,
+ // so find first available target
+
+ // Auras are pushed_back, last caster will be on the end
+ AuraEffectList::const_iterator aura = --tauntAuras.end();
+ do
+ {
+ --aura;
+ if ( (caster = (*aura)->GetCaster()) &&
+ caster->IsInMap(this) && canAttack(caster) && caster->isInAccessiblePlaceFor((Creature*)this) )
+ {
+ target = caster;
+ break;
+ }
+ }while (aura != tauntAuras.begin());
}
else
target = getVictim();
}
+ if ( !target && !m_ThreatManager.isThreatListEmpty() )
+ // No taunt aura or taunt aura caster is dead standart target selection
+ target = m_ThreatManager.getHostilTarget();
+
if(target)
{
if(!hasUnitState(UNIT_STAT_STUNNED))
@@ -10264,9 +10871,9 @@ Unit* Creature::SelectVictim()
if(m_invisibilityMask)
{
- Unit::AuraList const& iAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
- for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
- if((*itr)->IsPermanent())
+ Unit::AuraEffectList const& iAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
+ for(Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
+ if((*itr)->GetParentAura()->IsPermanent())
{
AI()->EnterEvadeMode();
break;
@@ -10303,8 +10910,11 @@ int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_inde
int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel);
float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index];
- // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
- int32 randvalue = spellProto->EffectBaseDice[effect_index] >= randomPoints ? spellProto->EffectBaseDice[effect_index]:irand(spellProto->EffectBaseDice[effect_index], randomPoints);
+ // range can have possitive and negative values, so order its for irand
+ int32 randvalue = int32(spellProto->EffectBaseDice[effect_index]) >= randomPoints
+ ? irand(randomPoints, int32(spellProto->EffectBaseDice[effect_index]))
+ : irand(int32(spellProto->EffectBaseDice[effect_index]), randomPoints);
+
int32 value = basePoints + randvalue;
//random damage
if(comboDamage != 0 && unitPlayer /*&& target && (target->GetGUID() == unitPlayer->GetComboTarget())*/)
@@ -10337,7 +10947,7 @@ int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_inde
return value;
}
-int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_index, Unit const* target)
+int32 Unit::CalcSpellDuration(SpellEntry const* spellProto)
{
Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
@@ -10353,14 +10963,24 @@ int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_in
else
duration = minduration;
- if (duration > 0)
+ return duration;
+}
+
+int32 Unit::ModSpellDuration(SpellEntry const* spellProto, Unit const* target, int32 duration, bool positive)
+{
+ //don't mod permament auras duration
+ if (duration<0)
+ return duration;
+
+ //cut duration only of negative effects
+ if (!positive)
{
- int32 mechanic = GetEffectMechanic(spellProto, effect_index);
+ int32 mechanic = spellProto->Mechanic;
+
// Find total mod value (negative bonus)
int32 durationMod_always = target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic);
// Find max mod (negative bonus)
int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic);
-
int32 durationMod = 0;
// Select strongest negative mod
if (durationMod_always > durationMod_not_stack)
@@ -10369,12 +10989,41 @@ int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_in
durationMod = durationMod_always;
if (durationMod != 0)
- duration = int32(int64(duration) * (100+durationMod) /100);
+ duration = int32( float (duration) * float(100.0f+durationMod) /100.0f);
- if (duration < 0) duration = 0;
+ // there are only negative mods currently
+ durationMod_always =target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL, spellProto->Dispel);
+ durationMod_not_stack=target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK, spellProto->Dispel);
+
+ durationMod=0;
+ if (durationMod_always > durationMod_not_stack)
+ durationMod += durationMod_not_stack;
+ else
+ durationMod += durationMod_always;
+
+ if (durationMod != 0)
+ duration = int32( float (duration) * float(100.0f+durationMod) /100.0f);
}
+ //else positive mods here, there are no currently
+ //when there will be, change GetTotalAuraModifierByMiscValue to GetTotalPositiveAuraModifierByMiscValue
+ return duration>0 ? duration : 0;
+}
- return duration;
+void Unit::ModSpellCastTime(SpellEntry const* spellProto, int32 & castTime, Spell const * spell)
+{
+ if (!spellProto || castTime<0)
+ return;
+ //called from caster
+ if(Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CASTING_TIME, castTime, spell);
+
+ if( !(spellProto->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) && spellProto->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spellProto->SpellFamilyName)
+ castTime = int32( float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED));
+ else
+ {
+ if (spellProto->Attributes & SPELL_ATTR_REQ_AMMO && !(spellProto->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG))
+ castTime = int32 (float(castTime) * m_modAttackSpeedPct[RANGED_ATTACK]);
+ }
}
DiminishingLevels Unit::GetDiminishing(DiminishingGroup group)
@@ -10408,21 +11057,15 @@ DiminishingLevels Unit::GetDiminishing(DiminishingGroup group)
void Unit::IncrDiminishing(DiminishingGroup group)
{
// Checking for existing in the table
- bool IsExist = false;
for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
{
if(i->DRGroup != group)
continue;
-
- IsExist = true;
if(i->hitCount < DIMINISHING_LEVEL_IMMUNE)
i->hitCount += 1;
-
- break;
+ return;
}
-
- if(!IsExist)
- m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2));
+ m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2));
}
void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level)
@@ -10471,17 +11114,50 @@ void Unit::ApplyDiminishingAura( DiminishingGroup group, bool apply )
if(i->DRGroup != group)
continue;
- i->hitTime = getMSTime();
-
if(apply)
i->stack += 1;
else if(i->stack)
+ {
i->stack -= 1;
-
+ // Remember time after last aura from group removed
+ if (i->stack == 0)
+ i->hitTime = getMSTime();
+ }
break;
}
}
+uint32 Unit::GetSpellMaxRangeForTarget(Unit* target,const SpellRangeEntry * rangeEntry)
+{
+ if (!rangeEntry)
+ return 0;
+ if (rangeEntry->maxRangeHostile == rangeEntry->maxRangeFriend)
+ return rangeEntry->maxRangeFriend;
+ if (IsHostileTo(target))
+ return rangeEntry->maxRangeHostile;
+ return rangeEntry->maxRangeFriend;
+};
+uint32 Unit::GetSpellMinRangeForTarget(Unit* target,const SpellRangeEntry * rangeEntry)
+{
+ if (!rangeEntry)
+ return 0;
+ if (rangeEntry->minRangeHostile == rangeEntry->minRangeFriend)
+ return rangeEntry->minRangeFriend;
+ if (IsHostileTo(target))
+ return rangeEntry->minRangeHostile;
+ return rangeEntry->minRangeFriend;
+};
+uint32 Unit::GetSpellRadiusForTarget(Unit* target,const SpellRadiusEntry * radiusEntry)
+{
+ if (!radiusEntry)
+ return 0;
+ if (radiusEntry->radiusHostile == radiusEntry->radiusFriend)
+ return radiusEntry->radiusFriend;
+ if (IsHostileTo(target))
+ return radiusEntry->radiusHostile;
+ return radiusEntry->radiusFriend;
+};
+
Unit* Unit::GetUnit(WorldObject& object, uint64 guid)
{
return ObjectAccessor::GetUnit(object,guid);
@@ -10494,19 +11170,19 @@ Player* Unit::GetPlayer(uint64 guid)
Creature* Unit::GetCreature(WorldObject& object, uint64 guid)
{
- return ObjectAccessor::GetCreature(object, guid);
+ return object.GetMap()->GetCreature(guid);
}
bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const
{
- return isVisibleForOrDetect(u, false, inVisibleList, false);
+ return u->canSeeOrDetect(this, false, inVisibleList, false);
}
uint32 Unit::GetCreatureType() const
{
if(GetTypeId() == TYPEID_PLAYER)
{
- SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(((Player*)this)->m_form);
+ SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(m_form);
if(ssEntry && ssEntry->creatureType > 0)
return ssEntry->creatureType;
else
@@ -10569,7 +11245,9 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f
case UNIT_MOD_RAGE:
case UNIT_MOD_FOCUS:
case UNIT_MOD_ENERGY:
- case UNIT_MOD_HAPPINESS: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break;
+ case UNIT_MOD_HAPPINESS:
+ case UNIT_MOD_RUNE:
+ case UNIT_MOD_RUNIC_POWER: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break;
case UNIT_MOD_RESISTANCE_HOLY:
case UNIT_MOD_RESISTANCE_FIRE:
@@ -10596,7 +11274,7 @@ float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) co
{
if( unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
{
- sLog.outError("ERROR: trial to access non existed modifier value from UnitMods!");
+ sLog.outError("trial to access non existed modifier value from UnitMods!");
return 0.0f;
}
@@ -10626,7 +11304,7 @@ float Unit::GetTotalAuraModValue(UnitMods unitMod) const
{
if(unitMod >= UNIT_MOD_END)
{
- sLog.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
+ sLog.outError("trial to access non existed UnitMods in GetTotalAuraModValue()!");
return 0.0f;
}
@@ -10682,32 +11360,37 @@ Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const
Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const
{
- Powers power = POWER_MANA;
-
switch(unitMod)
{
- case UNIT_MOD_MANA: power = POWER_MANA; break;
- case UNIT_MOD_RAGE: power = POWER_RAGE; break;
- case UNIT_MOD_FOCUS: power = POWER_FOCUS; break;
- case UNIT_MOD_ENERGY: power = POWER_ENERGY; break;
- case UNIT_MOD_HAPPINESS: power = POWER_HAPPINESS; break;
-
- default:
- break;
+ case UNIT_MOD_MANA: return POWER_MANA;
+ case UNIT_MOD_RAGE: return POWER_RAGE;
+ case UNIT_MOD_FOCUS: return POWER_FOCUS;
+ case UNIT_MOD_ENERGY: return POWER_ENERGY;
+ case UNIT_MOD_HAPPINESS: return POWER_HAPPINESS;
+ case UNIT_MOD_RUNE: return POWER_RUNE;
+ case UNIT_MOD_RUNIC_POWER:return POWER_RUNIC_POWER;
+ default: return POWER_MANA;
}
- return power;
+ return POWER_MANA;
}
float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const
{
- UnitMods unitMod = (attType == RANGED_ATTACK) ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
-
- float val = GetTotalAuraModValue(unitMod);
- if(val < 0.0f)
- val = 0.0f;
-
- return val;
+ if (attType == RANGED_ATTACK)
+ {
+ int32 ap = GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS);
+ if (ap < 0)
+ return 0.0f;
+ return ap * (1.0f + GetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER));
+ }
+ else
+ {
+ int32 ap = GetInt32Value(UNIT_FIELD_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS);
+ if (ap < 0)
+ return 0.0f;
+ return ap * (1.0f + GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER));
+ }
}
float Unit::GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const
@@ -10795,6 +11478,12 @@ void Unit::SetPower(Powers power, uint32 val)
SetStatInt32Value(UNIT_FIELD_POWER1 + power, val);
+ WorldPacket data(SMSG_POWER_UPDATE);
+ data.append(GetPackGUID());
+ data << uint8(power);
+ data << uint32(val);
+ SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER ? true : false);
+
// group update
if(GetTypeId() == TYPEID_PLAYER)
{
@@ -10889,15 +11578,6 @@ void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply)
}
}
-void Unit::ApplyAuraProcTriggerDamage( Aura* aura, bool apply )
-{
- AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE];
- if(apply)
- tAuraProcTriggerDamage.push_back(aura);
- else
- tAuraProcTriggerDamage.remove(aura);
-}
-
uint32 Unit::GetCreatePowers( Powers power ) const
{
// POWER_FOCUS and POWER_HAPPINESS only have hunter pet
@@ -10908,6 +11588,9 @@ uint32 Unit::GetCreatePowers( Powers power ) const
case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100);
case POWER_ENERGY: return 100;
case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000);
+ case POWER_RUNIC_POWER: return 1000;
+ case POWER_RUNE: return 0;
+ case POWER_HEALTH: return 0;
}
return 0;
@@ -10927,18 +11610,27 @@ void Unit::AddToWorld()
void Unit::RemoveFromWorld()
{
// cleanup
+ assert(GetGUID());
+
if(IsInWorld())
{
+ UnsummonAllTotems();
+ RemoveAllControlled();
RemoveCharmAuras();
RemoveBindSightAuras();
RemoveNotOwnSingleTargetAuras();
+ ExitVehicle();
+
+ if(GetCharmerGUID())
+ sLog.outCrash("Unit %u has charmer guid when removed from world", GetEntry());
+
WorldObject::RemoveFromWorld();
}
}
void Unit::CleanupsBeforeDelete()
{
- assert(m_uint32Values);
+ assert(GetGUID());
//A unit may be in removelist and not in world, but it is still in grid
//and may have some references during delete
@@ -11053,7 +11745,7 @@ void CharmInfo::InitEmptyActionBar(bool withAttack)
for(uint32 x = 0; x < 10; ++x)
{
- PetActionBar[x].Type = ACT_CAST;
+ PetActionBar[x].Type = ACT_PASSIVE;
PetActionBar[x].SpellOrAction = 0;
}
if (withAttack)
@@ -11071,11 +11763,14 @@ void CharmInfo::InitPossessCreateSpells()
{
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
{
- uint32 spellid = ((Creature*)m_unit)->m_spells[i];
- if(IsPassiveSpell(spellid))
- m_unit->CastSpell(m_unit, spellid, true);
+ uint32 spellId = ((Creature*)m_unit)->m_spells[i];
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
+ if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
+ spellId = 0;
+ if(IsPassiveSpell(spellId))
+ m_unit->CastSpell(m_unit, spellId, true);
else
- AddSpellToAB(0, spellid, ACT_CAST);
+ AddSpellToAB(0, spellId, ACT_DISABLED);
}
}
}
@@ -11090,9 +11785,13 @@ void CharmInfo::InitCharmCreateSpells()
InitPetActionBar();
- for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
+ for(uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
{
uint32 spellId = ((Creature*)m_unit)->m_spells[x];
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
+ if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
+ spellId = 0;
+
m_charmspells[x].spellId = spellId;
if(!spellId)
@@ -11106,21 +11805,26 @@ void CharmInfo::InitCharmCreateSpells()
else
{
ActiveStates newstate;
- bool onlyselfcast = true;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
-
- if(!spellInfo) onlyselfcast = false;
- for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
+ if(spellInfo)
{
- if(spellInfo->EffectImplicitTargetA[i] != TARGET_UNIT_CASTER && spellInfo->EffectImplicitTargetA[i] != 0)
- onlyselfcast = false;
- }
-
- if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable
- newstate = ACT_DISABLED;
- else
- newstate = ACT_CAST;
+ if(!IsAutocastableSpell(spellId))
+ newstate = ACT_PASSIVE;
+ else
+ {
+ bool autocast = false;
+ for(uint32 i = 0; i < 3 && !autocast; ++i)
+ if(spellmgr.SpellTargetType[spellInfo->EffectImplicitTargetA[i]] == TARGET_TYPE_UNIT_TARGET)
+ autocast = true;
+ if(autocast)
+ {
+ newstate = ACT_ENABLED;
+ ToggleCreatureAutocast(spellId, true);
+ }
+ else
+ newstate = ACT_DISABLED;
+ }
+ }
AddSpellToAB(0, spellId, newstate);
}
}
@@ -11128,20 +11832,32 @@ void CharmInfo::InitCharmCreateSpells()
bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate)
{
- for(uint8 i = 0; i < 10; i++)
+ // new spell already listed for example in case prepered switch to lesser rank in Pet::removeSpell
+ for(uint8 i = 0; i < 10; ++i)
+ if (PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE)
+ if (newid && PetActionBar[i].SpellOrAction == newid)
+ return true;
+
+ // old spell can be leasted for example in case learn high rank
+ for(uint8 i = 0; i < 10; ++i)
{
- if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_CAST) && PetActionBar[i].SpellOrAction == oldid)
+ if (PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE)
{
- PetActionBar[i].SpellOrAction = newid;
- if(!oldid)
+ if (PetActionBar[i].SpellOrAction == oldid)
{
- if(newstate == ACT_DECIDE)
- PetActionBar[i].Type = ACT_DISABLED;
- else
- PetActionBar[i].Type = newstate;
- }
+ PetActionBar[i].SpellOrAction = newid;
+ if (!oldid)
+ {
+ if(!IsAutocastableSpell(newid))
+ PetActionBar[i].Type = ACT_PASSIVE;
+ else if (newstate == ACT_DECIDE)
+ PetActionBar[i].Type = ACT_DISABLED;
+ else
+ PetActionBar[i].Type = newstate;
+ }
- return true;
+ return true;
+ }
}
}
return false;
@@ -11152,7 +11868,7 @@ void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply)
if(IsPassiveSpell(spellid))
return;
- for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
+ for(uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
{
if(spellid == m_charmspells[x].spellId)
{
@@ -11172,209 +11888,29 @@ void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
bool Unit::isFrozen() const
{
- AuraList const& mRoot = GetAurasByType(SPELL_AURA_MOD_ROOT);
- for(AuraList::const_iterator i = mRoot.begin(); i != mRoot.end(); ++i)
- if( GetSpellSchoolMask((*i)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
- return true;
- return false;
+ return HasAuraState(AURA_STATE_FROZEN);
}
-/*
struct ProcTriggeredData
{
- ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown)
- : triggeredByAura(_triggeredByAura),
- triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex())),
- cooldown(_cooldown)
- {}
-
- Aura* triggeredByAura; // triggred aura, can be invalidate at triggered aura proccessing
- Unit::spellEffectPair triggeredByAura_SpellPair; // spell pair, used for re-find aura (by pointer comparison in range)
- uint32 cooldown; // possible hidden cooldown
-};
-
-typedef std::list< ProcTriggeredData > ProcTriggeredList;
-
-void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask )
-{
- for(AuraTypeSet::const_iterator aur = procAuraTypes.begin(); aur != procAuraTypes.end(); ++aur)
+ ProcTriggeredData(Aura* _aura)
+ : aura(_aura)
{
- // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
- ProcTriggeredList procTriggered;
-
- AuraList const& auras = GetAurasByType(*aur);
- for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next)
- {
- next = i; ++next;
-
- Aura* i_aura = *i;
-
- uint32 cooldown; // returned at next line
- if(!IsTriggeredAtSpellProcEvent(i_aura->GetSpellProto(), procSpell, procFlag,attType,isVictim,cooldown))
- continue;
-
- procTriggered.push_back( ProcTriggeredData(i_aura, cooldown) );
- }
-
- // Handle effects proceed this time
- for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
- {
- // Some auras can be deleted in function called in this loop (except first, ofc)
- // Until storing auras in std::multimap to hard check deleting by another way
- if(i != procTriggered.begin())
- {
- bool found = false;
- AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
- AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
- for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
- {
- if(itr->second==i->triggeredByAura)
- {
- found = true;
- break;
- }
- }
-
- if(!found)
- {
- sLog.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur,i->triggeredByAura_SpellPair.first,i->triggeredByAura_SpellPair.second);
- sLog.outError("It can be deleted one from early processed auras:");
- for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2)
- sLog.outError(" Spell aura %u (id:%u effect:%u)",*aur,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second);
- sLog.outError(" <end of list>");
- continue;
- }
- }
-
- /// this is aura triggering code call
- Aura* triggeredByAura = i->triggeredByAura;
-
- /// save charges existence before processing to prevent crash at access to deleted triggered aura after
- /// used in speedup code check before check aura existance.
- bool triggeredByAuraWithCharges = triggeredByAura->m_procCharges > 0;
-
- /// success in event proccesing
- /// used in speedup code check before check aura existance.
- bool casted = false;
-
- /// process triggered code
- switch(*aur)
- {
- case SPELL_AURA_PROC_TRIGGER_SPELL:
- {
- sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
- (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
- casted = HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, attType, i->cooldown);
- break;
- }
- case SPELL_AURA_PROC_TRIGGER_DAMAGE:
- {
- uint32 triggered_damage = triggeredByAura->GetModifier()->m_amount;
- sLog.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
- triggered_damage, (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
- SpellNonMeleeDamageLog(pTarget, triggeredByAura->GetId(), triggered_damage, true, true);
- casted = true;
- break;
- }
- case SPELL_AURA_DUMMY:
- {
- uint32 effect = triggeredByAura->GetEffIndex();
- sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
- (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
- casted = HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown);
- break;
- }
- case SPELL_AURA_PRAYER_OF_MENDING:
- {
- sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
- (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
-
- casted = HandleMeandingAuraProc(triggeredByAura);
- break;
- }
- case SPELL_AURA_MOD_HASTE:
- {
- sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
- (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
- casted = HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown);
- break;
- }
- case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
- {
- // nothing do, just charges counter
- // but count only in case appropriate school damage
- casted = triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask;
- break;
- }
- case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
- {
- sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)",
- (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
- casted = HandleOverrideClassScriptAuraProc(pTarget, triggeredByAura, procSpell,i->cooldown);
- break;
- }
- default:
- {
- // nothing do, just charges counter
- casted = true;
- break;
- }
- }
-
- /// Update charge (aura can be removed by triggers)
- if(casted && triggeredByAuraWithCharges)
- {
- /// need re-found aura (can be dropped by triggers)
- AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
- AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
- for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
- {
- if(itr->second == triggeredByAura) // pointer still valid
- {
- if(triggeredByAura->m_procCharges > 0)
- triggeredByAura->m_procCharges -= 1;
-
- triggeredByAura->UpdateAuraCharges();
- break;
- }
- }
- }
- }
-
- /// Safely remove auras with zero charges
- for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next)
- {
- next = i; ++next;
- if((*i)->m_procCharges == 0)
- {
- RemoveAurasDueToSpell((*i)->GetId());
- next = auras.begin();
- }
- }
+ effMask = 0;
+ spellProcEvent = NULL;
}
-}
-*/
-struct ProcTriggeredData
-{
- ProcTriggeredData(SpellProcEventEntry const * _spellProcEvent, Aura* _triggeredByAura)
- : spellProcEvent(_spellProcEvent), triggeredByAura(_triggeredByAura),
- triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex()))
- {}
SpellProcEventEntry const *spellProcEvent;
- Aura* triggeredByAura;
- Unit::spellEffectPair triggeredByAura_SpellPair;
+ Aura * aura;
+ uint32 effMask;
};
typedef std::list< ProcTriggeredData > ProcTriggeredList;
-typedef std::list< uint32> RemoveSpellList;
// List of auras that CAN be trigger but may not exist in spell_proc_event
// in most case need for drop charges
// in some types of aura need do additional check
// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic
-static bool isTriggerAura[TOTAL_AURAS];
-static bool isNonTriggerAura[TOTAL_AURAS];
-void InitTriggerAuraData()
+bool InitTriggerAuraData()
{
for (int i=0;i<TOTAL_AURAS;i++)
{
@@ -11388,12 +11924,13 @@ void InitTriggerAuraData()
isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
+ isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; // Aura not have charges but need remove him on trigger
isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
- isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED] = true;
+ isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
@@ -11407,10 +11944,17 @@ void InitTriggerAuraData()
isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true;
isTriggerAura[SPELL_AURA_MOD_HASTE] = true;
isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE]=true;
- isTriggerAura[SPELL_AURA_PRAYER_OF_MENDING] = true;
+ isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true;
+ isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true;
+ isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
+ isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN]=true;
- isNonTriggerAura[SPELL_AURA_RESIST_PUSHBACK]=true;
+ isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK]=true;
+
+ return true;
}
uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
@@ -11451,17 +11995,8 @@ uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missC
return procEx;
}
-void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage )
+void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage , SpellEntry const * procAura)
{
- ++m_procDeep;
- if (m_procDeep > 5)
- {
- sLog.outError("Prevent possible stack owerflow in Unit::ProcDamageAndSpellFor");
- if (procSpell)
- sLog.outError(" Spell %u", procSpell->Id);
- --m_procDeep;
- return;
- }
// For melee/ranged based attack need update skills and set some Aura states
if (procFlag & MELEE_BASED_TRIGGER_MASK)
{
@@ -11472,7 +12007,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
if (procExtra&(PROC_EX_NORMAL_HIT|PROC_EX_MISS|PROC_EX_RESIST))
{
if (pTarget->GetTypeId() != TYPEID_PLAYER && pTarget->GetCreatureType() != CREATURE_TYPE_CRITTER)
- ((Player*)this)->UpdateCombatSkills(pTarget, attType, MELEE_HIT_MISS, isVictim);
+ ((Player*)this)->UpdateCombatSkills(pTarget, attType, isVictim);
}
// Update defence if player is victim and parry/dodge/block
if (isVictim && procExtra&(PROC_EX_DODGE|PROC_EX_PARRY|PROC_EX_BLOCK))
@@ -11524,199 +12059,212 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
((Player*)this)->AddComboPoints(pTarget, 1);
StartReactiveTimer( REACTIVE_OVERPOWER );
}
- // Enable AURA_STATE_CRIT on crit
- if (procExtra & PROC_EX_CRITICAL_HIT)
- {
- ModifyAuraState(AURA_STATE_CRIT, true);
- StartReactiveTimer( REACTIVE_CRIT );
- if(getClass()==CLASS_HUNTER)
- {
- ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true);
- StartReactiveTimer( REACTIVE_HUNTER_CRIT );
- }
- }
}
}
}
- RemoveSpellList removedSpells;
ProcTriggeredList procTriggered;
// Fill procTriggered list
for(AuraMap::const_iterator itr = GetAuras().begin(); itr!= GetAuras().end(); ++itr)
{
- SpellProcEventEntry const* spellProcEvent = NULL;
- if(!IsTriggeredAtSpellProcEvent(itr->second, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), spellProcEvent))
- continue;
-
- procTriggered.push_back( ProcTriggeredData(spellProcEvent, itr->second) );
- }
- // Handle effects proceed this time
- for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
- {
- // Some auras can be deleted in function called in this loop (except first, ofc)
- // Until storing auars in std::multimap to hard check deleting by another way
- if(i != procTriggered.begin())
+ // Do not allow auras to proc from effect of itself
+ if (procAura && procAura->Id == itr->first)
+ continue;
+ ProcTriggeredData triggerData(itr->second);
+ if(!IsTriggeredAtSpellProcEvent(pTarget, triggerData.aura, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), triggerData.spellProcEvent))
+ continue;
+ for (uint8 i=0; i<MAX_SPELL_EFFECTS;++i)
{
- bool found = false;
- AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
- AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
- for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
+ if (AuraEffect * aurEff = itr->second->GetPartAura(i))
{
- if(itr->second==i->triggeredByAura)
- {
- found = true;
- break;
- }
- }
- if(!found)
- {
-// sLog.outDebug("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler", i->triggeredByAura->GetModifier()->m_auraname, i->triggeredByAura_SpellPair.first, i->triggeredByAura_SpellPair.second);
-// sLog.outDebug("It can be deleted one from early proccesed auras:");
-// for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2)
-// sLog.outDebug(" Spell aura %u (id:%u effect:%u)", i->triggeredByAura->GetModifier()->m_auraname,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second);
-// sLog.outDebug(" <end of list>");
- continue;
+ // Skip this auras
+ if (isNonTriggerAura[aurEff->GetAuraName()])
+ continue;
+ // If not trigger by default and spellProcEvent==NULL - skip
+ if (!isTriggerAura[aurEff->GetAuraName()] && triggerData.spellProcEvent==NULL)
+ continue;
+ triggerData.effMask |= 1<<i;
}
}
+ if (triggerData.effMask)
+ procTriggered.push_front(triggerData);
+ }
+
+ // Nothing found
+ if (procTriggered.empty())
+ return;
+
+ if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC))
+ SetCantProc(true);
+
+ // Handle effects proceed this time
+ for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
+ {
+ // look for aura in auras list, it may be removed while proc event processing
+ if (!HasAura(i->aura))
+ continue;
+
+ bool useCharges= i->aura->GetAuraCharges()>0;
+ bool takeCharges = false;
+ SpellEntry const *spellInfo = i->aura->GetSpellProto();
+ uint32 Id = i->aura->GetId();
- SpellProcEventEntry const *spellProcEvent = i->spellProcEvent;
- Aura *triggeredByAura = i->triggeredByAura;
- Modifier *auraModifier = triggeredByAura->GetModifier();
- SpellEntry const *spellInfo = triggeredByAura->GetSpellProto();
- uint32 effIndex = triggeredByAura->GetEffIndex();
- bool useCharges = triggeredByAura->m_procCharges > 0;
// For players set spell cooldown if need
uint32 cooldown = 0;
- if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown)
- cooldown = spellProcEvent->cooldown;
+ if (GetTypeId() == TYPEID_PLAYER && i->spellProcEvent && i->spellProcEvent->cooldown)
+ cooldown = i->spellProcEvent->cooldown;
+
+ uint32 procDebug = 0;
- switch(auraModifier->m_auraname)
+ for (uint8 effIndex = 0; effIndex<MAX_SPELL_EFFECTS;++effIndex)
{
- case SPELL_AURA_PROC_TRIGGER_SPELL:
- {
- sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- break;
- }
- case SPELL_AURA_PROC_TRIGGER_DAMAGE:
- {
- sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", auraModifier->m_amount, spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask);
- uint32 damage = SpellDamageBonus(pTarget, spellInfo, auraModifier->m_amount, SPELL_DIRECT_DAMAGE);
- CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
- SendSpellNonMeleeDamageLog(&damageInfo);
- DealSpellDamage(&damageInfo, true);
- break;
- }
- case SPELL_AURA_MANA_SHIELD:
- case SPELL_AURA_DUMMY:
- {
- sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- break;
- }
- case SPELL_AURA_MOD_HASTE:
- {
- sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- break;
- }
- case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
- {
- sLog.outDebug("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(pTarget, triggeredByAura, procSpell, cooldown))
- continue;
- break;
- }
- case SPELL_AURA_PRAYER_OF_MENDING:
+ if (!(i->effMask & (1<<effIndex)))
+ continue;
+
+ AuraEffect *triggeredByAura = i->aura->GetPartAura(effIndex);
+ assert(triggeredByAura);
+
+ switch(triggeredByAura->GetAuraName())
{
- sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
- (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
+ case SPELL_AURA_PROC_TRIGGER_SPELL:
+ {
+ sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_PROC_TRIGGER_DAMAGE:
+ {
+ sLog.outDebug("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, pTarget, spellInfo->Id, spellInfo->SchoolMask);
+ uint32 damage = SpellDamageBonus(pTarget, spellInfo, triggeredByAura->GetAmount(), SPELL_DIRECT_DAMAGE);
+ CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
+ DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
+ SendSpellNonMeleeDamageLog(&damageInfo);
+ DealSpellDamage(&damageInfo, true);
+ break;
+ }
+ case SPELL_AURA_MANA_SHIELD:
+ case SPELL_AURA_DUMMY:
+ {
+ sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ if (procDebug & 1)
+ sLog.outError("Dummy aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 1;
+ break;
+ }
+ case SPELL_AURA_OBS_MOD_ENERGY:
+ sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ if (procDebug & 2)
+ sLog.outError("ObsModEnergy aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 2;
+ break;
+ case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
+ sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ if (procDebug & 16)
+ sLog.outError("ModDamagePctTaken aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 16;
+ break;
+ case SPELL_AURA_MOD_HASTE:
+ {
+ sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ if (procDebug & 4)
+ sLog.outError("Haste aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 4;
+ break;
+ }
+ case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
+ {
+ sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, cooldown))
+ continue;
+ if (procDebug & 8)
+ sLog.outError("OverrideClassScripts aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 8;
+ break;
+ }
+ case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
+ (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
- HandleMeandingAuraProc(triggeredByAura);
- break;
- }
- case SPELL_AURA_MOD_STUN:
- // Remove by default, but if charge exist drop it
- if (triggeredByAura->m_procCharges == 0)
- removedSpells.push_back(triggeredByAura->GetId());
- break;
- case SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS:
- case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS:
- // Hunter's Mark (1-4 Rangs)
- if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (spellInfo->SpellFamilyFlags&0x0000000000000400LL))
+ HandleAuraRaidProcFromChargeWithValue(triggeredByAura);
+ break;
+ }
+ case SPELL_AURA_RAID_PROC_FROM_CHARGE:
{
- uint32 basevalue = triggeredByAura->GetBasePoints();
- auraModifier->m_amount += basevalue/10;
- if (auraModifier->m_amount > basevalue*4)
- auraModifier->m_amount = basevalue*4;
+ sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
+ (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
+
+ HandleAuraRaidProcFromCharge(triggeredByAura);
+ break;
}
- break;
- case SPELL_AURA_MOD_CASTING_SPEED:
- // Skip melee hits or instant cast spells
- if (procSpell == NULL || GetSpellCastTime(procSpell) == 0)
- continue;
- break;
- case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
- // Skip Melee hits and spells ws wrong school
- if (procSpell == NULL || (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0)
- continue;
- 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 == NULL ||
- (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check
- (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0) // School check
- continue;
- break;
- case SPELL_AURA_MECHANIC_IMMUNITY:
- // Compare mechanic
- if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue)
- continue;
- break;
- case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
- // Compare mechanic
- if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue)
- continue;
- break;
- default:
- // nothing do, just charges counter
- break;
- }
- // Remove charge (aura can be removed by triggers)
- if(useCharges)
- {
- // need found aura on drop (can be dropped by triggers)
- AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
- AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
- for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
- {
- if(itr->second == i->triggeredByAura)
+ case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
{
- triggeredByAura->m_procCharges -=1;
- triggeredByAura->UpdateAuraCharges();
- if (triggeredByAura->m_procCharges <= 0)
- removedSpells.push_back(triggeredByAura->GetId());
+ sLog.outDebug("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(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
break;
}
+ case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
+ // Skip melee hits or instant cast spells
+ if (procSpell == NULL || GetSpellCastTime(procSpell) == 0)
+ continue;
+ break;
+ case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
+ // Skip Melee hits and spells ws wrong school
+ if (procSpell == NULL || (triggeredByAura->GetMiscValue() & procSpell->SchoolMask) == 0)
+ continue;
+ 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 == NULL ||
+ (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check
+ (triggeredByAura->GetMiscValue() & procSpell->SchoolMask) == 0) // School check
+ continue;
+ break;
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ // Compare mechanic
+ if (procSpell==NULL || procSpell->Mechanic != triggeredByAura->GetMiscValue())
+ continue;
+ break;
+ case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
+ // Compare mechanic
+ if (procSpell==NULL || procSpell->Mechanic != triggeredByAura->GetMiscValue())
+ continue;
+ break;
+ case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
+ // Compare casters
+ if (triggeredByAura->GetCasterGUID() != pTarget->GetGUID())
+ continue;
+ break;
+ default:
+ // nothing do, just charges counter
+ break;
}
+ takeCharges=true;
+ }
+ // Remove charge (aura can be removed by triggers)
+ if(useCharges && takeCharges)
+ {
+ i->aura->DropAuraCharge();
}
}
- if (removedSpells.size())
- {
- // Sort spells and remove dublicates
- removedSpells.sort();
- removedSpells.unique();
- // Remove auras from removedAuras
- for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();i++)
- RemoveAurasDueToSpell(*i);
- }
- --m_procDeep;
+
+ // Cleanup proc requirements
+ if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC))
+ SetCantProc(false);
}
SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
@@ -11738,15 +12286,21 @@ Player* Unit::GetSpellModOwner() const
}
///----------Pet responses methods-----------------
-void Unit::SendPetCastFail(uint32 spellid, uint8 msg)
+void Unit::SendPetCastFail(uint32 spellid, SpellCastResult msg)
{
+ if(msg == SPELL_CAST_OK)
+ return;
+
Unit *owner = GetCharmerOrOwner();
if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
return;
WorldPacket data(SMSG_PET_CAST_FAILED, (4+1));
+ data << uint8(0); // cast count?
data << uint32(spellid);
data << uint8(msg);
+ // uint32 for some reason
+ // uint32 for some reason
((Player*)owner)->GetSession()->SendPacket(&data);
}
@@ -11832,8 +12386,15 @@ void Unit::StopMoving()
SendMessageToSet(&data,false);
}
+void Unit::SendMovementFlagUpdate()
+{
+ WorldPacket data;
+ BuildHeartBeatMsg(&data);
+ SendMessageToSet(&data, false);
+}
+
/*
-void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID)
+void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID, uint32 time)
{
if( apply )
{
@@ -11847,7 +12408,7 @@ void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID)
Unit* caster = ObjectAccessor::GetUnit(*this,casterGUID);
- GetMotionMaster()->MoveFleeing(caster); // caster==NULL processed in MoveFleeing
+ GetMotionMaster()->MoveFleeing(caster, time); // caster==NULL processed in MoveFleeing
}
else
{
@@ -11865,8 +12426,8 @@ void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID)
// attack caster if can
Unit* caster = ObjectAccessor::GetObjectInWorld(casterGUID, (Unit*)NULL);
- if(caster && caster != getVictim() && ((Creature*)this)->IsAIEnabled)
- ((Creature*)this)->AI()->AttackStart(caster);
+ if(caster && ((Creature*)this)->AI())
+ ((Creature*)this)->AI()->AttackedBy(caster);
}
}
@@ -11906,15 +12467,16 @@ void Unit::SetConfused(bool apply, uint64 casterGUID, uint32 spellID)
bool Unit::IsSitState() const
{
uint8 s = getStandState();
- return s == PLAYER_STATE_SIT_CHAIR || s == PLAYER_STATE_SIT_LOW_CHAIR ||
- s == PLAYER_STATE_SIT_MEDIUM_CHAIR || s == PLAYER_STATE_SIT_HIGH_CHAIR ||
- s == PLAYER_STATE_SIT;
+ return
+ s == UNIT_STAND_STATE_SIT_CHAIR || s == UNIT_STAND_STATE_SIT_LOW_CHAIR ||
+ s == UNIT_STAND_STATE_SIT_MEDIUM_CHAIR || s == UNIT_STAND_STATE_SIT_HIGH_CHAIR ||
+ s == UNIT_STAND_STATE_SIT;
}
bool Unit::IsStandState() const
{
uint8 s = getStandState();
- return !IsSitState() && s != PLAYER_STATE_SLEEP && s != PLAYER_STATE_KNEEL;
+ return !IsSitState() && s != UNIT_STAND_STATE_SLEEP && s != UNIT_STAND_STATE_KNEEL;
}
void Unit::SetStandState(uint8 state)
@@ -11968,7 +12530,6 @@ void Unit::ClearComboPointHolders()
void Unit::ClearAllReactives()
{
-
for(int i=0; i < MAX_REACTIVE; ++i)
m_reactiveTimer[i] = 0;
@@ -11976,11 +12537,6 @@ void Unit::ClearAllReactives()
ModifyAuraState(AURA_STATE_DEFENSE, false);
if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_PARRY))
ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
- if (HasAuraState( AURA_STATE_CRIT))
- ModifyAuraState(AURA_STATE_CRIT, false);
- if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE) )
- ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false);
-
if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER)
((Player*)this)->ClearComboPoints();
}
@@ -12008,14 +12564,6 @@ void Unit::UpdateReactives( uint32 p_time )
if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY))
ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
break;
- case REACTIVE_CRIT:
- if (HasAuraState(AURA_STATE_CRIT))
- ModifyAuraState(AURA_STATE_CRIT, false);
- break;
- case REACTIVE_HUNTER_CRIT:
- if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE) )
- ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false);
- break;
case REACTIVE_OVERPOWER:
if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER)
((Player*)this)->ClearComboPoints();
@@ -12035,7 +12583,7 @@ Unit* Unit::SelectNearbyTarget(float dist) const
{
std::list<Unit *> targets;
Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
- Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(targets, u_check);
+ Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(this, targets, u_check);
VisitNearbyObject(dist, searcher);
// remove current target
@@ -12068,6 +12616,16 @@ Unit* Unit::SelectNearbyTarget(float dist) const
return *tcIter;
}
+bool Unit::hasNegativeAuraWithInterruptFlag(uint32 flag)
+{
+ for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ++iter)
+ {
+ if (!iter->second->IsPositive() && iter->second->GetSpellProto()->AuraInterruptFlags & flag)
+ return true;
+ }
+ return false;
+}
+
void Unit::ApplyAttackTimePercentMod( WeaponAttackType att,float val, bool apply )
{
float remainingTimePct = (float)m_attackTimer[att] / (GetAttackTime(att) * m_modAttackSpeedPct[att]);
@@ -12151,7 +12709,7 @@ uint32 Unit::GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectT
if (OriginalCastTime > 7000) OriginalCastTime = 7000;
if (OriginalCastTime < 1500) OriginalCastTime = 1500;
// Portion to Over Time
- float PtOT = (overTime / 15000.f) / ((overTime / 15000.f) + (OriginalCastTime / 3500.f));
+ float PtOT = (overTime / 15000.0f) / ((overTime / 15000.0f) + (OriginalCastTime / 3500.0f));
if ( damagetype == DOT )
CastingTime = uint32(CastingTime * PtOT);
@@ -12184,13 +12742,15 @@ uint32 Unit::GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectT
void Unit::UpdateAuraForGroup(uint8 slot)
{
+ if(slot >= MAX_AURAS) // slot not found, return
+ return;
if(GetTypeId() == TYPEID_PLAYER)
{
Player* player = (Player*)this;
if(player->GetGroup())
{
player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
- player->SetAuraUpdateMask(slot);
+ player->SetAuraUpdateMaskForRaid(slot);
}
}
else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
@@ -12202,7 +12762,7 @@ void Unit::UpdateAuraForGroup(uint8 slot)
if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
{
((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS);
- pet->SetAuraUpdateMask(slot);
+ pet->SetAuraUpdateMaskForRaid(slot);
}
}
}
@@ -12233,10 +12793,10 @@ float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized)
}
}
-Aura* Unit::GetDummyAura( uint32 spell_id ) const
+AuraEffect* Unit::GetDummyAura( uint32 spell_id ) const
{
- Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
+ Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
if ((*itr)->GetId() == spell_id)
return *itr;
@@ -12273,21 +12833,30 @@ void Unit::SetContestedPvP(Player *attackedPlayer)
void Unit::AddPetAura(PetAura const* petSpell)
{
+ if(GetTypeId() != TYPEID_PLAYER)
+ return;
+
m_petAuras.insert(petSpell);
- if(Pet* pet = GetPet())
+ if(Pet* pet = ((Player*)this)->GetPet())
pet->CastPetAura(petSpell);
}
void Unit::RemovePetAura(PetAura const* petSpell)
{
+ if(GetTypeId() != TYPEID_PLAYER)
+ return;
+
m_petAuras.erase(petSpell);
- if(Pet* pet = GetPet())
+ if(Pet* pet = ((Player*)this)->GetPet())
pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry()));
}
Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id)
{
- Pet* pet = new Pet(HUNTER_PET);
+ if(GetTypeId()!=TYPEID_PLAYER)
+ return NULL;
+
+ Pet* pet = new Pet((Player*)this, HUNTER_PET);
if(!pet->CreateBaseAtCreature(creatureTarget))
{
@@ -12295,43 +12864,39 @@ Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id)
return NULL;
}
- pet->SetOwnerGUID(GetGUID());
pet->SetCreatorGUID(GetGUID());
pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction());
pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, spell_id);
- if(!pet->InitStatsForLevel(creatureTarget->getLevel()))
+ if(GetTypeId()==TYPEID_PLAYER)
+ pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+
+ uint32 level = (creatureTarget->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget->getLevel();
+
+ if(!pet->InitStatsForLevel(level))
{
- sLog.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget->GetEntry());
+ sLog.outError("Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget->GetEntry());
delete pet;
return NULL;
}
pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
// this enables pet details window (Shift+P)
- pet->AIM_Initialize();
pet->InitPetCreateSpells();
+ //pet->InitLevelupSpellsForLevel();
+ pet->InitTalentForLevel();
pet->SetHealth(pet->GetMaxHealth());
return pet;
}
-bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent )
+bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const *& spellProcEvent )
{
SpellEntry const* spellProto = aura->GetSpellProto ();
// Get proc Event Entry
spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
- // Aura info stored here
- Modifier *mod = aura->GetModifier();
- // Skip this auras
- if (isNonTriggerAura[mod->m_auraname])
- return false;
- // If not trigger by default and spellProcEvent==NULL - skip
- if (!isTriggerAura[mod->m_auraname] && spellProcEvent==NULL)
- return false;
-
// Get EventProcFlag
uint32 EventProcFlag;
if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags
@@ -12342,11 +12907,27 @@ bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell,
if (!EventProcFlag)
return false;
+ // Additional checks for triggered spells
+ if (procExtra & PROC_EX_INTERNAL_TRIGGERED)
+ {
+ if (!(spellProto->AttributesEx3 & SPELL_ATTR_EX3_CAN_PROC_TRIGGERED))
+ return false;
+ }
+
// Check spellProcEvent data requirements
- if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
+ if(!spellmgr.IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
return false;
-
- // Aura added by spell can`t trogger from self (prevent drop cahres/do triggers)
+ // In most cases req get honor or XP from kill
+ if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER)
+ {
+ bool allow = ((Player*)this)->isHonorOrXPTarget(pVictim);
+ // Shadow Word: Death - can trigger from every kill
+ if (aura->GetId() == 32409)
+ allow = true;
+ if (!allow)
+ return false;
+ }
+ // Aura added by spell can`t trogger from self (prevent drop charges/do triggers)
// But except periodic triggers (can triggered from self)
if(procSpell && procSpell->Id == spellProto->Id && !(spellProto->procFlags&PROC_FLAG_ON_TAKE_PERIODIC))
return false;
@@ -12358,13 +12939,13 @@ bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell,
{
Item *item = NULL;
if(attType == BASE_ATTACK)
- item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
else if (attType == OFF_ATTACK)
- item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
else
- item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
+ item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
- if (!((Player*)this)->IsUseEquipedWeapon(attType==BASE_ATTACK))
+ if (((Player*)this)->IsInFeralForm())
return false;
if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
@@ -12373,7 +12954,7 @@ bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell,
else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
{
// Check if player is wearing shield
- Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ Item *item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
return false;
}
@@ -12387,60 +12968,56 @@ bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell,
if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
{
uint32 WeaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
+ chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
}
// Apply chance modifer aura
if(Player* modOwner = GetSpellModOwner())
+ {
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
+ }
return roll_chance_f(chance);
}
-bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura )
+bool Unit::HandleAuraRaidProcFromChargeWithValue( AuraEffect* triggeredByAura )
{
// aura can be deleted at casts
SpellEntry const* spellProto = triggeredByAura->GetSpellProto();
uint32 effIdx = triggeredByAura->GetEffIndex();
- int32 heal = triggeredByAura->GetModifier()->m_amount;
+ int32 heal = triggeredByAura->GetAmount();
uint64 caster_guid = triggeredByAura->GetCasterGUID();
+ //Currently only Prayer Of Mending
+ if (!(spellProto->SpellFamilyName==SPELLFAMILY_PRIEST && spellProto->SpellFamilyFlags[1] & 0x20))
+ {
+ sLog.outDebug("Unit::HandleAuraRaidProcFromChargeWithValue, received not handled spell: %u", spellProto->Id);
+ return false;
+ }
// jumps
- int32 jumps = triggeredByAura->m_procCharges-1;
+ int32 jumps = triggeredByAura->GetParentAura()->GetAuraCharges()-1;
// current aura expire
- triggeredByAura->m_procCharges = 1; // will removed at next charges decrease
+ triggeredByAura->GetParentAura()->SetAuraCharges(1); // will removed at next charges decrease
// next target selection
- if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid))
+ if(jumps > 0 && IS_PLAYER_GUID(caster_guid))
{
float radius;
if (spellProto->EffectRadiusIndex[effIdx])
- radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx]));
+ radius = GetSpellRadiusForTarget(triggeredByAura->GetCaster(), sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx]));
else
- radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex));
+ radius = GetSpellMaxRangeForTarget(triggeredByAura->GetCaster() ,sSpellRangeStore.LookupEntry(spellProto->rangeIndex));
if(Player* caster = ((Player*)triggeredByAura->GetCaster()))
{
caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL);
- if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius))
+ if (Unit* target= GetNextRandomRaidMemberOrPet(radius))
{
- // aura will applied from caster, but spell casted from current aura holder
- SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_CHARGES;
- mod->value = jumps-5; // negative
- mod->type = SPELLMOD_FLAT;
- mod->spellId = spellProto->Id;
- mod->effectId = effIdx;
- mod->lastAffected = NULL;
- mod->mask = spellProto->SpellFamilyFlags;
- mod->charges = 0;
-
- caster->AddSpellMod(mod, true);
CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID());
- caster->AddSpellMod(mod, false);
-
- heal = caster->SpellHealingBonus(spellProto, heal, HEAL, this);
+ if (Aura * aur = target->GetAura(spellProto->Id, caster->GetGUID()))
+ aur->SetAuraCharges(jumps);
+ //caster->SpellHealingBonus(this, spellProto, heal, HEAL);
}
}
}
@@ -12449,29 +13026,64 @@ bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura )
CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid);
return true;
}
-
-void Unit::RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo, Unit * caster)
+bool Unit::HandleAuraRaidProcFromCharge( AuraEffect* triggeredByAura )
{
-/* uint64 target_guid = GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT);
- if(target_guid == GetGUID())
- return;
+ // aura can be deleted at casts
+ SpellEntry const* spellProto = triggeredByAura->GetSpellProto();
- if(!IS_UNIT_GUID(target_guid))
- return;
+ uint32 damageSpellId;
+ switch(spellProto->Id)
+ {
+ case 57949: //shiver
+ damageSpellId=57952;
+// animationSpellId=57951; dummy effects for jump spell have unknown use (see also 41637)
+ break;
+ case 59978: //shiver
+ damageSpellId=59979;
+ break;
+ case 43593: //Cold Stare
+ damageSpellId=43594;
+ break;
+ default:
+ sLog.outDebug("Unit::HandleAuraRaidProcFromCharge, received not handled spell: %u", spellProto->Id);
+ return false;
+ }
- Unit* target = ObjectAccessor::GetUnit(*this, target_guid);*/
- if(!caster)
- return;
+ uint64 caster_guid = triggeredByAura->GetCasterGUID();
+ uint32 effIdx = triggeredByAura->GetEffIndex();
+
+ // jumps
+ int32 jumps = triggeredByAura->GetParentAura()->GetAuraCharges()-1;
- for (AuraMap::iterator iter = GetAuras().begin(); iter != GetAuras().end(); )
+ // current aura expire
+ triggeredByAura->GetParentAura()->SetAuraCharges(1); // will removed at next charges decrease
+
+ // next target selection
+ if(jumps > 0 && IS_PLAYER_GUID(caster_guid))
{
- if (iter->second->GetId() == spellInfo->Id && iter->second->GetCasterGUID() == caster->GetGUID())
- RemoveAura(iter);
+ float radius;
+ if (spellProto->EffectRadiusIndex[effIdx])
+ radius = GetSpellRadiusForTarget(triggeredByAura->GetCaster(), sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx]));
else
- ++iter;
+ radius = GetSpellMaxRangeForTarget(triggeredByAura->GetCaster() ,sSpellRangeStore.LookupEntry(spellProto->rangeIndex));
+
+ if(Player* caster = ((Player*)triggeredByAura->GetCaster()))
+ {
+ caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL);
+
+ if (Unit* target= GetNextRandomRaidMemberOrPet(radius))
+ {
+ CastSpell(target, spellProto, true,NULL,triggeredByAura,caster_guid);
+ if (Aura * aur = target->GetAura(spellProto->Id, caster->GetGUID()))
+ aur->SetAuraCharges(jumps);
+ }
+ }
}
-}
+ CastSpell(this, damageSpellId, true,NULL,triggeredByAura,caster_guid);
+
+ return true;
+}
/*-----------------------TRINITY-----------------------------*/
void Unit::SetToNotify()
@@ -12485,6 +13097,9 @@ void Unit::SetToNotify()
void Unit::Kill(Unit *pVictim, bool durabilityLoss)
{
+ // Prevent killing unit twice (and giving reward from kill twice)
+ if (!pVictim->GetHealth())
+ return;
pVictim->SetHealth(0);
// find player: owner of controlled `this` or `this` itself maybe
@@ -12505,7 +13120,7 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
if(bRewardIsAllowed && player && player!=pVictim)
{
if(player->RewardPlayerAndGroupAtKill(pVictim))
- player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL_AND_GET_XP, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
+ player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
else
player->ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_EX_NONE, 0);
}
@@ -12514,8 +13129,8 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
bool SpiritOfRedemption = false;
if(pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST )
{
- AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
- for(AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
+ AuraEffectList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
+ for(AuraEffectList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
{
if((*itr)->GetSpellProto()->SpellIconID==1654)
{
@@ -12637,6 +13252,15 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
bg->HandleKillUnit((Creature*)pVictim, player);
}
}
+
+ // achievement stuff
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (GetTypeId() == TYPEID_UNIT)
+ ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
+ else if(GetTypeId() == TYPEID_PLAYER && pVictim != this)
+ ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ((Player*)this)->GetTeam());
+ }
}
void Unit::SetControlled(bool apply, UnitState state)
@@ -12706,14 +13330,14 @@ void Unit::SetStunned(bool apply)
if(apply)
{
SetUInt64Value(UNIT_FIELD_TARGET, 0);
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
CastStop();
// Creature specific
if(GetTypeId() != TYPEID_PLAYER)
((Creature*)this)->StopMoving();
- else
- SetUnitMovementFlags(0); //Clear movement flags
+ //else
+ // SetUnitMovementFlags(0); //Clear movement flags
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
data.append(GetPackGUID());
@@ -12724,7 +13348,7 @@ void Unit::SetStunned(bool apply)
{
if(isAlive() && getVictim())
SetUInt64Value(UNIT_FIELD_TARGET, getVictim()->GetGUID());
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
if(!hasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect
{
@@ -12745,7 +13369,7 @@ void Unit::SetRooted(bool apply)
if(GetTypeId() == TYPEID_PLAYER)
{
- SetUnitMovementFlags(0);
+ //SetUnitMovementFlags(0);
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
data.append(GetPackGUID());
@@ -12777,12 +13401,12 @@ void Unit::SetFeared(bool apply)
if(apply)
{
Unit *caster = NULL;
- Unit::AuraList const& fearAuras = GetAurasByType(SPELL_AURA_MOD_FEAR);
+ Unit::AuraEffectList const& fearAuras = GetAurasByType(SPELL_AURA_MOD_FEAR);
if(!fearAuras.empty())
caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
if(!caster)
caster = getAttackerForHelper();
- GetMotionMaster()->MoveFleeing(caster); // caster==NULL processed in MoveFleeing
+ GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? sWorld.getConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY) : 0); // caster==NULL processed in MoveFleeing
}
else
{
@@ -12820,34 +13444,37 @@ void Unit::SetCharmedOrPossessedBy(Unit* charmer, bool possess)
if(this == charmer)
return;
- if(isInFlight())
+ if(hasUnitState(UNIT_STAT_UNATTACKABLE))
return;
if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetTransport())
return;
- RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
CastStop();
CombatStop(); //TODO: CombatStop(true) may cause crash (interrupt spells)
DeleteThreatList();
// Charmer stop charming
if(charmer->GetTypeId() == TYPEID_PLAYER)
+ {
((Player*)charmer)->StopCastingCharm();
+ ((Player*)charmer)->StopCastingBindSight();
+ }
// Charmed stop charming
if(GetTypeId() == TYPEID_PLAYER)
+ {
((Player*)this)->StopCastingCharm();
+ ((Player*)this)->StopCastingBindSight();
+ }
// StopCastingCharm may remove a possessed pet?
if(!IsInWorld())
return;
// Set charmed
- charmer->SetCharm(this);
- SetCharmerGUID(charmer->GetGUID());
setFaction(charmer->getFaction());
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
+ charmer->SetCharm(this, true);
if(GetTypeId() == TYPEID_UNIT)
{
@@ -12859,11 +13486,12 @@ void Unit::SetCharmedOrPossessedBy(Unit* charmer, bool possess)
{
if(((Player*)this)->isAFK())
((Player*)this)->ToggleAFK();
- ((Player*)this)->SetViewport(GetGUID(), false);
+ ((Player*)this)->SetClientControl(this, 0);
}
// Pets already have a properly initialized CharmInfo, don't overwrite it.
- if(GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet())
+ if(GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT
+ && !((Creature*)this)->HasSummonMask(SUMMON_MASK_GUARDIAN))
{
CharmInfo *charmInfo = InitCharmInfo();
if(possess)
@@ -12876,9 +13504,9 @@ void Unit::SetCharmedOrPossessedBy(Unit* charmer, bool possess)
if(possess)
{
addUnitState(UNIT_STAT_POSSESSED);
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
- AddPlayerToVision((Player*)charmer);
- ((Player*)charmer)->SetViewport(GetGUID(), true);
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
+ ((Player*)charmer)->SetClientControl(this, 1);
+ ((Player*)charmer)->SetViewpoint(this, true);
charmer->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
}
// Charm demon
@@ -12921,13 +13549,13 @@ void Unit::RemoveCharmedOrPossessedBy(Unit *charmer)
CombatStop(); //TODO: CombatStop(true) may cause crash (interrupt spells)
getHostilRefManager().deleteReferences();
DeleteThreatList();
- SetCharmerGUID(0);
RestoreFaction();
+ GetMotionMaster()->InitDefault();
if(possess)
{
clearUnitState(UNIT_STAT_POSSESSED);
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
}
if(GetTypeId() == TYPEID_UNIT)
@@ -12948,7 +13576,7 @@ void Unit::RemoveCharmedOrPossessedBy(Unit *charmer)
}
}
else
- ((Player*)this)->SetViewport(GetGUID(), true);
+ ((Player*)this)->SetClientControl(this, 1);
// If charmer still exists
if(!charmer)
@@ -12956,11 +13584,11 @@ void Unit::RemoveCharmedOrPossessedBy(Unit *charmer)
assert(!possess || charmer->GetTypeId() == TYPEID_PLAYER);
- charmer->SetCharm(0);
+ charmer->SetCharm(this, false);
if(possess)
{
- RemovePlayerFromVision((Player*)charmer);
- ((Player*)charmer)->SetViewport(charmer->GetGUID(), true);
+ ((Player*)charmer)->SetClientControl(charmer, 1);
+ ((Player*)charmer)->SetViewpoint(this, false);
charmer->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
}
// restore UNIT_FIELD_BYTES_0
@@ -12982,7 +13610,9 @@ void Unit::RemoveCharmedOrPossessedBy(Unit *charmer)
}
}
- if(GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet())
+ //a guardian should always have charminfo
+ if(GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT
+ && !((Creature*)this)->HasSummonMask(SUMMON_MASK_GUARDIAN))
{
DeleteCharmInfo();
}
@@ -13055,17 +13685,30 @@ void Unit::GetRaidMember(std::list<Unit*> &nearMembers, float radius)
return;
Group *pGroup = owner->GetGroup();
- if(!pGroup)
- return;
-
- for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ if(pGroup)
{
- Player* Target = itr->getSource();
+ for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player* Target = itr->getSource();
- // IsHostileTo check duel and controlled by enemy
- if( Target && Target != this && Target->isAlive()
- && IsWithinDistInMap(Target, radius) && !IsHostileTo(Target) )
- nearMembers.push_back(Target);
+ if( Target && !IsHostileTo(Target) )
+ {
+ if(Target->isAlive() && IsWithinDistInMap(Target, radius) )
+ nearMembers.push_back(Target);
+
+ if(Guardian* pet = Target->GetGuardianPet())
+ if(pet->isAlive() && IsWithinDistInMap(pet, radius) )
+ nearMembers.push_back(pet);
+ }
+ }
+ }
+ else
+ {
+ if(owner->isAlive() && (owner == this || IsWithinDistInMap(owner, radius)))
+ nearMembers.push_back(owner);
+ if(Guardian* pet = owner->GetGuardianPet())
+ if(pet->isAlive() && (pet == this && IsWithinDistInMap(pet, radius)))
+ nearMembers.push_back(pet);
}
}
@@ -13090,7 +13733,7 @@ void Unit::GetPartyMember(std::list<Unit*> &TagUnitMap, float radius)
if(Target->isAlive() && IsWithinDistInMap(Target, radius) )
TagUnitMap.push_back(Target);
- if(Pet* pet = Target->GetPet())
+ if(Guardian* pet = Target->GetGuardianPet())
if(pet->isAlive() && IsWithinDistInMap(pet, radius) )
TagUnitMap.push_back(pet);
}
@@ -13100,12 +13743,38 @@ void Unit::GetPartyMember(std::list<Unit*> &TagUnitMap, float radius)
{
if(owner->isAlive() && (owner == this || IsWithinDistInMap(owner, radius)))
TagUnitMap.push_back(owner);
- if(Pet* pet = owner->GetPet())
+ if(Guardian* pet = owner->GetGuardianPet())
if(pet->isAlive() && (pet == this && IsWithinDistInMap(pet, radius)))
TagUnitMap.push_back(pet);
}
}
+void Unit::HandleAuraEffect(AuraEffect * aureff, bool apply)
+{
+ if (aureff->GetParentAura()->IsRemoved())
+ return;
+ if (apply)
+ {
+ m_modAuras[aureff->GetAuraName()].push_back(aureff);
+ aureff->ApplyModifier(true, true);
+ }
+ else
+ {
+ // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
+ m_modAuras[aureff->GetAuraName()].remove(aureff);
+ aureff->ApplyModifier(false, true);
+ Unit * caster = aureff->GetParentAura()->GetCaster();
+ if(caster && aureff->IsPersistent())
+ {
+ DynamicObject *dynObj = caster->GetDynObject(aureff->GetId(), aureff->GetEffIndex());
+ if (dynObj)
+ dynObj->RemoveAffected(this);
+ }
+ // Remove all triggered by aura spells vs unlimited duration
+ aureff->CleanupTriggeredSpells();
+ }
+}
+
void Unit::AddAura(uint32 spellId, Unit* target)
{
if(!target || !target->isAlive())
@@ -13118,23 +13787,374 @@ void Unit::AddAura(uint32 spellId, Unit* target)
if (target->IsImmunedToSpell(spellInfo))
return;
+ uint8 eff_mask=0;
+
for(uint32 i = 0; i < 3; ++i)
{
- if(spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA)
+ if(spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA || IsAreaAuraEffect(spellInfo->Effect[i]))
{
- if(target->IsImmunedToSpellEffect(spellInfo->Effect[i], spellInfo->EffectMechanic[i]))
+ if(target->IsImmunedToSpellEffect(spellInfo, i))
continue;
+ eff_mask|=1<<i;
+ }
+ }
- /*if(spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_CASTER)
- {
- Aura *Aur = CreateAura(spellInfo, i, NULL, this, this);
- AddAura(Aur);
- }
- else*/
- {
- Aura *Aur = CreateAura(spellInfo, i, NULL, target, this);
- target->AddAura(Aur);
- }
+ if (!eff_mask)
+ return;
+
+ //TODO: we use target as source for now, but that may not be true
+ Aura *Aur = new Aura(spellInfo, eff_mask, NULL, target, target, this, NULL);
+ target->AddAura(Aur);
+}
+
+void Unit::SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
+{
+ Aura *aur = target->GetAura(spellId, GetGUID());
+ if(!aur)
+ {
+ AddAura(spellId, target);
+ aur = target->GetAura(spellId, GetGUID());
+ }
+ if(aur && stack)
+ aur->SetStackAmount(stack);
+}
+
+Aura * Unit::AddAuraEffect(const SpellEntry * spellInfo, uint8 effIndex, Unit* caster, int32 * basePoints, Unit * source)
+{
+ // can't do that for passive auras - they stack from same caster so there is no way to get exact aura which should get effect
+ //assert (!IsPassiveSpell(spellInfo));
+
+ sLog.outDebug("AddAuraEffect: spell id: %u, effect index: %u", spellInfo->Id, (uint32)effIndex);
+
+ Aura *aur = GetAura(spellInfo->Id, caster->GetGUID());
+
+ if (aur)
+ {
+ AuraEffect *aurEffect = CreateAuraEffect(aur, effIndex, basePoints, caster,NULL, source);
+ if (aurEffect && !aur->SetPartAura(aurEffect, effIndex))
+ delete aurEffect;
+ }
+ else
+ {
+ if (basePoints)
+ {
+ int32 amount[3];
+ amount[effIndex] = *basePoints;
+ aur = new Aura(spellInfo, 1<<effIndex, amount, this, source, caster, NULL);
+ }
+ else
+ aur = new Aura(spellInfo, 1<<effIndex, NULL, this, source ,caster, NULL);
+
+ if(!AddAura(aur))
+ return NULL;
+ }
+ return aur;
+}
+
+// Melee based spells can be miss, parry or dodge on this step
+// Crit or block - determined on damage calculation phase! (and can be both in some time)
+float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
+{
+ // Calculate hit chance (more correct for chance mod)
+ int32 HitChance;
+
+ // PvP - PvE melee chances
+ /*int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
+ int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
+ if(leveldif < 3)
+ HitChance = 95 - leveldif;
+ else
+ HitChance = 93 - (leveldif - 2) * lchance;*/
+ if (spellId || attType == RANGED_ATTACK || !haveOffhandWeapon())
+ HitChance = 95.0f;
+ else
+ HitChance = 76.0f;
+
+ // Hit chance depends from victim auras
+ if(attType == RANGED_ATTACK)
+ HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
+ else
+ HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
+
+ // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
+ if(spellId)
+ {
+ if(Player *modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
+ }
+
+ // Miss = 100 - hit
+ float miss_chance= 100.0f - HitChance;
+
+ // Bonuses from attacker aura and ratings
+ if (attType == RANGED_ATTACK)
+ miss_chance -= m_modRangedHitChance;
+ else
+ miss_chance -= m_modMeleeHitChance;
+
+ // bonus from skills is 0.04%
+ //miss_chance -= skillDiff * 0.04f;
+ int32 diff = -skillDiff;
+ if(pVictim->GetTypeId()==TYPEID_PLAYER)
+ miss_chance += diff > 0 ? diff * 0.04 : diff * 0.02;
+ else
+ miss_chance += diff > 10 ? 2 + (diff - 10) * 0.4 : diff * 0.1;
+
+ // Limit miss chance from 0 to 60%
+ if (miss_chance < 0.0f)
+ return 0.0f;
+ if (miss_chance > 60.0f)
+ return 60.0f;
+ return miss_chance;
+}
+
+void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
+{
+ WorldObject::SetPhaseMask(newPhaseMask,update);
+
+ if(!IsInWorld())
+ return;
+
+ for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
+ if((*itr)->GetOwnerGUID() == GetGUID())
+ (*itr)->SetPhaseMask(newPhaseMask,true);
+
+ for(int8 i = 0; i < MAX_SUMMON_SLOT; ++i)
+ if(m_SummonSlot[i])
+ if(Creature *summon = GetMap()->GetCreature(m_SummonSlot[i]))
+ summon->SetPhaseMask(newPhaseMask,true);
+}
+
+void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
+{
+ if(GetTypeId() == TYPEID_UNIT)
+ {
+ GetMotionMaster()->MoveKnockbackFrom(x, y, speedXY, speedZ);
+ }
+ else
+ {
+ float vcos, vsin;
+ GetSinCos(x, y, vsin, vcos);
+
+ WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
+ data.append(GetPackGUID());
+ data << uint32(0); // Sequence
+ data << float(vcos); // x direction
+ data << float(vsin); // y direction
+ data << float(speedXY); // Horizontal speed
+ data << float(-speedZ); // Z Movement speed (vertical)
+
+ ((Player*)this)->GetSession()->SendPacket(&data);
+ }
+}
+
+void Unit::JumpTo(float speedXY, float speedZ, bool forward)
+{
+ float angle = forward ? 0 : M_PI;
+ if(GetTypeId() == TYPEID_UNIT)
+ {
+ GetMotionMaster()->MoveJumpTo(angle, speedXY, speedZ);
+ }
+ else
+ {
+ float vcos = cos(angle+GetOrientation());
+ float vsin = sin(angle+GetOrientation());
+
+ WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
+ data.append(GetPackGUID());
+ data << uint32(0); // Sequence
+ data << float(vcos); // x direction
+ data << float(vsin); // y direction
+ data << float(speedXY); // Horizontal speed
+ data << float(-speedZ); // Z Movement speed (vertical)
+
+ ((Player*)this)->GetSession()->SendPacket(&data);
+ }
+}
+
+void Unit::JumpTo(WorldObject *obj, float speedZ)
+{
+ float x, y, z;
+ obj->GetContactPoint(this, x, y, z);
+ float speedXY = GetExactDistance2d(x, y) * 10.0f / speedZ;
+ GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ);
+}
+
+void Unit::EnterVehicle(Vehicle *vehicle, int8 seatId)
+{
+ if(!isAlive() || this == vehicle)
+ return;
+
+ if(m_Vehicle)
+ {
+ if(m_Vehicle == vehicle)
+ {
+ if(seatId >= 0)
+ ChangeSeat(seatId);
+ return;
}
+ else
+ ExitVehicle();
+ }
+
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)this)->StopCastingCharm();
+ ((Player*)this)->StopCastingBindSight();
+ }
+
+ assert(!m_Vehicle);
+ m_Vehicle = vehicle;
+ if(!m_Vehicle->AddPassenger(this, seatId))
+ {
+ m_Vehicle = NULL;
+ return;
+ }
+
+ m_Vehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
+ //m_Vehicle->setFaction(getFaction());
+
+ addUnitState(UNIT_STAT_ONVEHICLE);
+ //movementInfo is set in AddPassenger
+ //packets are sent in AddPassenger
+
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)this)->SetClientControl(vehicle, 1);
+ WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
+ ((Player*)this)->GetSession()->SendPacket(&data);
+ }
+}
+
+void Unit::ChangeSeat(int8 seatId, bool next)
+{
+ if(!m_Vehicle)
+ return;
+
+ if(seatId < 0)
+ {
+ seatId = m_Vehicle->GetNextEmptySeat(GetTransSeat(), next);
+ if(seatId < 0)
+ return;
+ }
+ else if(seatId == GetTransSeat() || !m_Vehicle->HasEmptySeat(seatId))
+ return;
+
+ m_Vehicle->RemovePassenger(this);
+ if(!m_Vehicle->AddPassenger(this, seatId))
+ assert(false);
+}
+
+void Unit::ExitVehicle()
+{
+ if(!m_Vehicle)
+ return;
+
+ m_Vehicle->RemovePassenger(this);
+
+ m_Vehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
+ //setFaction((GetTeam() == ALLIANCE) ? GetCreatureInfo()->faction_A : GetCreatureInfo()->faction_H);
+
+ clearUnitState(UNIT_STAT_ONVEHICLE);
+ RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+
+ m_movementInfo.t_x = 0;
+ m_movementInfo.t_y = 0;
+ m_movementInfo.t_z = 0;
+ m_movementInfo.t_o = 0;
+ m_movementInfo.t_time = 0;
+ m_movementInfo.t_seat = 0;
+
+ //Send leave vehicle
+ WorldPacket data;
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)this)->SetClientControl(this, 1);
+ ((Player*)this)->BuildTeleportAckMsg(&data, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
+ ((Player*)this)->GetSession()->SendPacket(&data);
+ }
+
+ BuildHeartBeatMsg(&data);
+ SendMessageToSet(&data, false);
+
+ // This should be done before dismiss, because there may be some aura removal
+ Vehicle *vehicle = m_Vehicle;
+ m_Vehicle = NULL;
+
+ if(vehicle->GetOwnerGUID() == GetGUID())
+ vehicle->Dismiss();
+}
+
+void Unit::BuildMovementPacket(ByteBuffer *data) const
+{
+ // 0x00000200
+ if(GetUnitMovementFlags() & MOVEMENTFLAG_ONTRANSPORT)
+ {
+ if(m_Vehicle)
+ *data << (uint64)m_Vehicle->GetGUID();
+ else if(GetTransport())
+ *data << (uint64)GetTransport()->GetGUID();
+ else
+ *data << (uint64)0; //This will cause client crash
+ *data << float (GetTransOffsetX());
+ *data << float (GetTransOffsetY());
+ *data << float (GetTransOffsetZ());
+ *data << float (GetTransOffsetO());
+ *data << uint32(GetTransTime());
+ *data << uint8 (GetTransSeat());
+ }
+
+ // 0x02200000
+ if((GetUnitMovementFlags() & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2))
+ || (m_movementInfo.unk1 & 0x20))
+ *data << (float)m_movementInfo.s_pitch;
+
+ *data << (uint32)m_movementInfo.fallTime;
+
+ // 0x00001000
+ if(GetUnitMovementFlags() & MOVEMENTFLAG_JUMPING)
+ {
+ *data << (float)m_movementInfo.j_zspeed;
+ *data << (float)m_movementInfo.j_sinAngle;
+ *data << (float)m_movementInfo.j_cosAngle;
+ *data << (float)m_movementInfo.j_xyspeed;
+ }
+
+ // 0x04000000
+ if(GetUnitMovementFlags() & MOVEMENTFLAG_SPLINE)
+ *data << (float)m_movementInfo.u_unk1;
+}
+
+void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool casting /*= false*/ )
+{
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player*)this)->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0));
+ else
+ {
+ WorldPacket data;
+ /*data.Initialize(MSG_MOVE_TELEPORT, 30);
+ data.append(GetPackGUID());
+ data << uint32(GetUnitMovementFlags());
+ data << uint16(0); // Probably walk flags here
+ data << getMSTime(); // time
+ data << x; // destination coords
+ data << y;
+ data << z;
+ data << orientation;
+ data << uint32 (0);
+ // Other information here: jumping angle etc
+ SendMessageToSet(&data, false);*/
+
+ // FIXME: this interrupts spell visual
+ DestroyForNearbyPlayers();
+
+ GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation);
+ //ObjectAccessor::UpdateObjectVisibility(this);
+
+ //WorldPacket data;
+ // Work strange for many spells: triggered active mover set for targeted player to creature
+ //BuildTeleportAckMsg(&data, x, y, z, orientation);
+ //BuildHeartBeatMsg(&data);
+ //SendMessageToSet(&data, false);
}
}
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 0a8cfc2c444..f92c5335b5b 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
#include "Common.h"
#include "Object.h"
#include "Opcodes.h"
-#include "Mthread.h"
#include "SpellAuraDefines.h"
#include "UpdateFields.h"
#include "SharedDefines.h"
@@ -34,7 +33,7 @@
#include "FollowerRefManager.h"
#include "Utilities/EventProcessor.h"
#include "MotionMaster.h"
-#include "Database/DBCStructure.h"
+#include "DBCStructure.h"
#include <list>
#define WORLD_TRIGGER 12999
@@ -45,7 +44,8 @@ enum SpellInterruptFlags
SPELL_INTERRUPT_FLAG_PUSH_BACK = 0x02, // push back
SPELL_INTERRUPT_FLAG_INTERRUPT = 0x04, // interrupt
SPELL_INTERRUPT_FLAG_AUTOATTACK = 0x08, // no
- SPELL_INTERRUPT_FLAG_DAMAGE = 0x10 // _complete_ interrupt on direct damage?
+ SPELL_INTERRUPT_FLAG_ABORT_ON_DMG = 0x10, // _complete_ interrupt on direct damage
+ //SPELL_INTERRUPT_UNK = 0x20 // unk, 564 of 727 spells having this spell start with "Glyph"
};
enum SpellChannelInterruptFlags
@@ -79,11 +79,13 @@ enum SpellAuraInterruptFlags
AURA_INTERRUPT_FLAG_MOUNT = 0x00020000, // 17 misdirect, aspect, swim speed
AURA_INTERRUPT_FLAG_NOT_SEATED = 0x00040000, // 18 removed by standing up
AURA_INTERRUPT_FLAG_CHANGE_MAP = 0x00080000, // 19 leaving map/getting teleported
- AURA_INTERRUPT_FLAG_UNATTACKABLE = 0x00100000, // 20 invulnerable or stealth
+ AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION = 0x00100000, // 20 removed by auras that make you invulnerable, or make other to loose selection on you
AURA_INTERRUPT_FLAG_UNK21 = 0x00200000, // 21
AURA_INTERRUPT_FLAG_TELEPORTED = 0x00400000, // 22
AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT = 0x00800000, // 23 removed by entering pvp combat
- AURA_INTERRUPT_FLAG_DIRECT_DAMAGE = 0x01000000 // 24 removed by any direct damage
+ AURA_INTERRUPT_FLAG_DIRECT_DAMAGE = 0x01000000, // 24 removed by any direct damage
+
+ AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE),
};
enum SpellModOp
@@ -101,7 +103,7 @@ enum SpellModOp
SPELLMOD_CASTING_TIME = 10,
SPELLMOD_COOLDOWN = 11,
SPELLMOD_EFFECT2 = 12,
- // spellmod 13 unused
+ SPELLMOD_IGNORE_ARMOR = 13,
SPELLMOD_COST = 14,
SPELLMOD_CRIT_DAMAGE_BONUS = 15,
SPELLMOD_RESIST_MISS_CHANCE = 16,
@@ -109,13 +111,16 @@ enum SpellModOp
SPELLMOD_CHANCE_OF_SUCCESS = 18,
SPELLMOD_ACTIVATION_TIME = 19,
SPELLMOD_EFFECT_PAST_FIRST = 20,
- SPELLMOD_CASTING_TIME_OLD = 21,
+ SPELLMOD_GLOBAL_COOLDOWN = 21, //TODO: GCD is not checked by server currently
SPELLMOD_DOT = 22,
SPELLMOD_EFFECT3 = 23,
SPELLMOD_SPELL_BONUS_DAMAGE = 24,
- // spellmod 25, 26 unused
+ // spellmod 25
+ SPELLMOD_PROC_PER_MINUTE = 26,
SPELLMOD_MULTIPLE_VALUE = 27,
- SPELLMOD_RESIST_DISPEL_CHANCE = 28
+ SPELLMOD_RESIST_DISPEL_CHANCE = 28,
+ SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
+ SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30
};
#define MAX_SPELLMOD 32
@@ -125,6 +130,7 @@ enum SpellValueMod
SPELLVALUE_BASE_POINT0,
SPELLVALUE_BASE_POINT1,
SPELLVALUE_BASE_POINT2,
+ SPELLVALUE_RADIUS_MOD,
SPELLVALUE_MAX_TARGETS,
};
@@ -147,6 +153,35 @@ enum SpellFacingFlags
#define BASE_MAXDAMAGE 2.0f
#define BASE_ATTACK_TIME 2000
+// byte value (UNIT_FIELD_BYTES_1,0)
+enum UnitStandStateType
+{
+ UNIT_STAND_STATE_STAND = 0,
+ UNIT_STAND_STATE_SIT = 1,
+ UNIT_STAND_STATE_SIT_CHAIR = 2,
+ UNIT_STAND_STATE_SLEEP = 3,
+ UNIT_STAND_STATE_SIT_LOW_CHAIR = 4,
+ UNIT_STAND_STATE_SIT_MEDIUM_CHAIR = 5,
+ UNIT_STAND_STATE_SIT_HIGH_CHAIR = 6,
+ UNIT_STAND_STATE_DEAD = 7,
+ UNIT_STAND_STATE_KNEEL = 8
+};
+
+// byte flag value (UNIT_FIELD_BYTES_1,2)
+enum UnitStandFlags
+{
+ UNIT_STAND_FLAGS_CREEP = 0x02,
+ UNIT_STAND_FLAGS_ALL = 0xFF
+};
+
+// byte flags value (UNIT_FIELD_BYTES_1,3)
+enum UnitBytes1_Flags
+{
+ UNIT_BYTE1_FLAG_ALWAYS_STAND = 0x01,
+ UNIT_BYTE1_FLAG_UNTRACKABLE = 0x04,
+ UNIT_BYTE1_FLAG_ALL = 0xFF
+};
+
// high byte (3 from 0..3) of UNIT_FIELD_BYTES_2
enum ShapeshiftForm
{
@@ -167,6 +202,7 @@ enum ShapeshiftForm
FORM_BERSERKERSTANCE = 0x13,
FORM_TEST = 0x14,
FORM_ZOMBIE = 0x15,
+ FORM_METAMORPHOSIS = 0x16,
FORM_FLIGHT_EPIC = 0x1B,
FORM_SHADOW = 0x1C,
FORM_FLIGHT = 0x1D,
@@ -186,14 +222,14 @@ enum SheathState
// byte (1 from 0..3) of UNIT_FIELD_BYTES_2
enum UnitBytes2_Flags
{
- UNIT_BYTE2_FLAG_UNK0 = 0x01,
- UNIT_BYTE2_FLAG_UNK1 = 0x02,
- UNIT_BYTE2_FLAG_UNK2 = 0x04,
+ UNIT_BYTE2_FLAG_PVP = 0x01,
+ UNIT_BYTE2_FLAG_UNK1 = 0x02,
+ UNIT_BYTE2_FLAG_FFA_PVP = 0x04,
UNIT_BYTE2_FLAG_SANCTUARY = 0x08,
- UNIT_BYTE2_FLAG_AURAS = 0x10, // show possitive auras as positive, and allow its dispel
- UNIT_BYTE2_FLAG_UNK5 = 0x20,
- UNIT_BYTE2_FLAG_UNK6 = 0x40,
- UNIT_BYTE2_FLAG_UNK7 = 0x80
+ UNIT_BYTE2_FLAG_UNK4 = 0x10,
+ UNIT_BYTE2_FLAG_UNK5 = 0x20,
+ UNIT_BYTE2_FLAG_UNK6 = 0x40,
+ UNIT_BYTE2_FLAG_UNK7 = 0x80
};
// byte (2 from 0..3) of UNIT_FIELD_BYTES_2
@@ -203,7 +239,11 @@ enum UnitRename
UNIT_RENAME_ALLOWED = 0x03
};
-#define CREATURE_MAX_SPELLS 4
+#define CREATURE_MAX_SPELLS 8
+#define MAX_SPELL_CHARM 4
+#define MAX_SPELL_VEHICLE 6
+#define MAX_SPELL_POSSESS 8
+#define MAX_SPELL_CONTROL_BAR 10
enum Swing
{
@@ -231,16 +271,27 @@ enum HitInfo
HITINFO_UNK1 = 0x00000001, // req correct packet structure
HITINFO_NORMALSWING2 = 0x00000002,
HITINFO_LEFTSWING = 0x00000004,
+ HITINFO_UNK2 = 0x00000008,
HITINFO_MISS = 0x00000010,
- HITINFO_ABSORB = 0x00000020, // plays absorb sound
- HITINFO_RESIST = 0x00000040, // resisted at least some damage
- HITINFO_CRITICALHIT = 0x00000080,
- HITINFO_UNK2 = 0x00000100, // wotlk?
- HITINFO_UNK3 = 0x00002000, // wotlk?
- HITINFO_GLANCING = 0x00004000,
- HITINFO_CRUSHING = 0x00008000,
- HITINFO_NOACTION = 0x00010000,
- HITINFO_SWINGNOHITSOUND = 0x00080000
+ HITINFO_ABSORB = 0x00000020, // absorbed damage
+ HITINFO_ABSORB2 = 0x00000040, // absorbed damage
+ HITINFO_RESIST = 0x00000080, // resisted atleast some damage
+ HITINFO_RESIST2 = 0x00000100, // resisted atleast some damage
+ HITINFO_CRITICALHIT = 0x00000200, // critical hit
+ // 0x00000400
+ // 0x00000800
+ // 0x00001000
+ HITINFO_BLOCK = 0x00002000, // blocked damage
+ // 0x00004000
+ // 0x00008000
+ HITINFO_GLANCING = 0x00010000,
+ HITINFO_CRUSHING = 0x00020000,
+ HITINFO_NOACTION = 0x00040000, // guessed
+ // 0x00080000
+ // 0x00100000
+ HITINFO_SWINGNOHITSOUND = 0x00200000, // guessed
+ // 0x00400000
+ HITINFO_UNK3 = 0x00800000
};
//i would like to remove this: (it is defined in item.h
@@ -251,11 +302,11 @@ enum InventorySlot
};
struct FactionTemplateEntry;
-struct Modifier;
struct SpellEntry;
struct SpellValue;
class Aura;
+class AuraEffect;
class Creature;
class Spell;
class DynamicObject;
@@ -264,6 +315,10 @@ class Item;
class Pet;
class Path;
class PetAura;
+class Minion;
+class Guardian;
+class UnitAI;
+class Transport;
struct SpellImmune
{
@@ -297,10 +352,11 @@ enum DamageTypeToSchool
enum AuraRemoveMode
{
- AURA_REMOVE_BY_DEFAULT,
- AURA_REMOVE_BY_STACK, // at replace by semillar aura
+ AURA_REMOVE_BY_DEFAULT=0,
+ AURA_REMOVE_BY_STACK, // change stack, single aura remove,
AURA_REMOVE_BY_CANCEL,
- AURA_REMOVE_BY_DISPEL,
+ AURA_REMOVE_BY_ENEMY_SPELL, // dispel and absorb aura destroy
+ AURA_REMOVE_BY_EXPIRE, // dispel and absorb aura destroy
AURA_REMOVE_BY_DEATH
};
@@ -312,11 +368,13 @@ enum UnitMods
UNIT_MOD_STAT_INTELLECT,
UNIT_MOD_STAT_SPIRIT,
UNIT_MOD_HEALTH,
- UNIT_MOD_MANA, // UNIT_MOD_MANA..UNIT_MOD_HAPPINESS must be in existed order, it's accessed by index values of Powers enum.
+ UNIT_MOD_MANA, // UNIT_MOD_MANA..UNIT_MOD_RUNIC_POWER must be in existed order, it's accessed by index values of Powers enum.
UNIT_MOD_RAGE,
UNIT_MOD_FOCUS,
UNIT_MOD_ENERGY,
UNIT_MOD_HAPPINESS,
+ UNIT_MOD_RUNE,
+ UNIT_MOD_RUNIC_POWER,
UNIT_MOD_ARMOR, // UNIT_MOD_ARMOR..UNIT_MOD_RESISTANCE_ARCANE must be in existed order, it's accessed by index values of SpellSchools enum.
UNIT_MOD_RESISTANCE_HOLY,
UNIT_MOD_RESISTANCE_FIRE,
@@ -336,7 +394,7 @@ enum UnitMods
UNIT_MOD_RESISTANCE_START = UNIT_MOD_ARMOR,
UNIT_MOD_RESISTANCE_END = UNIT_MOD_RESISTANCE_ARCANE + 1,
UNIT_MOD_POWER_START = UNIT_MOD_MANA,
- UNIT_MOD_POWER_END = UNIT_MOD_HAPPINESS + 1
+ UNIT_MOD_POWER_END = UNIT_MOD_RUNIC_POWER + 1
};
enum BaseModGroup
@@ -386,9 +444,13 @@ enum UnitState
UNIT_STAT_CASTING = 0x00008000,
UNIT_STAT_POSSESSED = 0x00010000,
UNIT_STAT_CHARGING = 0x00020000,
- UNIT_STAT_MOVE = 0x00040000,
+ UNIT_STAT_JUMPING = 0x00040000,
+ UNIT_STAT_ONVEHICLE = 0x00080000,
+ UNIT_STAT_MOVE = 0x00100000,
+ UNIT_STAT_UNATTACKABLE = (UNIT_STAT_IN_FLIGHT | UNIT_STAT_ONVEHICLE),
UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE),
- UNIT_STAT_LOST_CONTROL = (UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_CHARGING),
+ UNIT_STAT_CONTROLLED = (UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING),
+ UNIT_STAT_LOST_CONTROL = (UNIT_STAT_CONTROLLED | UNIT_STAT_JUMPING | UNIT_STAT_CHARGING),
UNIT_STAT_SIGHTLESS = (UNIT_STAT_LOST_CONTROL),
UNIT_STAT_CANNOT_AUTOATTACK = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_CASTING),
UNIT_STAT_ALL_STATE = 0xffffffff //(UNIT_STAT_STOPPED | UNIT_STAT_MOVING | UNIT_STAT_IN_COMBAT | UNIT_STAT_IN_FLIGHT)
@@ -404,23 +466,21 @@ enum UnitMoveType
MOVE_TURN_RATE = 5,
MOVE_FLIGHT = 6,
MOVE_FLIGHT_BACK = 7,
+ MOVE_PITCH_RATE = 8
};
-#define MAX_MOVE_TYPE 8
+#define MAX_MOVE_TYPE 9
extern float baseMoveSpeed[MAX_MOVE_TYPE];
-// assume it is 25 yard per 0.6 second
-#define SPEED_CHARGE 42.0f
enum WeaponAttackType
{
BASE_ATTACK = 0,
OFF_ATTACK = 1,
- RANGED_ATTACK = 2
+ RANGED_ATTACK = 2,
+ MAX_ATTACK
};
-#define MAX_ATTACK 3
-
enum CombatRating
{
CR_WEAPON_SKILL = 0,
@@ -446,10 +506,11 @@ enum CombatRating
CR_WEAPON_SKILL_MAINHAND = 20,
CR_WEAPON_SKILL_OFFHAND = 21,
CR_WEAPON_SKILL_RANGED = 22,
- CR_EXPERTISE = 23
+ CR_EXPERTISE = 23,
+ CR_ARMOR_PENETRATION = 24
};
-#define MAX_COMBAT_RATING 24
+#define MAX_COMBAT_RATING 25
enum DamageEffectType
{
@@ -474,45 +535,50 @@ enum UnitVisibility
// Value masks for UNIT_FIELD_FLAGS
enum UnitFlags
{
- UNIT_FLAG_UNKNOWN7 = 0x00000001,
+ UNIT_FLAG_UNK_0 = 0x00000001,
UNIT_FLAG_NON_ATTACKABLE = 0x00000002, // not attackable
UNIT_FLAG_DISABLE_MOVE = 0x00000004,
UNIT_FLAG_PVP_ATTACKABLE = 0x00000008, // allow apply pvp rules to attackable state in addition to faction dependent state
UNIT_FLAG_RENAME = 0x00000010,
UNIT_FLAG_PREPARATION = 0x00000020, // don't take reagents for spells with SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP
- UNIT_FLAG_UNKNOWN9 = 0x00000040,
+ UNIT_FLAG_UNK_6 = 0x00000040,
UNIT_FLAG_NOT_ATTACKABLE_1 = 0x00000080, // ?? (UNIT_FLAG_PVP_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1) is NON_PVP_ATTACKABLE
UNIT_FLAG_NOT_ATTACKABLE_2 = 0x00000100, // 2.0.8
- UNIT_FLAG_UNKNOWN11 = 0x00000200,
+ UNIT_FLAG_UNK_9 = 0x00000200, // 3.0.3 - makes you unable to attack everything
UNIT_FLAG_LOOTING = 0x00000400, // loot animation
UNIT_FLAG_PET_IN_COMBAT = 0x00000800, // in combat?, 2.0.8
- UNIT_FLAG_PVP = 0x00001000,
+ UNIT_FLAG_PVP = 0x00001000, // changed in 3.0.3
UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1
- UNIT_FLAG_UNKNOWN4 = 0x00004000, // 2.0.8
- UNIT_FLAG_UNKNOWN13 = 0x00008000,
- UNIT_FLAG_UNKNOWN14 = 0x00010000,
- UNIT_FLAG_PACIFIED = 0x00020000,
- UNIT_FLAG_DISABLE_ROTATE = 0x00040000, // stunned, 2.1.1
+ UNIT_FLAG_UNK_14 = 0x00004000, // 2.0.8
+ UNIT_FLAG_UNK_15 = 0x00008000,
+ UNIT_FLAG_UNK_16 = 0x00010000,
+ UNIT_FLAG_PACIFIED = 0x00020000, // 3.0.3 ok
+ UNIT_FLAG_STUNNED = 0x00040000, // 3.0.3 ok
UNIT_FLAG_IN_COMBAT = 0x00080000,
UNIT_FLAG_TAXI_FLIGHT = 0x00100000, // disable casting at client side spell not allowed by taxi flight (mounted?), probably used with 0x4 flag
- UNIT_FLAG_DISARMED = 0x00200000, // disable melee spells casting..., "Required melee weapon" added to melee spells tooltip.
+ UNIT_FLAG_DISARMED = 0x00200000, // 3.0.3, disable melee spells casting..., "Required melee weapon" added to melee spells tooltip.
UNIT_FLAG_CONFUSED = 0x00400000,
UNIT_FLAG_FLEEING = 0x00800000,
- UNIT_FLAG_UNKNOWN5 = 0x01000000, // used in spell Eyes of the Beast for pet...
+ UNIT_FLAG_UNK_24 = 0x01000000, // used in spell Eyes of the Beast for pet...
UNIT_FLAG_NOT_SELECTABLE = 0x02000000,
UNIT_FLAG_SKINNABLE = 0x04000000,
UNIT_FLAG_MOUNT = 0x08000000,
- UNIT_FLAG_UNKNOWN17 = 0x10000000,
- UNIT_FLAG_UNKNOWN6 = 0x20000000, // used in Feing Death spell
- UNIT_FLAG_SHEATHE = 0x40000000
+ UNIT_FLAG_UNK_28 = 0x10000000,
+ UNIT_FLAG_UNK_29 = 0x20000000, // used in Feing Death spell
+ UNIT_FLAG_SHEATHE = 0x40000000,
+ UNIT_FLAG_UNK_31 = 0x80000000
};
// Value masks for UNIT_FIELD_FLAGS_2
enum UnitFlags2
{
- UNIT_FLAG2_FEIGN_DEATH = 0x00000001,
- UNIT_FLAG2_COMPREHEND_LANG= 0x00000008,
- UNIT_FLAG2_FORCE_MOVE = 0x00000040
+ UNIT_FLAG2_FEIGN_DEATH = 0x00000001,
+ UNIT_FLAG2_UNK1 = 0x00000002, // Hide unit model (show only player equip)
+ UNIT_FLAG2_COMPREHEND_LANG = 0x00000008,
+ UNIT_FLAG2_FORCE_MOVE = 0x00000040,
+ UNIT_FLAG2_DISARM_OFFHAND = 0x00000080,
+ UNIT_FLAG2_DISARM_RANGED = 0x00000400, //this does not disable ranged weapon display (maybe additional flag needed?)
+ UNIT_FLAG2_REGENERATE_POWER = 0x00000800
};
/// Non Player Character flags
@@ -590,6 +656,37 @@ enum MovementFlags
MOVEMENTFLAG_UNK3 = 0x40000000
};
+struct MovementInfo
+{
+ // common
+ uint32 flags;
+ uint16 unk1;
+ uint32 time;
+ float x, y, z, o;
+ // transport
+ uint64 t_guid;
+ float t_x, t_y, t_z, t_o;
+ uint32 t_time;
+ int8 t_seat;
+ // swimming and unknown
+ float s_pitch;
+ // last fall time
+ uint32 fallTime;
+ // jumping
+ float j_zspeed, j_sinAngle, j_cosAngle, j_xyspeed;
+ // spline
+ float u_unk1;
+
+ MovementInfo()
+ {
+ flags = 0;
+ time = t_time = fallTime = 0;
+ unk1 = 0;
+ x = y = z = o = t_x = t_y = t_z = t_o = s_pitch = j_zspeed = j_sinAngle = j_cosAngle = j_xyspeed = u_unk1 = 0.0f;
+ t_guid = 0;
+ }
+};
+
enum DiminishingLevels
{
DIMINISHING_LEVEL_1 = 0,
@@ -600,7 +697,9 @@ enum DiminishingLevels
struct DiminishingReturn
{
- DiminishingReturn(DiminishingGroup group, uint32 t, uint32 count) : DRGroup(group), hitTime(t), hitCount(count), stack(0) {}
+ DiminishingReturn(DiminishingGroup group, uint32 t, uint32 count)
+ : DRGroup(group), stack(0), hitTime(t), hitCount(count)
+ {}
DiminishingGroup DRGroup:16;
uint16 stack:16;
@@ -611,8 +710,9 @@ struct DiminishingReturn
enum MeleeHitOutcome
{
MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY,
- MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL, MELEE_HIT_BLOCK_CRIT
+ MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL
};
+
struct CleanDamage
{
CleanDamage(uint32 _damage, WeaponAttackType _attackType, MeleeHitOutcome _hitOutCome) :
@@ -647,30 +747,45 @@ struct CalcDamageInfo
// Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode
struct SpellNonMeleeDamage{
- SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask) :
- attacker(_attacker), target(_target), SpellID(_SpellID), damage(0), schoolMask(_schoolMask),
- absorb(0), resist(0), phusicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) {}
- Unit *target;
- Unit *attacker;
- uint32 SpellID;
- uint32 damage;
- uint32 schoolMask;
- uint32 absorb;
- uint32 resist;
- bool phusicalLog;
- bool unused;
- uint32 blocked;
- uint32 HitInfo;
- // Used for help
- uint32 cleanDamage;
+ SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask)
+ : target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask),
+ absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0)
+ {}
+
+ Unit *target;
+ Unit *attacker;
+ uint32 SpellID;
+ uint32 damage;
+ uint32 overkill;
+ uint32 schoolMask;
+ uint32 absorb;
+ uint32 resist;
+ bool physicalLog;
+ bool unused;
+ uint32 blocked;
+ uint32 HitInfo;
+ // Used for help
+ uint32 cleanDamage;
};
uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition);
struct UnitActionBarEntry
{
- uint32 Type;
- uint32 SpellOrAction;
+ UnitActionBarEntry() : Raw(0) {}
+
+ union
+ {
+ struct
+ {
+ uint16 SpellOrAction;
+ uint16 Type;
+ };
+ struct
+ {
+ uint32 Raw;
+ };
+ };
};
#define MAX_DECLINED_NAME_CASES 5
@@ -692,13 +807,12 @@ enum CurrentSpellTypes
enum ActiveStates
{
- ACT_ENABLED = 0xC100,
- ACT_DISABLED = 0x8100,
- ACT_COMMAND = 0x0700,
- ACT_REACTION = 0x0600,
- ACT_CAST = 0x0100,
- ACT_PASSIVE = 0x0000,
- ACT_DECIDE = 0x0001
+ ACT_PASSIVE = 0x0100, // 0x0100 - passive
+ ACT_DISABLED = 0x8100, // 0x8000 - castable
+ ACT_ENABLED = 0xC100, // 0x4000 | 0x8000 - auto cast + castable
+ ACT_COMMAND = 0x0700, // 0x0100 | 0x0200 | 0x0400
+ ACT_REACTION = 0x0600, // 0x0200 | 0x0400
+ ACT_DECIDE = 0x0001 // what is it?
};
enum ReactStates
@@ -767,15 +881,18 @@ struct TRINITY_DLL_SPEC CharmInfo
enum ReactiveType
{
- REACTIVE_DEFENSE = 1,
- REACTIVE_HUNTER_PARRY = 2,
- REACTIVE_CRIT = 3,
- REACTIVE_HUNTER_CRIT = 4,
- REACTIVE_OVERPOWER = 5
+ REACTIVE_DEFENSE = 0,
+ REACTIVE_HUNTER_PARRY = 1,
+ REACTIVE_OVERPOWER = 2
};
-#define MAX_REACTIVE 6
-#define MAX_TOTEM 4
+#define MAX_REACTIVE 3
+#define SUMMON_SLOT_PET 0
+#define SUMMON_SLOT_TOTEM 1
+#define MAX_TOTEM_SLOT 5
+#define SUMMON_SLOT_MINIPET 5
+#define SUMMON_SLOT_QUEST 6
+#define MAX_SUMMON_SLOT 7
// delay time next attack to prevent client attack animation problems
#define ATTACK_DISPLAY_DELAY 200
@@ -786,13 +903,16 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
{
public:
typedef std::set<Unit*> AttackerSet;
+ typedef std::set<Unit*> ControlList;
typedef std::pair<uint32, uint8> spellEffectPair;
- typedef std::multimap< spellEffectPair, Aura*> AuraMap;
+ typedef std::multimap<uint32, Aura*> AuraMap;
+ typedef std::list<AuraEffect *> AuraEffectList;
typedef std::list<Aura *> AuraList;
typedef std::list<DiminishingReturn> Diminishing;
- typedef std::set<AuraType> AuraTypeSet;
typedef std::set<uint32> ComboPointHolderSet;
+ typedef std::map<uint8, Aura*> VisibleAuraMap;
+
virtual ~Unit ( );
void AddToWorld();
@@ -806,6 +926,11 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void ApplyDiminishingAura(DiminishingGroup group, bool apply);
void ClearDiminishings() { m_Diminishing.clear(); }
+ //target dependent range checks
+ uint32 GetSpellMaxRangeForTarget(Unit* target,const SpellRangeEntry * rangeEntry);
+ uint32 GetSpellMinRangeForTarget(Unit* target,const SpellRangeEntry * rangeEntry);
+ uint32 GetSpellRadiusForTarget(Unit* target,const SpellRadiusEntry * radiusEntry);
+
virtual void Update( uint32 time );
void setAttackTimer(WeaponAttackType type, uint32 time) { m_attackTimer[type] = time; }
@@ -817,23 +942,19 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SetCanDualWield(bool value) { m_canDualWield = value; }
float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; }
float GetMeleeReach() const { float reach = m_floatValues[UNIT_FIELD_COMBATREACH]; return reach > MIN_MELEE_REACH ? reach : MIN_MELEE_REACH; }
- bool IsWithinCombatRange(Unit *obj, float dist2compare) const;
- bool IsWithinMeleeRange(Unit *obj, float dist = MELEE_RANGE) const;
+ bool IsWithinCombatRange(const Unit *obj, float dist2compare) const;
+ bool IsWithinMeleeRange(const Unit *obj, float dist = MELEE_RANGE) const;
void GetRandomContactPoint( const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax ) const;
uint32 m_extraAttacks;
bool m_canDualWield;
void _addAttacker(Unit *pAttacker) // must be called only from Unit::Attack(Unit*)
{
- AttackerSet::iterator itr = m_attackers.find(pAttacker);
- if(itr == m_attackers.end())
- m_attackers.insert(pAttacker);
+ m_attackers.insert(pAttacker);
}
void _removeAttacker(Unit *pAttacker) // must be called only from Unit::AttackStop()
{
- AttackerSet::iterator itr = m_attackers.find(pAttacker);
- if(itr != m_attackers.end())
- m_attackers.erase(itr);
+ m_attackers.erase(pAttacker);
}
Unit * getAttackerForHelper() // If someone wants to help, who to give them
{
@@ -852,9 +973,10 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
AttackerSet const& getAttackers() const { return m_attackers; }
bool isAttackingPlayer() const;
Unit* getVictim() const { return m_attacking; }
- void CombatStop(bool cast = false);
- void CombatStopWithPets(bool cast = false);
+ void CombatStop(bool includingCast = false);
+ void CombatStopWithPets(bool includingCast = false);
Unit* SelectNearbyTarget(float dist = NOMINAL_MELEE_RANGE) const;
+ bool hasNegativeAuraWithInterruptFlag(uint32 flag);
void addUnitState(uint32 f) { m_state |= f; }
bool hasUnitState(const uint32 f) const { return (m_state & f); }
@@ -887,6 +1009,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SetHealth( uint32 val);
void SetMaxHealth(uint32 val);
int32 ModifyHealth(int32 val);
+ int32 GetHealthGain(int32 dVal);
Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, 3)); }
void setPowerType(Powers power);
@@ -922,8 +1045,14 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
return false;
}
- bool IsPvP() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); }
- void SetPvP(bool state) { if(state) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); else RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); }
+ bool IsPvP() const { return HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); }
+ void SetPvP(bool state)
+ {
+ if(state)
+ SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
+ else
+ RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
+ }
uint32 GetCreatureType() const;
uint32 GetCreatureTypeMask() const
{
@@ -936,6 +1065,9 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
bool IsStandState() const;
void SetStandState(uint8 state);
+ void SetStandFlags(uint8 flags) { SetByteFlag(UNIT_FIELD_BYTES_1, 2,flags); }
+ void RemoveStandFlags(uint8 flags) { RemoveByteFlag(UNIT_FIELD_BYTES_1, 2,flags); }
+
bool IsMounted() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT ); }
uint32 GetMountID() const { return GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID); }
void Mount(uint32 mount);
@@ -943,11 +1075,13 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
void RemoveSpellbyDamageTaken(uint32 damage, uint32 spell);
+ void DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb);
uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage = NULL, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *spellProto = NULL, bool durabilityLoss = true);
void Kill(Unit *pVictim, bool durabilityLoss = true);
+ int32 DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical = false);
- void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellEntry const *procSpell = NULL);
- void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage );
+ void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellEntry const *procSpell = NULL, SpellEntry const * procAura = NULL);
+ void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage , SpellEntry const * procAura = NULL);
void HandleEmoteCommand(uint32 anim_id);
void AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType = BASE_ATTACK, bool extra = false );
@@ -958,6 +1092,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss);
void CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType = BASE_ATTACK);
+ int32 GetIgnoredArmorMultiplier(SpellEntry const *spellInfo, WeaponAttackType attackType);
void DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss);
float MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
@@ -969,16 +1104,26 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
float GetUnitParryChance() const;
float GetUnitBlockChance() const;
float GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const;
+ bool CanUseAttackType( uint8 attacktype ) const
+ {
+ switch(attacktype)
+ {
+ case BASE_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISARMED);
+ case OFF_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS_2,UNIT_FLAG2_DISARM_OFFHAND);
+ case RANGED_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS_2,UNIT_FLAG2_DISARM_RANGED);
+ }
+ return true;
+ }
virtual uint32 GetShieldBlockValue() const =0;
uint32 GetUnitMeleeSkill(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
uint32 GetDefenseSkillValue(Unit const* target = NULL) const;
uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const;
float GetWeaponProcChance() const;
- float GetPPMProcChance(uint32 WeaponSpeed, float PPM) const;
+ float GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellEntry * spellProto) const;
MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const;
- MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const;
+ MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const;
bool isVendor() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR ); }
bool isTrainer() const { return HasFlag( UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TRAINER ); }
@@ -1011,15 +1156,11 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
bool isInCombat() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); }
void CombatStart(Unit* target);
- void SetInCombatState(bool PvP);
+ void SetInCombatState(bool PvP, Unit* enemy = NULL);
void SetInCombatWith(Unit* enemy);
void ClearInCombat();
uint32 GetCombatTimer() const { return m_CombatTimer; }
- bool HasAuraType(AuraType auraType) const;
- bool HasAura(uint32 spellId, uint32 effIndex) const
- { return m_Auras.find(spellEffectPair(spellId, effIndex)) != m_Auras.end(); }
-
bool virtual HasSpell(uint32 /*spellID*/) const { return false; }
bool HasStealthAura() const { return HasAuraType(SPELL_AURA_MOD_STEALTH); }
@@ -1037,17 +1178,20 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
virtual bool IsUnderWater() const;
bool isInAccessiblePlaceFor(Creature const* c) const;
- void SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical = false);
+ void SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool critical, int32 gain);
void SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype);
- uint32 SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell = false, bool useSpellDamage = true);
- void CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
- void CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem= NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
- void CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
- void CastCustomSpell(uint32 spellId, SpellValueMod mod, uint32 value, Unit* Victim = NULL, bool triggered = true, Item *castItem = NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
- void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* Victim = NULL, bool triggered = true, Item *castItem = NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
- void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
- void CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
+ uint32 SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage);
+ void CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
+ void CastSpell(Unit* Victim, SpellEntry const *spellInfo, bool triggered, Item *castItem= NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
+ void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
+ void CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
+ void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* Victim = NULL, bool triggered = true, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
+ void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* Victim = NULL, bool triggered = true, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
+ void CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
void AddAura(uint32 spellId, Unit *target);
+ void SetAuraStack(uint32 spellId, Unit *target, uint32 stack);
+ void HandleAuraEffect(AuraEffect * aureff, bool apply);
+ Aura *AddAuraEffect(const SpellEntry * spellInfo, uint8 effIndex, Unit* caster, int32 * basePoints=NULL, Unit * source=NULL);
bool IsDamageToThreatSpell(SpellEntry const * spellInfo) const;
@@ -1060,14 +1204,20 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false);
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo);
+ void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false);
+
+ void KnockbackFrom(float x, float y, float speedXY, float speedZ);
+ void JumpTo(float speedXY, float speedZ, bool forward = true);
+ void JumpTo(WorldObject *obj, float speedZ);
+
void SendMonsterStop();
void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player = NULL);
+ void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player *player = NULL);
//void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL);
void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end);
- void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime = 0, Player* player = NULL);
+ void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL);
void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL);
-
- virtual void MoveOutOfRange(Player &) { };
+ void SendMovementFlagUpdate();
bool isAlive() const { return (m_deathState == ALIVE); };
bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); };
@@ -1075,14 +1225,17 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
virtual void setDeathState(DeathState s); // overwrited in Creature/Player/Pet
uint64 GetOwnerGUID() const { return GetUInt64Value(UNIT_FIELD_SUMMONEDBY); }
- void SetOwnerGUID(uint64 owner) { SetUInt64Value(UNIT_FIELD_SUMMONEDBY, owner); }
uint64 GetCreatorGUID() const { return GetUInt64Value(UNIT_FIELD_CREATEDBY); }
void SetCreatorGUID(uint64 creator) { SetUInt64Value(UNIT_FIELD_CREATEDBY, creator); }
- uint64 GetPetGUID() const { return GetUInt64Value(UNIT_FIELD_SUMMON); }
+ uint64 GetMinionGUID() const { return GetUInt64Value(UNIT_FIELD_SUMMON); }
+ void SetMinionGUID(uint64 guid) { SetUInt64Value(UNIT_FIELD_SUMMON, guid); }
uint64 GetCharmerGUID() const { return GetUInt64Value(UNIT_FIELD_CHARMEDBY); }
void SetCharmerGUID(uint64 owner) { SetUInt64Value(UNIT_FIELD_CHARMEDBY, owner); }
uint64 GetCharmGUID() const { return GetUInt64Value(UNIT_FIELD_CHARM); }
+ void SetPetGUID(uint64 guid) { m_SummonSlot[SUMMON_SLOT_PET] = guid; }
+ uint64 GetPetGUID() const { return m_SummonSlot[SUMMON_SLOT_PET]; }
+ bool IsControlledByPlayer() const { return m_ControlledByPlayer; }
uint64 GetCharmerOrOwnerGUID() const { return GetCharmerGUID() ? GetCharmerGUID() : GetOwnerGUID(); }
uint64 GetCharmerOrOwnerOrOwnGUID() const
{
@@ -1095,7 +1248,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
Player* GetSpellModOwner() const;
Unit* GetOwner() const;
- Pet* GetPet() const;
+ Guardian *GetGuardianPet() const;
+ Minion *GetFirstMinion() const;
Unit* GetCharmer() const;
Unit* GetCharm() const;
Unit* GetCharmerOrOwner() const { return GetCharmerGUID() ? GetCharmer() : GetOwner(); }
@@ -1108,12 +1262,17 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
}
Player* GetCharmerOrOwnerPlayerOrPlayerItself() const;
- void SetPet(Pet* pet);
- void SetCharm(Unit* pet);
+ void SetMinion(Minion *minion, bool apply);
+ void SetCharm(Unit* target, bool apply);
+ Unit* GetNextRandomRaidMemberOrPet(float radius);
void SetCharmedOrPossessedBy(Unit* charmer, bool possess);
void RemoveCharmedOrPossessedBy(Unit* charmer);
void RestoreFaction();
+ ControlList m_Controlled;
+ Unit* GetFirstControlled() const;
+ void RemoveAllControlled();
+
bool isCharmed() const { return GetCharmerGUID() != 0; }
bool isPossessed() const { return hasUnitState(UNIT_STAT_POSSESSED); }
bool isPossessedByPlayer() const { return hasUnitState(UNIT_STAT_POSSESSED) && IS_PLAYER_GUID(GetCharmerGUID()); }
@@ -1139,35 +1298,27 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
Pet* CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id = 0);
- bool AddAura(Aura *aur);
+ bool AddAura(Aura *aur, bool handleEffects = true);
void RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
- void RemoveAura(uint32 spellId, uint32 effindex, Aura* except = NULL);
- void RemoveSingleAuraFromStackByDispel(uint32 spellId);
- void RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex);
- void RemoveAurasDueToSpell(uint32 spellId, Aura* except = NULL);
- void RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId);
- void RemoveAurasByCasterSpell(uint32 spellId, uint64 casterGUID);
- void SetAurasDurationByCasterSpell(uint32 spellId, uint64 casterGUID, int32 duration);
- Aura* GetAuraByCasterSpell(uint32 spellId, uint64 casterGUID);
+ void RemoveAura(uint32 spellId, uint64 caster = 0 ,AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
+ void RemoveAura(Aura * aur, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
+ void RemoveAurasDueToSpell(uint32 spellId, uint64 caster = NULL ,AuraRemoveMode removeMode= AURA_REMOVE_BY_DEFAULT);
+ void RemoveAuraFromStack(uint32 spellId, uint64 caster = NULL ,AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
+ inline void RemoveAuraFromStack(AuraMap::iterator &iter,AuraRemoveMode removeMode);
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler);
void RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer);
- void RemoveAurasDueToSpellByCancel(uint32 spellId);
- void RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo, Unit * caster);
+ void RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId);
+ void RemoveAurasByType(AuraType auraType, uint64 casterGUID = 0, Aura * except=NULL);
+ void RemoveAurasByTypeWithDispel(AuraType auraType, Spell * spell = NULL);
void RemoveNotOwnSingleTargetAuras();
-
- void RemoveSpellsCausingAura(AuraType auraType);
- void RemoveAuraTypeByCaster(AuraType auraType, uint64 casterGUID);
- void RemoveRankAurasDueToSpell(uint32 spellId);
bool RemoveNoStackAurasDueToAura(Aura *Aur);
- void RemoveAurasWithInterruptFlags(uint32 flags, uint32 except = 0);
- void RemoveAurasWithDispelType( DispelType type );
+ void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except = NULL);
void RemoveMovementImpairingAuras();
-
void RemoveAllAuras();
void RemoveArenaAuras(bool onleave = false);
void RemoveAllAurasOnDeath();
- void DelayAura(uint32 spellId, uint32 effindex, int32 delaytime);
+ void DelayAura(uint32 spellId, uint64 caster, int32 delaytime);
float GetResistanceBuffMods(SpellSchools school, bool positive) const { return GetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school ); }
void SetResistanceBuffMods(SpellSchools school, bool positive, float val) { SetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school,val); }
@@ -1212,12 +1363,15 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
Spell* m_currentSpells[CURRENT_MAX_SPELL];
uint32 m_addDmgOnce;
- uint64 m_TotemSlot[MAX_TOTEM];
+ uint64 m_SummonSlot[MAX_SUMMON_SLOT];
uint64 m_ObjectSlot[4];
uint32 m_detectInvisibilityMask;
uint32 m_invisibilityMask;
+
uint32 m_ShapeShiftFormSpellId;
ShapeshiftForm m_form;
+ bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; }
+
float m_modMeleeHitChance;
float m_modRangedHitChance;
float m_modSpellHitChance;
@@ -1252,9 +1406,9 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const;
void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; }
- bool isInFront(Unit const* target,float distance, float arc = M_PI) const;
+ bool isInFrontInMap(Unit const* target,float distance, float arc = M_PI) const;
void SetInFront(Unit const* target);
- bool isInBack(Unit const* target, float distance, float arc = M_PI) const;
+ bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const;
bool isInLine(Unit const* target, float distance) const;
// Visibility system
@@ -1263,17 +1417,17 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void DestroyForNearbyPlayers();
// common function for visibility checks for player/creatures with detection code
- virtual bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const;
+ virtual bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const = 0;
bool isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const;
bool canDetectInvisibilityOf(Unit const* u) const;
bool canDetectStealthOf(Unit const* u, float distance) const;
+ void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask
// virtual functions for all world objects types
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
// function for low level grid visibility checks in player/creature cases
virtual bool IsVisibleInGridForPlayer(Player const* pl) const = 0;
- bool waterbreath;
AuraList & GetSingleCastAuras() { return m_scAuras; }
AuraList const& GetSingleCastAuras() const { return m_scAuras; }
SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY];
@@ -1290,15 +1444,33 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void removeHatedBy(HostilReference* /*pHostilReference*/ ) { /* nothing to do yet */ }
HostilRefManager& getHostilRefManager() { return m_HostilRefManager; }
- Aura* GetAura(uint32 spellId, uint32 effindex);
+ VisibleAuraMap const *GetVisibleAuras() { return &m_visibleAuras; }
+ Aura * GetVisibleAura(uint8 slot)
+ {
+ VisibleAuraMap::iterator itr = m_visibleAuras.find(slot);
+ if(itr != m_visibleAuras.end())
+ return itr->second;
+ return 0;
+ }
+ void SetVisibleAura(uint8 slot, Aura * aur){ m_visibleAuras[slot]=aur; }
+ void RemoveVisibleAura(uint8 slot){ m_visibleAuras.erase(slot); }
+
AuraMap & GetAuras() { return m_Auras; }
AuraMap const& GetAuras() const { return m_Auras; }
- AuraList const& GetAurasByType(AuraType type) const { return m_modAuras[type]; }
- void ApplyAuraProcTriggerDamage(Aura* aura, bool apply);
+ AuraEffectList const& GetAurasByType(AuraType type) const { return m_modAuras[type]; }
+
+ AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, uint64 casterGUID = 0) const;
+ Aura * GetAura(uint32 spellId, uint64 casterGUID = 0) const;
+ AuraEffect* GetAura(AuraType type, uint32 family, uint32 familyFlag1 , uint32 familyFlag2=0, uint32 familyFlag3=0, uint64 casterGUID=0);
+ bool HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster = 0) const;
+ bool HasAura(uint32 spellId, uint64 caster = 0) const;
+ bool HasAura(Aura * aur) const;
+ bool HasAuraType(AuraType auraType) const;
+ bool HasAuraTypeWithMiscvalue(AuraType auratype, uint32 miscvalue) const;
int32 GetTotalAuraModifier(AuraType auratype) const;
float GetTotalAuraMultiplier(AuraType auratype) const;
- int32 GetMaxPositiveAuraModifier(AuraType auratype) const;
+ int32 GetMaxPositiveAuraModifier(AuraType auratype);
int32 GetMaxNegativeAuraModifier(AuraType auratype) const;
int32 GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const;
@@ -1311,7 +1483,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
int32 GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const;
int32 GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const;
- Aura* GetDummyAura(uint32 spell_id) const;
+ AuraEffect* GetDummyAura(uint32 spell_id) const;
uint32 GetInterruptMask() const { return m_interruptMask; }
void AddInterruptMask(uint32 mask) { m_interruptMask |= mask; }
void UpdateInterruptMask();
@@ -1322,30 +1494,37 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SetNativeDisplayId(uint32 modelId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, modelId); }
void setTransForm(uint32 spellid) { m_transform = spellid;}
uint32 getTransForm() const { return m_transform;}
+
+ DynamicObject* GetDynObject(uint32 spellId, uint32 effIndex);
+ DynamicObject* GetDynObject(uint32 spellId);
void AddDynObject(DynamicObject* dynObj);
void RemoveDynObject(uint32 spellid);
void RemoveDynObjectWithGUID(uint64 guid) { m_dynObjGUIDs.remove(guid); }
void RemoveAllDynObjects();
+
+ GameObject* GetGameObject(uint32 spellId) const;
void AddGameObject(GameObject* gameObj);
void RemoveGameObject(GameObject* gameObj, bool del);
void RemoveGameObject(uint32 spellid, bool del);
void RemoveAllGameObjects();
- DynamicObject *GetDynObject(uint32 spellId, uint32 effIndex);
- DynamicObject *GetDynObject(uint32 spellId);
+
uint32 CalculateDamage(WeaponAttackType attType, bool normalized);
float GetAPMultiplier(WeaponAttackType attType, bool normalized);
void ModifyAuraState(AuraState flag, bool apply);
- bool HasAuraState(AuraState flag) const { return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); }
+ bool HasAuraState(AuraState flag, SpellEntry const *spellProto = NULL, Unit * Caster = NULL) const ;
void UnsummonAllTotems();
+ Unit* SelectMagnetTarget(Unit *victim, SpellEntry const *spellInfo = NULL);
int32 SpellBaseDamageBonus(SpellSchoolMask schoolMask);
int32 SpellBaseHealingBonus(SpellSchoolMask schoolMask);
int32 SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim);
int32 SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim);
- uint32 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype);
- uint32 SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim);
+ uint32 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype, uint32 stack = 1);
+ uint32 SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1);
bool isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType = BASE_ATTACK);
+ bool isBlockCritical();
bool isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK);
- uint32 SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim);
+ uint32 SpellCriticalDamageBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim);
+ uint32 SpellCriticalHealingBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim);
void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; }
bool IsUnderLastManaUseEffect() const;
@@ -1357,19 +1536,21 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply);
void ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply);
- virtual bool IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges = false);
+ virtual bool IsImmunedToSpell(SpellEntry const* spellInfo);
// redefined in Creature
- bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask, bool useCharges = false);
- virtual bool IsImmunedToSpellEffect(uint32 effect, uint32 mechanic) const;
+ bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask);
+ bool IsImmunedToDamage(SpellEntry const* spellInfo);
+ virtual bool IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const;
// redefined in Creature
- uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage);
- void CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist);
+ uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType=MAX_ATTACK);
+ void CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, SpellEntry const *spellInfo = NULL);
void UpdateSpeed(UnitMoveType mtype, bool forced);
float GetSpeed( UnitMoveType mtype ) const;
float GetSpeedRate( UnitMoveType mtype ) const { return m_speed_rate[mtype]; }
void SetSpeed(UnitMoveType mtype, float rate, bool forced = false);
+ float m_TempSpeed;
void SetHover(bool on);
bool isHover() const { return HasAuraType(SPELL_AURA_HOVER); }
@@ -1378,7 +1559,9 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void _ApplyAllAuraMods();
int32 CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_index, int32 basePoints, Unit const* target);
- int32 CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_index, Unit const* target);
+ int32 CalcSpellDuration(SpellEntry const* spellProto);
+ int32 ModSpellDuration(SpellEntry const* spellProto, Unit const* target, int32 duration, bool positive);
+ void ModSpellCastTime(SpellEntry const* spellProto, int32 & castTime, Spell const * spell=NULL);
float CalculateLevelPenalty(SpellEntry const* spellProto) const;
void addFollower(FollowerReference* pRef) { m_FollowingRefManager.insertFirst(pRef); }
@@ -1403,17 +1586,13 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SetUnitMovementFlags(uint32 f) { m_unit_movement_flags = f; }
void SetControlled(bool apply, UnitState state);
- void SetFeared(bool apply/*, uint64 casterGUID = 0, uint32 spellID = 0*/);
- void SetConfused(bool apply/*, uint64 casterGUID = 0, uint32 spellID = 0*/);
- void SetStunned(bool apply);
- void SetRooted(bool apply);
void AddComboPointHolder(uint32 lowguid) { m_ComboPointHolders.insert(lowguid); }
void RemoveComboPointHolder(uint32 lowguid) { m_ComboPointHolders.erase(lowguid); }
void ClearComboPointHolders();
///----------Pet responses methods-----------------
- void SendPetCastFail(uint32 spellid, uint8 msg);
+ void SendPetCastFail(uint32 spellid, SpellCastResult msg);
void SendPetActionFeedback (uint8 msg);
void SendPetTalk (uint32 pettalk);
void SendPetSpellCooldown (uint32 spellid, time_t cooltime);
@@ -1431,6 +1610,19 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
// group updates
void UpdateAuraForGroup(uint8 slot);
+ // proc trigger system
+ bool CanProc(){return !m_procDeep;}
+ void SetCantProc( bool apply)
+ {
+ if(apply)
+ ++m_procDeep;
+ else
+ {
+ assert(m_procDeep);
+ --m_procDeep;
+ }
+ }
+
// pet auras
typedef std::set<PetAura const*> PetAuraSet;
PetAuraSet m_petAuras;
@@ -1451,14 +1643,39 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
Unit *GetMisdirectionTarget() { return m_misdirectionTargetGUID ? GetUnit(*this, m_misdirectionTargetGUID) : NULL; }
bool IsAIEnabled, NeedChangeAI;
+ MovementInfo m_movementInfo;
+ Vehicle *m_Vehicle;
+ float GetTransOffsetX() const { return m_movementInfo.t_x; }
+ float GetTransOffsetY() const { return m_movementInfo.t_y; }
+ float GetTransOffsetZ() const { return m_movementInfo.t_z; }
+ float GetTransOffsetO() const { return m_movementInfo.t_o; }
+ uint32 GetTransTime() const { return m_movementInfo.t_time; }
+ int8 GetTransSeat() const { return m_movementInfo.t_seat; }
+
+ bool m_ControlledByPlayer;
+
+ void EnterVehicle(Vehicle *vehicle, int8 seatId = -1);
+ void ExitVehicle();
+ void ChangeSeat(int8 seatId, bool next = true);
+
+ // Transports
+ Transport * GetTransport() const { return m_transport; }
+ void SetTransport(Transport * t) { m_transport = t; }
+
+ void BuildMovementPacket(ByteBuffer *data) const;
protected:
explicit Unit ();
UnitAI *i_AI, *i_disabledAI;
+ // Transports
+ Transport * m_transport;
+
void _UpdateSpells(uint32 time);
+ void _DeleteAuras();
void _UpdateAutoRepeatSpell();
+
bool m_AutoRepeatFirstCast;
uint32 m_attackTimer[MAX_ATTACK];
@@ -1471,25 +1688,29 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
DeathState m_deathState;
AuraMap m_Auras;
+ uint32 m_removedAurasCount;
+ int32 m_procDeep;
typedef std::list<uint64> DynObjectGUIDs;
DynObjectGUIDs m_dynObjGUIDs;
- std::list<GameObject*> m_gameObj;
+ typedef std::list<GameObject*> GameObjectList;
+ GameObjectList m_gameObj;
bool m_isSorted;
uint32 m_transform;
- uint32 m_removedAuras;
- AuraList m_modAuras[TOTAL_AURAS];
+ AuraEffectList m_modAuras[TOTAL_AURAS];
AuraList m_scAuras; // casted singlecast auras
AuraList m_interruptableAuras;
AuraList m_ccAuras;
+ AuraList m_removedAuras;
uint32 m_interruptMask;
float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END];
float m_weaponDamage[MAX_ATTACK][2];
bool m_canModifyStats;
//std::list< spellEffectPair > AuraSpells[TOTAL_AURAS]; // TODO: use this if ok for mem
+ VisibleAuraMap m_visibleAuras;
float m_speed_rate[MAX_MOVE_TYPE];
@@ -1502,6 +1723,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
uint32 m_unit_movement_flags;
uint32 m_reactiveTimer[MAX_REACTIVE];
+ uint32 m_regenTimer;
ThreatManager m_ThreatManager;
@@ -1509,12 +1731,20 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SendAttackStop(Unit* victim); // only from AttackStop(Unit*)
//void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*)
- bool IsTriggeredAtSpellProcEvent( Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent );
- bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura* triggredByAura, SpellEntry const *procSpell, uint32 cooldown);
- bool HandleMeandingAuraProc(Aura* triggeredByAura);
+ bool IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura* aura, SpellEntry const * procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const *& spellProcEvent );
+ bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleObsModEnergyAuraProc( Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 cooldown);
+ bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura);
+ bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura);
+
+ void SetFeared(bool apply);
+ void SetConfused(bool apply);
+ void SetStunned(bool apply);
+ void SetRooted(bool apply);
uint32 m_state; // Even derived shouldn't modify
uint32 m_CombatTimer;
@@ -1534,8 +1764,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
uint32 m_reducedThreatPercent;
uint64 m_misdirectionTargetGUID;
-
- uint32 m_procDeep;
};
namespace Trinity
diff --git a/src/game/UnitAI.cpp b/src/game/UnitAI.cpp
new file mode 100644
index 00000000000..c159861697c
--- /dev/null
+++ b/src/game/UnitAI.cpp
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "UnitAI.h"
+#include "Player.h"
+#include "Creature.h"
+#include "SpellAuras.h"
+#include "SpellMgr.h"
+#include "CreatureAIImpl.h"
+
+void UnitAI::AttackStart(Unit *victim)
+{
+ if(victim && me->Attack(victim, true))
+ me->GetMotionMaster()->MoveChase(victim);
+}
+
+void UnitAI::AttackStartCaster(Unit *victim, float dist)
+{
+ if(victim && me->Attack(victim, false))
+ me->GetMotionMaster()->MoveChase(victim, dist);
+}
+
+void UnitAI::DoMeleeAttackIfReady()
+{
+ if(me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ //Make sure our attack is ready and we aren't currently casting before checking distance
+ if (me->isAttackReady())
+ {
+ //If we are within range melee the target
+ if (me->IsWithinMeleeRange(me->getVictim()))
+ {
+ me->AttackerStateUpdate(me->getVictim());
+ me->resetAttackTimer();
+ }
+ }
+ if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
+ {
+ //If we are within range melee the target
+ if (me->IsWithinMeleeRange(me->getVictim()))
+ {
+ me->AttackerStateUpdate(me->getVictim(), OFF_ATTACK);
+ me->resetAttackTimer(OFF_ATTACK);
+ }
+ }
+}
+
+bool UnitAI::DoSpellAttackIfReady(uint32 spell)
+{
+ if(me->hasUnitState(UNIT_STAT_CASTING))
+ return true;
+
+ if(me->isAttackReady())
+ {
+ if(me->IsWithinCombatRange(me->getVictim(), GetSpellMaxRange(spell, false)))
+ {
+ me->CastSpell(me->getVictim(), spell, false);
+ me->resetAttackTimer();
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
+inline bool SelectTargetHelper(const Unit * me, const Unit * target, const bool &playerOnly, const float &dist, const int32 &aura)
+{
+ if(playerOnly && target->GetTypeId() != TYPEID_PLAYER)
+ return false;
+
+ if(dist && !me->IsWithinCombatRange(target, dist))
+ return false;
+
+ if(aura)
+ {
+ if(aura > 0)
+ {
+ if(!target->HasAura(aura))
+ return false;
+ }
+ else
+ {
+ if(target->HasAura(aura))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+struct TargetDistanceOrder : public std::binary_function<const Unit *, const Unit *, bool>
+{
+ const Unit * me;
+ TargetDistanceOrder(const Unit* Target) : me(Target) {};
+ // functor for operator ">"
+ bool operator()(const Unit * _Left, const Unit * _Right) const
+ {
+ return (me->GetDistanceSq(_Left) < me->GetDistanceSq(_Right));
+ }
+};
+
+Unit* UnitAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura)
+{
+ if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
+ {
+ std::list<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList();
+ if(position >= m_threatlist.size())
+ return NULL;
+
+ std::list<Unit*> targetList;
+ for(std::list<HostilReference*>::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr)
+ if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura))
+ targetList.push_back((*itr)->getTarget());
+
+ if(position >= targetList.size())
+ return NULL;
+
+ targetList.sort(TargetDistanceOrder(me));
+
+ if(targetType == SELECT_TARGET_NEAREST)
+ {
+ std::list<Unit*>::iterator i = targetList.begin();
+ advance(i, position);
+ return *i;
+ }
+ else
+ {
+ std::list<Unit*>::reverse_iterator i = targetList.rbegin();
+ advance(i, position);
+ return *i;
+ }
+ }
+ else
+ {
+ std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList();
+ std::list<HostilReference*>::iterator i;
+ while(position < m_threatlist.size())
+ {
+ if(targetType == SELECT_TARGET_BOTTOMAGGRO)
+ {
+ i = m_threatlist.end();
+ advance(i, - (int32)position - 1);
+ }
+ else
+ {
+ i = m_threatlist.begin();
+ if(targetType == SELECT_TARGET_TOPAGGRO)
+ advance(i, position);
+ else // random
+ advance(i, position + rand()%(m_threatlist.size() - position));
+ }
+
+ if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura))
+ return (*i)->getTarget();
+ else
+ m_threatlist.erase(i);
+ }
+ }
+
+ return NULL;
+}
+
+void UnitAI::SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura)
+{
+ if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
+ {
+ std::list<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList();
+ if(m_threatlist.empty())
+ return;
+
+ for(std::list<HostilReference*>::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr)
+ if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura))
+ targetList.push_back((*itr)->getTarget());
+
+ targetList.sort(TargetDistanceOrder(me));
+ targetList.resize(num);
+ if(targetType == SELECT_TARGET_FARTHEST)
+ targetList.reverse();
+ }
+ else
+ {
+ std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList();
+ std::list<HostilReference*>::iterator i;
+ while(!m_threatlist.empty() && num)
+ {
+ if(targetType == SELECT_TARGET_BOTTOMAGGRO)
+ {
+ i = m_threatlist.end();
+ --i;
+ }
+ else
+ {
+ i = m_threatlist.begin();
+ if(targetType == SELECT_TARGET_RANDOM)
+ advance(i, rand()%m_threatlist.size());
+ }
+
+ if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura))
+ {
+ targetList.push_back((*i)->getTarget());
+ --num;
+ }
+ m_threatlist.erase(i);
+ }
+ }
+}
+
+void UnitAI::DoCast(uint32 spellId)
+{
+ Unit *target = NULL;
+ //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target);
+ switch(AISpellInfo[spellId].target)
+ {
+ default:
+ case AITARGET_SELF: target = me; break;
+ case AITARGET_VICTIM: target = me->getVictim(); break;
+ case AITARGET_ENEMY:
+ {
+ const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId);
+ bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY;
+ float range = GetSpellMaxRange(spellInfo, false);
+ target = SelectTarget(SELECT_TARGET_RANDOM, 0, GetSpellMaxRange(spellInfo, false), playerOnly);
+ break;
+ }
+ case AITARGET_ALLY: target = me; break;
+ case AITARGET_BUFF: target = me; break;
+ case AITARGET_DEBUFF:
+ {
+ const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId);
+ bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY;
+ float range = GetSpellMaxRange(spellInfo, false);
+ if(!(spellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE)
+ && !(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM)
+ && SelectTargetHelper(me, me->getVictim(), playerOnly, range, -(int32)spellId))
+ target = me->getVictim();
+ else
+ target = SelectTarget(SELECT_TARGET_RANDOM, 0, range, playerOnly, -(int32)spellId);
+ break;
+ }
+ }
+
+ if(target)
+ me->CastSpell(target, spellId, false);
+}
+
+void UnitAI::DoCast(Unit* victim, uint32 spellId, bool triggered)
+{
+ if(!victim || me->hasUnitState(UNIT_STAT_CASTING) && !triggered)
+ return;
+
+ me->CastSpell(victim, spellId, triggered);
+}
+
+void UnitAI::DoCastAOE(uint32 spellId, bool triggered)
+{
+ if(!triggered && me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ me->CastSpell((Unit*)NULL, spellId, triggered);
+}
+
+#define UPDATE_TARGET(a) {if(AIInfo->target<a) AIInfo->target=a;}
+
+void UnitAI::FillAISpellInfo()
+{
+ AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()];
+
+ AISpellInfoType *AIInfo = AISpellInfo;
+ const SpellEntry * spellInfo;
+
+ for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo)
+ {
+ spellInfo = GetSpellStore()->LookupEntry(i);
+ if(!spellInfo)
+ continue;
+
+ if(spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
+ AIInfo->condition = AICOND_DIE;
+ else if(IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1)
+ AIInfo->condition = AICOND_AGGRO;
+ else
+ AIInfo->condition = AICOND_COMBAT;
+
+ if(AIInfo->cooldown < spellInfo->RecoveryTime)
+ AIInfo->cooldown = spellInfo->RecoveryTime;
+
+ if(!GetSpellMaxRange(spellInfo, false))
+ UPDATE_TARGET(AITARGET_SELF)
+ else
+ {
+ for(uint32 j = 0; j < 3; ++j)
+ {
+ uint32 targetType = spellInfo->EffectImplicitTargetA[j];
+
+ if(targetType == TARGET_UNIT_TARGET_ENEMY
+ || targetType == TARGET_DST_TARGET_ENEMY)
+ UPDATE_TARGET(AITARGET_VICTIM)
+ else if(targetType == TARGET_UNIT_AREA_ENEMY_DST)
+ UPDATE_TARGET(AITARGET_ENEMY)
+
+ if(spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA)
+ {
+ if(targetType == TARGET_UNIT_TARGET_ENEMY)
+ UPDATE_TARGET(AITARGET_DEBUFF)
+ else if(IsPositiveSpell(i))
+ UPDATE_TARGET(AITARGET_BUFF)
+ }
+ }
+ }
+ }
+}
+
+//Enable PlayerAI when charmed
+void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; }
+
+void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
+{
+ Creature *charmer = (Creature*)me->GetCharmer();
+
+ //kill self if charm aura has infinite duration
+ if(charmer->IsInEvadeMode())
+ {
+ Unit::AuraEffectList const& auras = me->GetAurasByType(SPELL_AURA_MOD_CHARM);
+ for(Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
+ if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetParentAura()->IsPermanent())
+ {
+ charmer->Kill(me);
+ return;
+ }
+ }
+
+ if(!charmer->isInCombat())
+ me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+
+ Unit *target = me->getVictim();
+ if(!target || !charmer->canAttack(target))
+ AttackStart(charmer->SelectNearestTarget());
+}
diff --git a/src/game/UnitAI.h b/src/game/UnitAI.h
new file mode 100644
index 00000000000..9530405ed4d
--- /dev/null
+++ b/src/game/UnitAI.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITY_UNITAI_H
+#define TRINITY_UNITAI_H
+
+#include "Platform/Define.h"
+#include <list>
+
+class Unit;
+class Player;
+struct AISpellInfoType;
+
+//Selection method used by SelectTarget
+enum SelectAggroTarget
+{
+ SELECT_TARGET_RANDOM = 0, //Just selects a random target
+ SELECT_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom
+ SELECT_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top
+ SELECT_TARGET_NEAREST,
+ SELECT_TARGET_FARTHEST,
+};
+
+class TRINITY_DLL_SPEC UnitAI
+{
+ protected:
+ Unit * const me;
+ public:
+ explicit UnitAI(Unit *u) : me(u) {}
+ virtual void AttackStart(Unit *);
+ virtual void UpdateAI(const uint32 diff) = 0;
+
+ virtual void InitializeAI() { Reset(); }
+
+ virtual void Reset() {};
+
+ // Called when unit is charmed
+ virtual void OnCharmed(bool apply) = 0;
+
+ // Pass parameters between AI
+ virtual void DoAction(const int32 param = 0) {}
+ virtual void SetGUID(const uint64 &guid, const int32 param = 0) {}
+
+ Unit* SelectTarget(SelectAggroTarget target, uint32 position = 0, float dist = 0, bool playerOnly = false, int32 aura = 0);
+ void SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget target, float dist = 0, bool playerOnly = false, int32 aura = 0);
+
+ void AttackStartCaster(Unit *victim, float dist);
+
+ void DoCast(uint32 spellId);
+ void DoCast(Unit* victim, uint32 spellId, bool triggered = false);
+ void DoCastAOE(uint32 spellId, bool triggered = false);
+
+ void DoMeleeAttackIfReady();
+ bool DoSpellAttackIfReady(uint32 spell);
+
+ static AISpellInfoType *AISpellInfo;
+ static void FillAISpellInfo();
+};
+
+class TRINITY_DLL_SPEC PlayerAI : public UnitAI
+{
+ protected:
+ Player* const me;
+ public:
+ explicit PlayerAI(Player *p) : UnitAI((Unit*)p), me(p) {}
+
+ void OnCharmed(bool apply);
+};
+
+class TRINITY_DLL_SPEC SimpleCharmedAI : public PlayerAI
+{
+ public:
+ void UpdateAI(const uint32 diff);
+};
+
+#endif
diff --git a/src/game/UnitEvents.h b/src/game/UnitEvents.h
index 4bc362893a3..67f8d01f0d6 100644
--- a/src/game/UnitEvents.h
+++ b/src/game/UnitEvents.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/UpdateData.cpp b/src/game/UpdateData.cpp
index 91ef84bb372..b9c1ec04c63 100644
--- a/src/game/UpdateData.cpp
+++ b/src/game/UpdateData.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -103,12 +103,12 @@ void UpdateData::Compress(void* dst, uint32 *dst_size, void* src, int src_size)
*dst_size = c_stream.total_out;
}
-bool UpdateData::BuildPacket(WorldPacket *packet, bool hasTransport)
+bool UpdateData::BuildPacket(WorldPacket *packet, bool /*hasTransport*/)
{
ByteBuffer buf(m_data.size() + 10 + m_outOfRangeGUIDs.size()*8);
buf << (uint32) (!m_outOfRangeGUIDs.empty() ? m_blockCount + 1 : m_blockCount);
- buf << (uint8) (hasTransport ? 1 : 0);
+ //buf << (uint8) (hasTransport ? 1 : 0);
if(!m_outOfRangeGUIDs.empty())
{
@@ -116,7 +116,7 @@ bool UpdateData::BuildPacket(WorldPacket *packet, bool hasTransport)
buf << (uint32) m_outOfRangeGUIDs.size();
for(std::set<uint64>::const_iterator i = m_outOfRangeGUIDs.begin();
- i != m_outOfRangeGUIDs.end(); i++)
+ i != m_outOfRangeGUIDs.end(); ++i)
{
//buf.appendPackGUID(*i);
buf << (uint8)0xFF;
diff --git a/src/game/UpdateData.h b/src/game/UpdateData.h
index 256c572bb1d..71a9258b90b 100644
--- a/src/game/UpdateData.h
+++ b/src/game/UpdateData.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,11 +38,12 @@ enum OBJECT_UPDATE_FLAGS
UPDATEFLAG_NONE = 0x00,
UPDATEFLAG_SELF = 0x01,
UPDATEFLAG_TRANSPORT = 0x02,
- UPDATEFLAG_FULLGUID = 0x04,
+ UPDATEFLAG_HAS_TARGET = 0x04,
UPDATEFLAG_LOWGUID = 0x08,
UPDATEFLAG_HIGHGUID = 0x10,
UPDATEFLAG_LIVING = 0x20,
- UPDATEFLAG_HASPOSITION = 0x40
+ UPDATEFLAG_HAS_POSITION = 0x40,
+ UPDATEFLAG_VEHICLE = 0x80
};
class UpdateData
diff --git a/src/game/UpdateFields.h b/src/game/UpdateFields.h
index c8e70fc2198..97fcbeb05d6 100644
--- a/src/game/UpdateFields.h
+++ b/src/game/UpdateFields.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
#ifndef _UPDATEFIELDS_AUTO_H
#define _UPDATEFIELDS_AUTO_H
-// Auto generated for version 2, 4, 3, 8606
+// Auto generated for version 3, 0, 3, 9183
enum EObjectFields
{
@@ -43,13 +43,37 @@ enum EItemFields
ITEM_FIELD_DURATION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: OWNER_ONLY, UNK2
ITEM_FIELD_SPELL_CHARGES = OBJECT_END + 0x000A, // Size: 5, Type: INT, Flags: OWNER_ONLY, UNK2
ITEM_FIELD_FLAGS = OBJECT_END + 0x000F, // Size: 1, Type: INT, Flags: PUBLIC
- ITEM_FIELD_ENCHANTMENT = OBJECT_END + 0x0010, // Size: 33, Type: INT, Flags: PUBLIC
- ITEM_FIELD_PROPERTY_SEED = OBJECT_END + 0x0031, // Size: 1, Type: INT, Flags: PUBLIC
- ITEM_FIELD_RANDOM_PROPERTIES_ID = OBJECT_END + 0x0032, // Size: 1, Type: INT, Flags: PUBLIC
- ITEM_FIELD_ITEM_TEXT_ID = OBJECT_END + 0x0033, // Size: 1, Type: INT, Flags: OWNER_ONLY
- ITEM_FIELD_DURABILITY = OBJECT_END + 0x0034, // Size: 1, Type: INT, Flags: OWNER_ONLY, UNK2
- ITEM_FIELD_MAXDURABILITY = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: OWNER_ONLY, UNK2
- ITEM_END = OBJECT_END + 0x0036,
+ ITEM_FIELD_ENCHANTMENT_1_1 = OBJECT_END + 0x0010, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_1_3 = OBJECT_END + 0x0012, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_2_1 = OBJECT_END + 0x0013, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_2_3 = OBJECT_END + 0x0015, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_3_1 = OBJECT_END + 0x0016, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_3_3 = OBJECT_END + 0x0018, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_4_1 = OBJECT_END + 0x0019, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_4_3 = OBJECT_END + 0x001B, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_5_1 = OBJECT_END + 0x001C, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_5_3 = OBJECT_END + 0x001E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_6_1 = OBJECT_END + 0x001F, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_6_3 = OBJECT_END + 0x0021, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_7_1 = OBJECT_END + 0x0022, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_7_3 = OBJECT_END + 0x0024, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_8_1 = OBJECT_END + 0x0025, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_8_3 = OBJECT_END + 0x0027, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_9_1 = OBJECT_END + 0x0028, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_9_3 = OBJECT_END + 0x002A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_10_1 = OBJECT_END + 0x002B, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_10_3 = OBJECT_END + 0x002D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_11_1 = OBJECT_END + 0x002E, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_11_3 = OBJECT_END + 0x0030, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_12_1 = OBJECT_END + 0x0031, // Size: 2, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ENCHANTMENT_12_3 = OBJECT_END + 0x0033, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ ITEM_FIELD_PROPERTY_SEED = OBJECT_END + 0x0034, // Size: 1, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_RANDOM_PROPERTIES_ID = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC
+ ITEM_FIELD_ITEM_TEXT_ID = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: OWNER_ONLY
+ ITEM_FIELD_DURABILITY = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: OWNER_ONLY, UNK2
+ ITEM_FIELD_MAXDURABILITY = OBJECT_END + 0x0038, // Size: 1, Type: INT, Flags: OWNER_ONLY, UNK2
+ ITEM_FIELD_PAD = OBJECT_END + 0x0039, // Size: 1, Type: INT, Flags: NONE
+ ITEM_END = OBJECT_END + 0x003A,
};
enum EContainerFields
@@ -64,93 +88,94 @@ enum EUnitFields
{
UNIT_FIELD_CHARM = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
UNIT_FIELD_SUMMON = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC
- UNIT_FIELD_CHARMEDBY = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PUBLIC
- UNIT_FIELD_SUMMONEDBY = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC
- UNIT_FIELD_CREATEDBY = OBJECT_END + 0x0008, // Size: 2, Type: LONG, Flags: PUBLIC
- UNIT_FIELD_TARGET = OBJECT_END + 0x000A, // Size: 2, Type: LONG, Flags: PUBLIC
- UNIT_FIELD_PERSUADED = OBJECT_END + 0x000C, // Size: 2, Type: LONG, Flags: PUBLIC
+ UNIT_FIELD_CRITTER = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PRIVATE
+ UNIT_FIELD_CHARMEDBY = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC
+ UNIT_FIELD_SUMMONEDBY = OBJECT_END + 0x0008, // Size: 2, Type: LONG, Flags: PUBLIC
+ UNIT_FIELD_CREATEDBY = OBJECT_END + 0x000A, // Size: 2, Type: LONG, Flags: PUBLIC
+ UNIT_FIELD_TARGET = OBJECT_END + 0x000C, // Size: 2, Type: LONG, Flags: PUBLIC
UNIT_FIELD_CHANNEL_OBJECT = OBJECT_END + 0x000E, // Size: 2, Type: LONG, Flags: PUBLIC
- UNIT_FIELD_HEALTH = OBJECT_END + 0x0010, // Size: 1, Type: INT, Flags: DYNAMIC
- UNIT_FIELD_POWER1 = OBJECT_END + 0x0011, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_POWER2 = OBJECT_END + 0x0012, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_POWER3 = OBJECT_END + 0x0013, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_POWER4 = OBJECT_END + 0x0014, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_POWER5 = OBJECT_END + 0x0015, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_MAXHEALTH = OBJECT_END + 0x0016, // Size: 1, Type: INT, Flags: DYNAMIC
- UNIT_FIELD_MAXPOWER1 = OBJECT_END + 0x0017, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_MAXPOWER2 = OBJECT_END + 0x0018, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_MAXPOWER3 = OBJECT_END + 0x0019, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_MAXPOWER4 = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_MAXPOWER5 = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_LEVEL = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_FACTIONTEMPLATE = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_BYTES_0 = OBJECT_END + 0x001E, // Size: 1, Type: BYTES, Flags: PUBLIC
- UNIT_VIRTUAL_ITEM_SLOT_DISPLAY = OBJECT_END + 0x001F, // Size: 3, Type: INT, Flags: PUBLIC
- UNIT_VIRTUAL_ITEM_INFO = OBJECT_END + 0x0022, // Size: 6, Type: BYTES, Flags: PUBLIC
- UNIT_FIELD_FLAGS = OBJECT_END + 0x0028, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_FLAGS_2 = OBJECT_END + 0x0029, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_AURA = OBJECT_END + 0x002A, // Size: 56, Type: INT, Flags: PUBLIC
- UNIT_FIELD_AURAFLAGS = OBJECT_END + 0x0062, // Size: 14, Type: BYTES, Flags: PUBLIC
- UNIT_FIELD_AURALEVELS = OBJECT_END + 0x0070, // Size: 14, Type: BYTES, Flags: PUBLIC
- UNIT_FIELD_AURAAPPLICATIONS = OBJECT_END + 0x007E, // Size: 14, Type: BYTES, Flags: PUBLIC
- UNIT_FIELD_AURASTATE = OBJECT_END + 0x008C, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_BASEATTACKTIME = OBJECT_END + 0x008D, // Size: 2, Type: INT, Flags: PUBLIC
- UNIT_FIELD_RANGEDATTACKTIME = OBJECT_END + 0x008F, // Size: 1, Type: INT, Flags: PRIVATE
- UNIT_FIELD_BOUNDINGRADIUS = OBJECT_END + 0x0090, // Size: 1, Type: FLOAT, Flags: PUBLIC
- UNIT_FIELD_COMBATREACH = OBJECT_END + 0x0091, // Size: 1, Type: FLOAT, Flags: PUBLIC
- UNIT_FIELD_DISPLAYID = OBJECT_END + 0x0092, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_NATIVEDISPLAYID = OBJECT_END + 0x0093, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_MOUNTDISPLAYID = OBJECT_END + 0x0094, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_MINDAMAGE = OBJECT_END + 0x0095, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY, UNK3
- UNIT_FIELD_MAXDAMAGE = OBJECT_END + 0x0096, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY, UNK3
- UNIT_FIELD_MINOFFHANDDAMAGE = OBJECT_END + 0x0097, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY, UNK3
- UNIT_FIELD_MAXOFFHANDDAMAGE = OBJECT_END + 0x0098, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY, UNK3
- UNIT_FIELD_BYTES_1 = OBJECT_END + 0x0099, // Size: 1, Type: BYTES, Flags: PUBLIC
- UNIT_FIELD_PETNUMBER = OBJECT_END + 0x009A, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_PET_NAME_TIMESTAMP = OBJECT_END + 0x009B, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_PETEXPERIENCE = OBJECT_END + 0x009C, // Size: 1, Type: INT, Flags: OWNER_ONLY
- UNIT_FIELD_PETNEXTLEVELEXP = OBJECT_END + 0x009D, // Size: 1, Type: INT, Flags: OWNER_ONLY
- UNIT_DYNAMIC_FLAGS = OBJECT_END + 0x009E, // Size: 1, Type: INT, Flags: DYNAMIC
- UNIT_CHANNEL_SPELL = OBJECT_END + 0x009F, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_MOD_CAST_SPEED = OBJECT_END + 0x00A0, // Size: 1, Type: FLOAT, Flags: PUBLIC
- UNIT_CREATED_BY_SPELL = OBJECT_END + 0x00A1, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_NPC_FLAGS = OBJECT_END + 0x00A2, // Size: 1, Type: INT, Flags: DYNAMIC
- UNIT_NPC_EMOTESTATE = OBJECT_END + 0x00A3, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_TRAINING_POINTS = OBJECT_END + 0x00A4, // Size: 1, Type: TWO_SHORT, Flags: OWNER_ONLY
- UNIT_FIELD_STAT0 = OBJECT_END + 0x00A5, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_STAT1 = OBJECT_END + 0x00A6, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_STAT2 = OBJECT_END + 0x00A7, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_STAT3 = OBJECT_END + 0x00A8, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_STAT4 = OBJECT_END + 0x00A9, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_POSSTAT0 = OBJECT_END + 0x00AA, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_POSSTAT1 = OBJECT_END + 0x00AB, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_POSSTAT2 = OBJECT_END + 0x00AC, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_POSSTAT3 = OBJECT_END + 0x00AD, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_POSSTAT4 = OBJECT_END + 0x00AE, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_NEGSTAT0 = OBJECT_END + 0x00AF, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_NEGSTAT1 = OBJECT_END + 0x00B0, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_NEGSTAT2 = OBJECT_END + 0x00B1, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_NEGSTAT3 = OBJECT_END + 0x00B2, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_NEGSTAT4 = OBJECT_END + 0x00B3, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_RESISTANCES = OBJECT_END + 0x00B4, // Size: 7, Type: INT, Flags: PRIVATE, OWNER_ONLY, UNK3
- UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE = OBJECT_END + 0x00BB, // Size: 7, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE = OBJECT_END + 0x00C2, // Size: 7, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_BASE_MANA = OBJECT_END + 0x00C9, // Size: 1, Type: INT, Flags: PUBLIC
- UNIT_FIELD_BASE_HEALTH = OBJECT_END + 0x00CA, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_BYTES_2 = OBJECT_END + 0x00CB, // Size: 1, Type: BYTES, Flags: PUBLIC
- UNIT_FIELD_ATTACK_POWER = OBJECT_END + 0x00CC, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_ATTACK_POWER_MODS = OBJECT_END + 0x00CD, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x00CE, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_RANGED_ATTACK_POWER = OBJECT_END + 0x00CF, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_RANGED_ATTACK_POWER_MODS = OBJECT_END + 0x00D0, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x00D1, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_MINRANGEDDAMAGE = OBJECT_END + 0x00D2, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_MAXRANGEDDAMAGE = OBJECT_END + 0x00D3, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_POWER_COST_MODIFIER = OBJECT_END + 0x00D4, // Size: 7, Type: INT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_POWER_COST_MULTIPLIER = OBJECT_END + 0x00DB, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_MAXHEALTHMODIFIER = OBJECT_END + 0x00E2, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
- UNIT_FIELD_PADDING = OBJECT_END + 0x00E3, // Size: 1, Type: INT, Flags: NONE
- UNIT_END = OBJECT_END + 0x00E4,
+ UNIT_FIELD_BYTES_0 = OBJECT_END + 0x0010, // Size: 1, Type: BYTES, Flags: PUBLIC
+ UNIT_FIELD_HEALTH = OBJECT_END + 0x0011, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_POWER1 = OBJECT_END + 0x0012, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_POWER2 = OBJECT_END + 0x0013, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_POWER3 = OBJECT_END + 0x0014, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_POWER4 = OBJECT_END + 0x0015, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_POWER5 = OBJECT_END + 0x0016, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_POWER6 = OBJECT_END + 0x0017, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_POWER7 = OBJECT_END + 0x0018, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MAXHEALTH = OBJECT_END + 0x0019, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MAXPOWER1 = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MAXPOWER2 = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MAXPOWER3 = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MAXPOWER4 = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MAXPOWER5 = OBJECT_END + 0x001E, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MAXPOWER6 = OBJECT_END + 0x001F, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MAXPOWER7 = OBJECT_END + 0x0020, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER = OBJECT_END + 0x0021, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER = OBJECT_END + 0x0028, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_LEVEL = OBJECT_END + 0x002F, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_FACTIONTEMPLATE = OBJECT_END + 0x0030, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_VIRTUAL_ITEM_SLOT_ID = OBJECT_END + 0x0031, // Size: 3, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_FLAGS = OBJECT_END + 0x0034, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_FLAGS_2 = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_AURASTATE = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_BASEATTACKTIME = OBJECT_END + 0x0037, // Size: 2, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_RANGEDATTACKTIME = OBJECT_END + 0x0039, // Size: 1, Type: INT, Flags: PRIVATE
+ UNIT_FIELD_BOUNDINGRADIUS = OBJECT_END + 0x003A, // Size: 1, Type: FLOAT, Flags: PUBLIC
+ UNIT_FIELD_COMBATREACH = OBJECT_END + 0x003B, // Size: 1, Type: FLOAT, Flags: PUBLIC
+ UNIT_FIELD_DISPLAYID = OBJECT_END + 0x003C, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_NATIVEDISPLAYID = OBJECT_END + 0x003D, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MOUNTDISPLAYID = OBJECT_END + 0x003E, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_MINDAMAGE = OBJECT_END + 0x003F, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY, UNK3
+ UNIT_FIELD_MAXDAMAGE = OBJECT_END + 0x0040, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY, UNK3
+ UNIT_FIELD_MINOFFHANDDAMAGE = OBJECT_END + 0x0041, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY, UNK3
+ UNIT_FIELD_MAXOFFHANDDAMAGE = OBJECT_END + 0x0042, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY, UNK3
+ UNIT_FIELD_BYTES_1 = OBJECT_END + 0x0043, // Size: 1, Type: BYTES, Flags: PUBLIC
+ UNIT_FIELD_PETNUMBER = OBJECT_END + 0x0044, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_PET_NAME_TIMESTAMP = OBJECT_END + 0x0045, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_PETEXPERIENCE = OBJECT_END + 0x0046, // Size: 1, Type: INT, Flags: OWNER_ONLY
+ UNIT_FIELD_PETNEXTLEVELEXP = OBJECT_END + 0x0047, // Size: 1, Type: INT, Flags: OWNER_ONLY
+ UNIT_DYNAMIC_FLAGS = OBJECT_END + 0x0048, // Size: 1, Type: INT, Flags: DYNAMIC
+ UNIT_CHANNEL_SPELL = OBJECT_END + 0x0049, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_MOD_CAST_SPEED = OBJECT_END + 0x004A, // Size: 1, Type: FLOAT, Flags: PUBLIC
+ UNIT_CREATED_BY_SPELL = OBJECT_END + 0x004B, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_NPC_FLAGS = OBJECT_END + 0x004C, // Size: 1, Type: INT, Flags: DYNAMIC
+ UNIT_NPC_EMOTESTATE = OBJECT_END + 0x004D, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_STAT0 = OBJECT_END + 0x004E, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_STAT1 = OBJECT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_STAT2 = OBJECT_END + 0x0050, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_STAT3 = OBJECT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_STAT4 = OBJECT_END + 0x0052, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_POSSTAT0 = OBJECT_END + 0x0053, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_POSSTAT1 = OBJECT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_POSSTAT2 = OBJECT_END + 0x0055, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_POSSTAT3 = OBJECT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_POSSTAT4 = OBJECT_END + 0x0057, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_NEGSTAT0 = OBJECT_END + 0x0058, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_NEGSTAT1 = OBJECT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_NEGSTAT2 = OBJECT_END + 0x005A, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_NEGSTAT3 = OBJECT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_NEGSTAT4 = OBJECT_END + 0x005C, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_RESISTANCES = OBJECT_END + 0x005D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER_ONLY, UNK3
+ UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE = OBJECT_END + 0x0064, // Size: 7, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE = OBJECT_END + 0x006B, // Size: 7, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_BASE_MANA = OBJECT_END + 0x0072, // Size: 1, Type: INT, Flags: PUBLIC
+ UNIT_FIELD_BASE_HEALTH = OBJECT_END + 0x0073, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_BYTES_2 = OBJECT_END + 0x0074, // Size: 1, Type: BYTES, Flags: PUBLIC
+ UNIT_FIELD_ATTACK_POWER = OBJECT_END + 0x0075, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_ATTACK_POWER_MODS = OBJECT_END + 0x0076, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x0077, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_RANGED_ATTACK_POWER = OBJECT_END + 0x0078, // Size: 1, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_RANGED_ATTACK_POWER_MODS = OBJECT_END + 0x0079, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x007A, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_MINRANGEDDAMAGE = OBJECT_END + 0x007B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_MAXRANGEDDAMAGE = OBJECT_END + 0x007C, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_POWER_COST_MODIFIER = OBJECT_END + 0x007D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_POWER_COST_MULTIPLIER = OBJECT_END + 0x0084, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_MAXHEALTHMODIFIER = OBJECT_END + 0x008B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER_ONLY
+ UNIT_FIELD_HOVERHEIGHT = OBJECT_END + 0x008C, // Size: 1, Type: FLOAT, Flags: PUBLIC
+ UNIT_FIELD_PADDING = OBJECT_END + 0x008D, // Size: 1, Type: INT, Flags: NONE
+ UNIT_END = OBJECT_END + 0x008E,
PLAYER_DUEL_ARBITER = UNIT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
PLAYER_FLAGS = UNIT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC
@@ -262,160 +287,184 @@ enum EUnitFields
PLAYER_QUEST_LOG_25_3 = UNIT_END + 0x006C, // Size: 1, Type: BYTES, Flags: PRIVATE
PLAYER_QUEST_LOG_25_4 = UNIT_END + 0x006D, // Size: 1, Type: INT, Flags: PRIVATE
PLAYER_VISIBLE_ITEM_1_CREATOR = UNIT_END + 0x006E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_1_0 = UNIT_END + 0x0070, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_1_PROPERTIES = UNIT_END + 0x007C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_1_PAD = UNIT_END + 0x007D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_2_CREATOR = UNIT_END + 0x007E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_2_0 = UNIT_END + 0x0080, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_2_PROPERTIES = UNIT_END + 0x008C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_2_PAD = UNIT_END + 0x008D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_3_CREATOR = UNIT_END + 0x008E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_3_0 = UNIT_END + 0x0090, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_3_PROPERTIES = UNIT_END + 0x009C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_3_PAD = UNIT_END + 0x009D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_4_CREATOR = UNIT_END + 0x009E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_4_0 = UNIT_END + 0x00A0, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_4_PROPERTIES = UNIT_END + 0x00AC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_4_PAD = UNIT_END + 0x00AD, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_5_CREATOR = UNIT_END + 0x00AE, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_5_0 = UNIT_END + 0x00B0, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_5_PROPERTIES = UNIT_END + 0x00BC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_5_PAD = UNIT_END + 0x00BD, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_6_CREATOR = UNIT_END + 0x00BE, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_6_0 = UNIT_END + 0x00C0, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_6_PROPERTIES = UNIT_END + 0x00CC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_6_PAD = UNIT_END + 0x00CD, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_7_CREATOR = UNIT_END + 0x00CE, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_7_0 = UNIT_END + 0x00D0, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_7_PROPERTIES = UNIT_END + 0x00DC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_7_PAD = UNIT_END + 0x00DD, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_8_CREATOR = UNIT_END + 0x00DE, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_8_0 = UNIT_END + 0x00E0, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_8_PROPERTIES = UNIT_END + 0x00EC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_8_PAD = UNIT_END + 0x00ED, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_9_CREATOR = UNIT_END + 0x00EE, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_9_0 = UNIT_END + 0x00F0, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_9_PROPERTIES = UNIT_END + 0x00FC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_9_PAD = UNIT_END + 0x00FD, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_10_CREATOR = UNIT_END + 0x00FE, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_10_0 = UNIT_END + 0x0100, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_10_PROPERTIES = UNIT_END + 0x010C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_10_PAD = UNIT_END + 0x010D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_11_CREATOR = UNIT_END + 0x010E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_11_0 = UNIT_END + 0x0110, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_11_PROPERTIES = UNIT_END + 0x011C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_11_PAD = UNIT_END + 0x011D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_12_CREATOR = UNIT_END + 0x011E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_12_0 = UNIT_END + 0x0120, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_12_PROPERTIES = UNIT_END + 0x012C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_12_PAD = UNIT_END + 0x012D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_13_CREATOR = UNIT_END + 0x012E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_13_0 = UNIT_END + 0x0130, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_13_PROPERTIES = UNIT_END + 0x013C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_13_PAD = UNIT_END + 0x013D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_14_CREATOR = UNIT_END + 0x013E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_14_0 = UNIT_END + 0x0140, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_14_PROPERTIES = UNIT_END + 0x014C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_14_PAD = UNIT_END + 0x014D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_15_CREATOR = UNIT_END + 0x014E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_15_0 = UNIT_END + 0x0150, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_15_PROPERTIES = UNIT_END + 0x015C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_15_PAD = UNIT_END + 0x015D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_16_CREATOR = UNIT_END + 0x015E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_16_0 = UNIT_END + 0x0160, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_16_PROPERTIES = UNIT_END + 0x016C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_16_PAD = UNIT_END + 0x016D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_17_CREATOR = UNIT_END + 0x016E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_17_0 = UNIT_END + 0x0170, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_17_PROPERTIES = UNIT_END + 0x017C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_17_PAD = UNIT_END + 0x017D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_18_CREATOR = UNIT_END + 0x017E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_18_0 = UNIT_END + 0x0180, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_18_PROPERTIES = UNIT_END + 0x018C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_18_PAD = UNIT_END + 0x018D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_19_CREATOR = UNIT_END + 0x018E, // Size: 2, Type: LONG, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_19_0 = UNIT_END + 0x0190, // Size: 12, Type: INT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_19_PROPERTIES = UNIT_END + 0x019C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
- PLAYER_VISIBLE_ITEM_19_PAD = UNIT_END + 0x019D, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_CHOSEN_TITLE = UNIT_END + 0x019E, // Size: 1, Type: INT, Flags: PUBLIC
- PLAYER_FIELD_PAD_0 = UNIT_END + 0x019F, // Size: 1, Type: INT, Flags: NONE
- PLAYER_FIELD_INV_SLOT_HEAD = UNIT_END + 0x01A0, // Size: 46, Type: LONG, Flags: PRIVATE
- PLAYER_FIELD_PACK_SLOT_1 = UNIT_END + 0x01CE, // Size: 32, Type: LONG, Flags: PRIVATE
- PLAYER_FIELD_BANK_SLOT_1 = UNIT_END + 0x01EE, // Size: 56, Type: LONG, Flags: PRIVATE
- PLAYER_FIELD_BANKBAG_SLOT_1 = UNIT_END + 0x0226, // Size: 14, Type: LONG, Flags: PRIVATE
- PLAYER_FIELD_VENDORBUYBACK_SLOT_1 = UNIT_END + 0x0234, // Size: 24, Type: LONG, Flags: PRIVATE
- PLAYER_FIELD_KEYRING_SLOT_1 = UNIT_END + 0x024C, // Size: 64, Type: LONG, Flags: PRIVATE
- PLAYER_FIELD_VANITYPET_SLOT_1 = UNIT_END + 0x028C, // Size: 36, Type: LONG, Flags: PRIVATE
- PLAYER_FARSIGHT = UNIT_END + 0x02B0, // Size: 2, Type: LONG, Flags: PRIVATE
- PLAYER__FIELD_KNOWN_TITLES = UNIT_END + 0x02B2, // Size: 2, Type: LONG, Flags: PRIVATE
- PLAYER_XP = UNIT_END + 0x02B4, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_NEXT_LEVEL_XP = UNIT_END + 0x02B5, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_SKILL_INFO_1_1 = UNIT_END + 0x02B6, // Size: 384, Type: TWO_SHORT, Flags: PRIVATE
- PLAYER_CHARACTER_POINTS1 = UNIT_END + 0x0436, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_CHARACTER_POINTS2 = UNIT_END + 0x0437, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_TRACK_CREATURES = UNIT_END + 0x0438, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_TRACK_RESOURCES = UNIT_END + 0x0439, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_BLOCK_PERCENTAGE = UNIT_END + 0x043A, // Size: 1, Type: FLOAT, Flags: PRIVATE
- PLAYER_DODGE_PERCENTAGE = UNIT_END + 0x043B, // Size: 1, Type: FLOAT, Flags: PRIVATE
- PLAYER_PARRY_PERCENTAGE = UNIT_END + 0x043C, // Size: 1, Type: FLOAT, Flags: PRIVATE
- PLAYER_EXPERTISE = UNIT_END + 0x043D, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_OFFHAND_EXPERTISE = UNIT_END + 0x043E, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_CRIT_PERCENTAGE = UNIT_END + 0x043F, // Size: 1, Type: FLOAT, Flags: PRIVATE
- PLAYER_RANGED_CRIT_PERCENTAGE = UNIT_END + 0x0440, // Size: 1, Type: FLOAT, Flags: PRIVATE
- PLAYER_OFFHAND_CRIT_PERCENTAGE = UNIT_END + 0x0441, // Size: 1, Type: FLOAT, Flags: PRIVATE
- PLAYER_SPELL_CRIT_PERCENTAGE1 = UNIT_END + 0x0442, // Size: 7, Type: FLOAT, Flags: PRIVATE
- PLAYER_SHIELD_BLOCK = UNIT_END + 0x0449, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_EXPLORED_ZONES_1 = UNIT_END + 0x044A, // Size: 128, Type: BYTES, Flags: PRIVATE
- PLAYER_REST_STATE_EXPERIENCE = UNIT_END + 0x04CA, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_COINAGE = UNIT_END + 0x04CB, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_MOD_DAMAGE_DONE_POS = UNIT_END + 0x04CC, // Size: 7, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_MOD_DAMAGE_DONE_NEG = UNIT_END + 0x04D3, // Size: 7, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_MOD_DAMAGE_DONE_PCT = UNIT_END + 0x04DA, // Size: 7, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_MOD_HEALING_DONE_POS = UNIT_END + 0x04E1, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x04E2, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x04E3, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_BYTES = UNIT_END + 0x04E4, // Size: 1, Type: BYTES, Flags: PRIVATE
- PLAYER_AMMO_ID = UNIT_END + 0x04E5, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_SELF_RES_SPELL = UNIT_END + 0x04E6, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x04E7, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x04E8, // Size: 12, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x04F4, // Size: 12, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_KILLS = UNIT_END + 0x0500, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE
- PLAYER_FIELD_TODAY_CONTRIBUTION = UNIT_END + 0x0501, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_YESTERDAY_CONTRIBUTION = UNIT_END + 0x0502, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_LIFETIME_HONORBALE_KILLS = UNIT_END + 0x0503, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_BYTES2 = UNIT_END + 0x0504, // Size: 1, Type: BYTES, Flags: PRIVATE
- PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x0505, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x0506, // Size: 24, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x051E, // Size: 18, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x0530, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x0531, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_MOD_MANA_REGEN = UNIT_END + 0x0532, // Size: 1, Type: FLOAT, Flags: PRIVATE
- PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT = UNIT_END + 0x0533, // Size: 1, Type: FLOAT, Flags: PRIVATE
- PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x0534, // Size: 1, Type: INT, Flags: PRIVATE
- PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x0535, // Size: 25, Type: INT, Flags: PRIVATE
- PLAYER_END = UNIT_END + 0x054E,
+ PLAYER_VISIBLE_ITEM_1_0 = UNIT_END + 0x0070, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_1_PROPERTIES = UNIT_END + 0x007D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_1_SEED = UNIT_END + 0x007E, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_1_PAD = UNIT_END + 0x007F, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_2_CREATOR = UNIT_END + 0x0080, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_2_0 = UNIT_END + 0x0082, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_2_PROPERTIES = UNIT_END + 0x008F, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_2_SEED = UNIT_END + 0x0090, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_2_PAD = UNIT_END + 0x0091, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_3_CREATOR = UNIT_END + 0x0092, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_3_0 = UNIT_END + 0x0094, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_3_PROPERTIES = UNIT_END + 0x00A1, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_3_SEED = UNIT_END + 0x00A2, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_3_PAD = UNIT_END + 0x00A3, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_4_CREATOR = UNIT_END + 0x00A4, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_4_0 = UNIT_END + 0x00A6, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_4_PROPERTIES = UNIT_END + 0x00B3, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_4_SEED = UNIT_END + 0x00B4, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_4_PAD = UNIT_END + 0x00B5, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_5_CREATOR = UNIT_END + 0x00B6, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_5_0 = UNIT_END + 0x00B8, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_5_PROPERTIES = UNIT_END + 0x00C5, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_5_SEED = UNIT_END + 0x00C6, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_5_PAD = UNIT_END + 0x00C7, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_6_CREATOR = UNIT_END + 0x00C8, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_6_0 = UNIT_END + 0x00CA, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_6_PROPERTIES = UNIT_END + 0x00D7, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_6_SEED = UNIT_END + 0x00D8, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_6_PAD = UNIT_END + 0x00D9, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_7_CREATOR = UNIT_END + 0x00DA, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_7_0 = UNIT_END + 0x00DC, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_7_PROPERTIES = UNIT_END + 0x00E9, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_7_SEED = UNIT_END + 0x00EA, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_7_PAD = UNIT_END + 0x00EB, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_8_CREATOR = UNIT_END + 0x00EC, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_8_0 = UNIT_END + 0x00EE, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_8_PROPERTIES = UNIT_END + 0x00FB, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_8_SEED = UNIT_END + 0x00FC, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_8_PAD = UNIT_END + 0x00FD, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_9_CREATOR = UNIT_END + 0x00FE, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_9_0 = UNIT_END + 0x0100, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_9_PROPERTIES = UNIT_END + 0x010D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_9_SEED = UNIT_END + 0x010E, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_9_PAD = UNIT_END + 0x010F, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_10_CREATOR = UNIT_END + 0x0110, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_10_0 = UNIT_END + 0x0112, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_10_PROPERTIES = UNIT_END + 0x011F, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_10_SEED = UNIT_END + 0x0120, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_10_PAD = UNIT_END + 0x0121, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_11_CREATOR = UNIT_END + 0x0122, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_11_0 = UNIT_END + 0x0124, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_11_PROPERTIES = UNIT_END + 0x0131, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_11_SEED = UNIT_END + 0x0132, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_11_PAD = UNIT_END + 0x0133, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_12_CREATOR = UNIT_END + 0x0134, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_12_0 = UNIT_END + 0x0136, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_12_PROPERTIES = UNIT_END + 0x0143, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_12_SEED = UNIT_END + 0x0144, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_12_PAD = UNIT_END + 0x0145, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_13_CREATOR = UNIT_END + 0x0146, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_13_0 = UNIT_END + 0x0148, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_13_PROPERTIES = UNIT_END + 0x0155, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_13_SEED = UNIT_END + 0x0156, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_13_PAD = UNIT_END + 0x0157, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_14_CREATOR = UNIT_END + 0x0158, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_14_0 = UNIT_END + 0x015A, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_14_PROPERTIES = UNIT_END + 0x0167, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_14_SEED = UNIT_END + 0x0168, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_14_PAD = UNIT_END + 0x0169, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_15_CREATOR = UNIT_END + 0x016A, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_15_0 = UNIT_END + 0x016C, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_15_PROPERTIES = UNIT_END + 0x0179, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_15_SEED = UNIT_END + 0x017A, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_15_PAD = UNIT_END + 0x017B, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_16_CREATOR = UNIT_END + 0x017C, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_16_0 = UNIT_END + 0x017E, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_16_PROPERTIES = UNIT_END + 0x018B, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_16_SEED = UNIT_END + 0x018C, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_16_PAD = UNIT_END + 0x018D, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_17_CREATOR = UNIT_END + 0x018E, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_17_0 = UNIT_END + 0x0190, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_17_PROPERTIES = UNIT_END + 0x019D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_17_SEED = UNIT_END + 0x019E, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_17_PAD = UNIT_END + 0x019F, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_18_CREATOR = UNIT_END + 0x01A0, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_18_0 = UNIT_END + 0x01A2, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_18_PROPERTIES = UNIT_END + 0x01AF, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_18_SEED = UNIT_END + 0x01B0, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_18_PAD = UNIT_END + 0x01B1, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_19_CREATOR = UNIT_END + 0x01B2, // Size: 2, Type: LONG, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_19_0 = UNIT_END + 0x01B4, // Size: 13, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_19_PROPERTIES = UNIT_END + 0x01C1, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_19_SEED = UNIT_END + 0x01C2, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_VISIBLE_ITEM_19_PAD = UNIT_END + 0x01C3, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_CHOSEN_TITLE = UNIT_END + 0x01C4, // Size: 1, Type: INT, Flags: PUBLIC
+ PLAYER_FIELD_PAD_0 = UNIT_END + 0x01C5, // Size: 1, Type: INT, Flags: NONE
+ PLAYER_FIELD_INV_SLOT_HEAD = UNIT_END + 0x01C6, // Size: 46, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_PACK_SLOT_1 = UNIT_END + 0x01F4, // Size: 32, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_BANK_SLOT_1 = UNIT_END + 0x0214, // Size: 56, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_BANKBAG_SLOT_1 = UNIT_END + 0x024C, // Size: 14, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_VENDORBUYBACK_SLOT_1 = UNIT_END + 0x025A, // Size: 24, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_KEYRING_SLOT_1 = UNIT_END + 0x0272, // Size: 64, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_VANITYPET_SLOT_1 = UNIT_END + 0x02B2, // Size: 36, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_CURRENCYTOKEN_SLOT_1 = UNIT_END + 0x02D6, // Size: 64, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_QUESTBAG_SLOT_1 = UNIT_END + 0x0316, // Size: 64, Type: LONG, Flags: PRIVATE
+ PLAYER_FARSIGHT = UNIT_END + 0x0356, // Size: 2, Type: LONG, Flags: PRIVATE
+ PLAYER__FIELD_KNOWN_TITLES = UNIT_END + 0x0358, // Size: 2, Type: LONG, Flags: PRIVATE
+ PLAYER__FIELD_KNOWN_TITLES1 = UNIT_END + 0x035A, // Size: 2, Type: LONG, Flags: PRIVATE
+ PLAYER_FIELD_KNOWN_CURRENCIES = UNIT_END + 0x035C, // Size: 2, Type: LONG, Flags: PRIVATE
+ PLAYER_XP = UNIT_END + 0x035E, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_NEXT_LEVEL_XP = UNIT_END + 0x035F, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_SKILL_INFO_1_1 = UNIT_END + 0x0360, // Size: 384, Type: TWO_SHORT, Flags: PRIVATE
+ PLAYER_CHARACTER_POINTS1 = UNIT_END + 0x04E0, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_CHARACTER_POINTS2 = UNIT_END + 0x04E1, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_TRACK_CREATURES = UNIT_END + 0x04E2, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_TRACK_RESOURCES = UNIT_END + 0x04E3, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_BLOCK_PERCENTAGE = UNIT_END + 0x04E4, // Size: 1, Type: FLOAT, Flags: PRIVATE
+ PLAYER_DODGE_PERCENTAGE = UNIT_END + 0x04E5, // Size: 1, Type: FLOAT, Flags: PRIVATE
+ PLAYER_PARRY_PERCENTAGE = UNIT_END + 0x04E6, // Size: 1, Type: FLOAT, Flags: PRIVATE
+ PLAYER_EXPERTISE = UNIT_END + 0x04E7, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_OFFHAND_EXPERTISE = UNIT_END + 0x04E8, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_CRIT_PERCENTAGE = UNIT_END + 0x04E9, // Size: 1, Type: FLOAT, Flags: PRIVATE
+ PLAYER_RANGED_CRIT_PERCENTAGE = UNIT_END + 0x04EA, // Size: 1, Type: FLOAT, Flags: PRIVATE
+ PLAYER_OFFHAND_CRIT_PERCENTAGE = UNIT_END + 0x04EB, // Size: 1, Type: FLOAT, Flags: PRIVATE
+ PLAYER_SPELL_CRIT_PERCENTAGE1 = UNIT_END + 0x04EC, // Size: 7, Type: FLOAT, Flags: PRIVATE
+ PLAYER_SHIELD_BLOCK = UNIT_END + 0x04F3, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_SHIELD_BLOCK_CRIT_PERCENTAGE = UNIT_END + 0x04F4, // Size: 1, Type: FLOAT, Flags: PRIVATE
+ PLAYER_EXPLORED_ZONES_1 = UNIT_END + 0x04F5, // Size: 128, Type: BYTES, Flags: PRIVATE
+ PLAYER_REST_STATE_EXPERIENCE = UNIT_END + 0x0575, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_COINAGE = UNIT_END + 0x0576, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_MOD_DAMAGE_DONE_POS = UNIT_END + 0x0577, // Size: 7, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_MOD_DAMAGE_DONE_NEG = UNIT_END + 0x057E, // Size: 7, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_MOD_DAMAGE_DONE_PCT = UNIT_END + 0x0585, // Size: 7, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_MOD_HEALING_DONE_POS = UNIT_END + 0x058C, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x058D, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x058E, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_BYTES = UNIT_END + 0x058F, // Size: 1, Type: BYTES, Flags: PRIVATE
+ PLAYER_AMMO_ID = UNIT_END + 0x0590, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_SELF_RES_SPELL = UNIT_END + 0x0591, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x0592, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x0593, // Size: 12, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x059F, // Size: 12, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_KILLS = UNIT_END + 0x05AB, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE
+ PLAYER_FIELD_TODAY_CONTRIBUTION = UNIT_END + 0x05AC, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_YESTERDAY_CONTRIBUTION = UNIT_END + 0x05AD, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_LIFETIME_HONORBALE_KILLS = UNIT_END + 0x05AE, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_BYTES2 = UNIT_END + 0x05AF, // Size: 1, Type: BYTES, Flags: PRIVATE
+ PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x05B0, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x05B1, // Size: 25, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x05CA, // Size: 18, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x05DC, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x05DD, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x05DE, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x05DF, // Size: 25, Type: INT, Flags: PRIVATE
+ PLAYER_RUNE_REGEN_1 = UNIT_END + 0x05F8, // Size: 4, Type: FLOAT, Flags: PRIVATE
+ PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x05FC, // Size: 3, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x05FF, // Size: 8, Type: INT, Flags: PRIVATE
+ PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x0607, // Size: 8, Type: INT, Flags: PRIVATE
+ PLAYER_GLYPHS_ENABLED = UNIT_END + 0x060F, // Size: 1, Type: INT, Flags: PRIVATE
+ PLAYER_END = UNIT_END + 0x0610,
};
enum EGameObjectFields
{
OBJECT_FIELD_CREATED_BY = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC
GAMEOBJECT_DISPLAYID = OBJECT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC
- GAMEOBJECT_FLAGS = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC
- GAMEOBJECT_ROTATION = OBJECT_END + 0x0004, // Size: 4, Type: FLOAT, Flags: PUBLIC
- GAMEOBJECT_STATE = OBJECT_END + 0x0008, // Size: 1, Type: INT, Flags: PUBLIC
- GAMEOBJECT_POS_X = OBJECT_END + 0x0009, // Size: 1, Type: FLOAT, Flags: PUBLIC
- GAMEOBJECT_POS_Y = OBJECT_END + 0x000A, // Size: 1, Type: FLOAT, Flags: PUBLIC
- GAMEOBJECT_POS_Z = OBJECT_END + 0x000B, // Size: 1, Type: FLOAT, Flags: PUBLIC
- GAMEOBJECT_FACING = OBJECT_END + 0x000C, // Size: 1, Type: FLOAT, Flags: PUBLIC
- GAMEOBJECT_DYN_FLAGS = OBJECT_END + 0x000D, // Size: 1, Type: INT, Flags: DYNAMIC
- GAMEOBJECT_FACTION = OBJECT_END + 0x000E, // Size: 1, Type: INT, Flags: PUBLIC
- GAMEOBJECT_TYPE_ID = OBJECT_END + 0x000F, // Size: 1, Type: INT, Flags: PUBLIC
+ GAMEOBJECT_FLAGS = OBJECT_END + 0x0003, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC
+ GAMEOBJECT_ROTATION = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PUBLIC
+ GAMEOBJECT_PARENTROTATION = OBJECT_END + 0x0006, // Size: 4, Type: FLOAT, Flags: PUBLIC
+ GAMEOBJECT_POS_X = OBJECT_END + 0x000A, // Size: 1, Type: FLOAT, Flags: PUBLIC
+ GAMEOBJECT_POS_Y = OBJECT_END + 0x000B, // Size: 1, Type: FLOAT, Flags: PUBLIC
+ GAMEOBJECT_POS_Z = OBJECT_END + 0x000C, // Size: 1, Type: FLOAT, Flags: PUBLIC
+ GAMEOBJECT_FACING = OBJECT_END + 0x000D, // Size: 1, Type: FLOAT, Flags: PUBLIC
+ GAMEOBJECT_DYNAMIC = OBJECT_END + 0x000E, // Size: 1, Type: TWO_SHORT, Flags: DYNAMIC
+ GAMEOBJECT_FACTION = OBJECT_END + 0x000F, // Size: 1, Type: INT, Flags: PUBLIC
GAMEOBJECT_LEVEL = OBJECT_END + 0x0010, // Size: 1, Type: INT, Flags: PUBLIC
- GAMEOBJECT_ARTKIT = OBJECT_END + 0x0011, // Size: 1, Type: INT, Flags: PUBLIC
- GAMEOBJECT_ANIMPROGRESS = OBJECT_END + 0x0012, // Size: 1, Type: INT, Flags: DYNAMIC
- GAMEOBJECT_PADDING = OBJECT_END + 0x0013, // Size: 1, Type: INT, Flags: NONE
- GAMEOBJECT_END = OBJECT_END + 0x0014,
+ GAMEOBJECT_BYTES_1 = OBJECT_END + 0x0011, // Size: 1, Type: BYTES, Flags: PUBLIC
+ GAMEOBJECT_END = OBJECT_END + 0x0012,
};
enum EDynamicObjectFields
diff --git a/src/game/UpdateMask.h b/src/game/UpdateMask.h
index 436aa523440..66a6947fc37 100644
--- a/src/game/UpdateMask.h
+++ b/src/game/UpdateMask.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,27 +36,27 @@ class UpdateMask
delete [] mUpdateMask;
}
- inline void SetBit (uint32 index)
+ void SetBit (uint32 index)
{
( (uint8 *)mUpdateMask )[ index >> 3 ] |= 1 << ( index & 0x7 );
}
- inline void UnsetBit (uint32 index)
+ void UnsetBit (uint32 index)
{
( (uint8 *)mUpdateMask )[ index >> 3 ] &= (0xff ^ (1 << ( index & 0x7 ) ) );
}
- inline bool GetBit (uint32 index)
+ bool GetBit (uint32 index) const
{
return ( ( (uint8 *)mUpdateMask)[ index >> 3 ] & ( 1 << ( index & 0x7 ) )) != 0;
}
- inline uint32 GetBlockCount() { return mBlocks; }
- inline uint32 GetLength() { return mBlocks << 2; }
- inline uint32 GetCount() { return mCount; }
- inline uint8* GetMask() { return (uint8*)mUpdateMask; }
+ uint32 GetBlockCount() const { return mBlocks; }
+ uint32 GetLength() const { return mBlocks << 2; }
+ uint32 GetCount() const { return mCount; }
+ uint8* GetMask() { return (uint8*)mUpdateMask; }
- inline void SetCount (uint32 valuesCount)
+ void SetCount (uint32 valuesCount)
{
if(mUpdateMask)
delete [] mUpdateMask;
@@ -68,13 +68,13 @@ class UpdateMask
memset(mUpdateMask, 0, mBlocks << 2);
}
- inline void Clear()
+ void Clear()
{
if (mUpdateMask)
memset(mUpdateMask, 0, mBlocks << 2);
}
- inline UpdateMask& operator = ( const UpdateMask& mask )
+ UpdateMask& operator = ( const UpdateMask& mask )
{
SetCount(mask.mCount);
memcpy(mUpdateMask, mask.mUpdateMask, mBlocks << 2);
@@ -82,21 +82,21 @@ class UpdateMask
return *this;
}
- inline void operator &= ( const UpdateMask& mask )
+ void operator &= ( const UpdateMask& mask )
{
ASSERT(mask.mCount <= mCount);
- for (uint32 i = 0; i < mBlocks; i++)
+ for (uint32 i = 0; i < mBlocks; ++i)
mUpdateMask[i] &= mask.mUpdateMask[i];
}
- inline void operator |= ( const UpdateMask& mask )
+ void operator |= ( const UpdateMask& mask )
{
ASSERT(mask.mCount <= mCount);
- for (uint32 i = 0; i < mBlocks; i++)
+ for (uint32 i = 0; i < mBlocks; ++i)
mUpdateMask[i] |= mask.mUpdateMask[i];
}
- inline UpdateMask operator & ( const UpdateMask& mask ) const
+ UpdateMask operator & ( const UpdateMask& mask ) const
{
ASSERT(mask.mCount <= mCount);
@@ -107,7 +107,7 @@ class UpdateMask
return newmask;
}
- inline UpdateMask operator | ( const UpdateMask& mask ) const
+ UpdateMask operator | ( const UpdateMask& mask ) const
{
ASSERT(mask.mCount <= mCount);
diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp
new file mode 100644
index 00000000000..bfc87011761
--- /dev/null
+++ b/src/game/Vehicle.cpp
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Common.h"
+#include "Log.h"
+#include "ObjectMgr.h"
+#include "Vehicle.h"
+#include "Unit.h"
+#include "Util.h"
+#include "WorldPacket.h"
+
+#include "Chat.h"
+
+Vehicle::Vehicle() : Creature(), m_vehicleInfo(NULL), m_usableSeatNum(0)
+{
+ m_summonMask |= SUMMON_MASK_VEHICLE;
+ m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_VEHICLE);
+}
+
+Vehicle::~Vehicle()
+{
+}
+
+void Vehicle::AddToWorld()
+{
+ if(!IsInWorld())
+ {
+ ObjectAccessor::Instance().AddObject(this);
+ Unit::AddToWorld();
+ AIM_Initialize();
+ switch(GetEntry())
+ {
+ case 27850:InstallAccessory(27905,1);break;
+ case 28312:InstallAccessory(28319,7);break;
+ case 32627:InstallAccessory(32629,7);break;
+ }
+ //setPowerType(POWER_ENERGY);SetMaxPower(POWER_ENERGY, 100);
+ }
+}
+
+void Vehicle::RemoveFromWorld()
+{
+ if(IsInWorld())
+ {
+ RemoveAllPassengers();
+ ///- Don't call the function for Creature, normal mobs + totems go in a different storage
+ Unit::RemoveFromWorld();
+ ObjectAccessor::Instance().RemoveObject(this);
+ }
+}
+
+void Vehicle::setDeathState(DeathState s) // overwrite virtual Creature::setDeathState and Unit::setDeathState
+{
+ if(s == JUST_DIED)
+ {
+ for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
+ {
+ if(Unit *passenger = itr->second.passenger)
+ if(passenger->GetTypeId() == TYPEID_UNIT && ((Creature*)passenger)->isVehicle())
+ {
+ passenger->ExitVehicle();
+ ((Vehicle*)passenger)->setDeathState(s);
+ }
+ }
+ RemoveAllPassengers();
+ }
+ Creature::setDeathState(s);
+}
+
+void Vehicle::Update(uint32 diff)
+{
+ Creature::Update(diff);
+ //310
+ //if(getPowerType() == POWER_ENERGY)
+ // ModifyPower(POWER_ENERGY, 1);
+}
+
+bool Vehicle::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehicleId, uint32 team, const CreatureData * data)
+{
+ if(!Creature::Create(guidlow, map, phaseMask, Entry, team, data))
+ return false;
+
+ SetVehicleId(vehicleId);
+ return true;
+}
+
+void Vehicle::RemoveAllPassengers()
+{
+ for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
+ if(Unit *passenger = itr->second.passenger)
+ {
+ if(passenger->GetTypeId() == TYPEID_UNIT && ((Creature*)passenger)->isVehicle())
+ ((Vehicle*)passenger)->RemoveAllPassengers();
+ passenger->ExitVehicle();
+ assert(!itr->second.passenger);
+ }
+}
+
+void Vehicle::SetVehicleId(uint32 id)
+{
+ if(m_vehicleInfo && id == m_vehicleInfo->m_ID)
+ return;
+
+ VehicleEntry const *ve = sVehicleStore.LookupEntry(id);
+ if(!ve)
+ return;
+
+ m_vehicleInfo = ve;
+
+ RemoveAllPassengers();
+ m_Seats.clear();
+ m_usableSeatNum = 0;
+
+ for(uint32 i = 0; i < 8; ++i)
+ {
+ if(uint32 seatId = m_vehicleInfo->m_seatID[i])
+ if(VehicleSeatEntry const *veSeat = sVehicleSeatStore.LookupEntry(seatId))
+ {
+ m_Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
+ if(veSeat->IsUsable())
+ ++m_usableSeatNum;
+ }
+ }
+
+ assert(!m_Seats.empty());
+ if(m_usableSeatNum)
+ SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+}
+
+bool Vehicle::HasEmptySeat(int8 seatId) const
+{
+ SeatMap::const_iterator seat = m_Seats.find(seatId);
+ if(seat == m_Seats.end()) return false;
+ return !seat->second.passenger;
+}
+
+int8 Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
+{
+ SeatMap::const_iterator seat = m_Seats.find(seatId);
+ if(seat == m_Seats.end()) return -1;
+ while(seat->second.passenger || !seat->second.seatInfo->IsUsable())
+ {
+ if(next)
+ {
+ ++seat;
+ if(seat == m_Seats.end())
+ seat = m_Seats.begin();
+ }
+ else
+ {
+ if(seat == m_Seats.begin())
+ seat = m_Seats.end();
+ --seat;
+ }
+ if(seat->first == seatId)
+ return -1; // no available seat
+ }
+ return seat->first;
+}
+
+void Vehicle::InstallAccessory(uint32 entry, int8 seatId)
+{
+ //Creature *accessory = SummonCreature(entry, GetPositionX(), GetPositionY(), GetPositionZ());
+ Creature *accessory = SummonVehicle(entry, GetPositionX(), GetPositionY(), GetPositionZ());
+ if(!accessory)
+ return;
+
+ accessory->m_Vehicle = this;
+ AddPassenger(accessory, seatId);
+}
+
+bool Vehicle::AddPassenger(Unit *unit, int8 seatId)
+{
+ if(unit->m_Vehicle != this)
+ return false;
+
+ SeatMap::iterator seat;
+ if(seatId < 0) // no specific seat requirement
+ {
+ for(seat = m_Seats.begin(); seat != m_Seats.end(); ++seat)
+ if(!seat->second.passenger && seat->second.seatInfo->IsUsable())
+ break;
+
+ if(seat == m_Seats.end()) // no available seat
+ return false;
+ }
+ else
+ {
+ seat = m_Seats.find(seatId);
+ if(seat == m_Seats.end())
+ return false;
+
+ if(seat->second.passenger)
+ seat->second.passenger->ExitVehicle();
+
+ assert(!seat->second.passenger);
+ }
+
+ sLog.outDebug("Unit %s enter vehicle entry %u id %u dbguid %u", unit->GetName(), GetEntry(), m_vehicleInfo->m_ID, GetDBTableGUIDLow());
+
+ seat->second.passenger = unit;
+ if(seat->second.seatInfo->IsUsable())
+ {
+ assert(m_usableSeatNum);
+ --m_usableSeatNum;
+ if(!m_usableSeatNum)
+ RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ }
+
+ //SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
+
+ unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ VehicleSeatEntry const *veSeat = seat->second.seatInfo;
+ unit->m_movementInfo.t_x = veSeat->m_attachmentOffsetX;
+ unit->m_movementInfo.t_y = veSeat->m_attachmentOffsetY;
+ unit->m_movementInfo.t_z = veSeat->m_attachmentOffsetZ;
+ unit->m_movementInfo.t_o = 0;
+ unit->m_movementInfo.t_time = 4;
+ unit->m_movementInfo.t_seat = seat->first;
+
+ unit->Relocate(GetPositionX() + unit->m_movementInfo.t_x,
+ GetPositionY() + unit->m_movementInfo.t_y,
+ GetPositionZ() + unit->m_movementInfo.t_z,
+ GetOrientation());
+
+ WorldPacket data;
+ if(unit->GetTypeId() == TYPEID_PLAYER)
+ {
+ //ChatHandler(player).PSendSysMessage("Enter seat %u %u", veSeat->m_ID, seat->first);
+
+ if(seat->first == 0 && seat->second.seatInfo->IsUsable()) // not right
+ {
+ ((Player*)unit)->SetCharm(this, true);
+ ((Player*)unit)->SetViewpoint(this, true);
+ ((Player*)unit)->VehicleSpellInitialize();
+ }
+
+ ((Player*)unit)->BuildTeleportAckMsg(&data, unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetOrientation());
+ ((Player*)unit)->GetSession()->SendPacket(&data);
+ }
+
+ unit->BuildHeartBeatMsg(&data);
+ unit->SendMessageToSet(&data, false);
+
+ return true;
+}
+
+void Vehicle::RemovePassenger(Unit *unit)
+{
+ if(unit->m_Vehicle != this)
+ return;
+
+ SeatMap::iterator seat;
+ for(seat = m_Seats.begin(); seat != m_Seats.end(); ++seat)
+ {
+ if(seat->second.passenger == unit)
+ {
+ seat->second.passenger = NULL;
+ if(seat->second.seatInfo->IsUsable())
+ {
+ if(!m_usableSeatNum)
+ SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ ++m_usableSeatNum;
+ }
+ break;
+ }
+ }
+
+ assert(seat != m_Seats.end());
+
+ sLog.outDebug("Unit %s exit vehicle entry %u id %u dbguid %u", unit->GetName(), GetEntry(), m_vehicleInfo->m_ID, GetDBTableGUIDLow());
+
+ //SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+
+ if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->IsUsable())
+ {
+ ((Player*)unit)->SetCharm(this, false);
+ ((Player*)unit)->SetViewpoint(this, false);
+ ((Player*)unit)->SendRemoveControlBar();
+ }
+
+ // only for flyable vehicles?
+ //CastSpell(this, 45472, true); // Parachute
+}
+
+void Vehicle::Dismiss()
+{
+ for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
+ {
+ if(Unit *passenger = itr->second.passenger)
+ if(passenger->GetTypeId() == TYPEID_UNIT && ((Creature*)passenger)->isVehicle())
+ {
+ passenger->ExitVehicle();
+ ((Vehicle*)passenger)->Dismiss();
+ }
+ }
+ RemoveAllPassengers();
+ SendObjectDeSpawnAnim(GetGUID());
+ CombatStop();
+ CleanupsBeforeDelete();
+ AddObjectToRemoveList();
+}
+
+bool Vehicle::LoadFromDB(uint32 guid, Map *map)
+{
+ CreatureData const* data = objmgr.GetCreatureData(guid);
+
+ if(!data)
+ {
+ sLog.outErrorDb("Creature (GUID: %u) not found in table `creature`, can't load. ",guid);
+ return false;
+ }
+
+ uint32 id = 0;
+ if(const CreatureInfo *cInfo = objmgr.GetCreatureTemplate(data->id))
+ id = cInfo->VehicleId;
+ if(!id || !sVehicleStore.LookupEntry(id))
+ return false;
+
+ m_DBTableGuid = guid;
+ if (map->GetInstanceId() != 0) guid = objmgr.GenerateLowGuid(HIGHGUID_VEHICLE);
+
+ uint16 team = 0;
+ if(!Create(guid,map,data->phaseMask,data->id,id,team,data))
+ return false;
+
+ Relocate(data->posX,data->posY,data->posZ,data->orientation);
+
+ if(!IsPositionValid())
+ {
+ sLog.outError("Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",GetGUIDLow(),GetEntry(),GetPositionX(),GetPositionY());
+ return false;
+ }
+ //We should set first home position, because then AI calls home movement
+ SetHomePosition(data->posX,data->posY,data->posZ,data->orientation);
+
+ m_respawnradius = data->spawndist;
+
+ m_respawnDelay = data->spawntimesecs;
+ m_isDeadByDefault = data->is_dead;
+ m_deathState = m_isDeadByDefault ? DEAD : ALIVE;
+
+ m_respawnTime = objmgr.GetCreatureRespawnTime(m_DBTableGuid,GetInstanceId());
+ if(m_respawnTime > time(NULL)) // not ready to respawn
+ {
+ m_deathState = DEAD;
+ if(canFly())
+ {
+ float tz = GetMap()->GetHeight(data->posX,data->posY,data->posZ,false);
+ if(data->posZ - tz > 0.1)
+ Relocate(data->posX,data->posY,tz);
+ }
+ }
+ else if(m_respawnTime) // respawn time set but expired
+ {
+ m_respawnTime = 0;
+ objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0);
+ }
+
+ uint32 curhealth = data->curhealth;
+ if(curhealth)
+ {
+ curhealth = uint32(curhealth*_GetHealthMod(GetCreatureInfo()->rank));
+ if(curhealth < 1)
+ curhealth = 1;
+ }
+
+ SetHealth(m_deathState == ALIVE ? curhealth : 0);
+ SetPower(POWER_MANA,data->curmana);
+
+ // checked at creature_template loading
+ m_defaultMovementType = MovementGeneratorType(data->movementType);
+
+ return true;
+}
diff --git a/src/game/Vehicle.h b/src/game/Vehicle.h
new file mode 100644
index 00000000000..083033c7574
--- /dev/null
+++ b/src/game/Vehicle.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MANGOSSERVER_VEHICLE_H
+#define MANGOSSERVER_VEHICLE_H
+
+#include "ObjectDefines.h"
+#include "Creature.h"
+#include "Unit.h"
+
+struct VehicleEntry;
+struct VehicleSeatEntry;
+
+struct VehicleSeat
+{
+ explicit VehicleSeat(VehicleSeatEntry const *_seatInfo) : seatInfo(_seatInfo), passenger(NULL) {}
+ VehicleSeatEntry const *seatInfo;
+ Unit* passenger;
+};
+
+typedef std::map<int8, VehicleSeat> SeatMap;
+
+class Vehicle : public Creature
+{
+ public:
+ explicit Vehicle();
+ virtual ~Vehicle();
+
+ void AddToWorld();
+ void RemoveFromWorld();
+
+ bool Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehicleId, uint32 team, const CreatureData * data = NULL);
+
+ void setDeathState(DeathState s); // overwrite virtual Creature::setDeathState and Unit::setDeathState
+ void Update(uint32 diff); // overwrite virtual Creature::Update and Unit::Update
+
+ VehicleEntry const *GetVehicleInfo() { return m_vehicleInfo; }
+ void SetVehicleId(uint32 vehicleid);
+
+ bool HasEmptySeat(int8 seatId) const;
+ int8 GetNextEmptySeat(int8 seatId, bool next) const;
+ bool AddPassenger(Unit *passenger, int8 seatId = -1);
+ void RemovePassenger(Unit *passenger);
+ void InstallAccessory(uint32 entry, int8 seatId);
+ void Dismiss();
+
+ bool LoadFromDB(uint32 guid, Map *map);
+
+ SeatMap m_Seats;
+ protected:
+ VehicleEntry const *m_vehicleInfo;
+ uint32 m_usableSeatNum;
+
+ void RemoveAllPassengers();
+
+ private:
+ void SaveToDB(uint32, uint8) // overwrited of Creature::SaveToDB - don't must be called
+ {
+ assert(false);
+ }
+ void DeleteFromDB() // overwrited of Creature::DeleteFromDB - don't must be called
+ {
+ assert(false);
+ }
+};
+#endif
diff --git a/src/game/VoiceChatHandler.cpp b/src/game/VoiceChatHandler.cpp
index ba03ee1c543..8e787549e33 100644
--- a/src/game/VoiceChatHandler.cpp
+++ b/src/game/VoiceChatHandler.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "World.h"
#include "Opcodes.h"
#include "Log.h"
diff --git a/src/game/WaypointManager.cpp b/src/game/WaypointManager.cpp
index 30947abe4c8..26be14d89fa 100644
--- a/src/game/WaypointManager.cpp
+++ b/src/game/WaypointManager.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,12 +24,12 @@
#include "ProgressBar.h"
#include "MapManager.h"
-UNORDERED_MAP<uint32, WaypointPath*> waypoint_map;
+WaypointPathMap WaypointPathHolder;
WaypointStore WaypointMgr;
void WaypointStore::Free()
{
- waypoint_map.clear();
+ WaypointPathHolder.clear();
}
void WaypointStore::Load()
@@ -37,7 +37,7 @@ void WaypointStore::Load()
QueryResult *result = WorldDatabase.PQuery("SELECT MAX(`id`) FROM `waypoint_data`");
if(!result)
{
- sLog.outError(" an error occured while loading the table `waypoint_data` ( maybe it doesn't exist ?)\n");
+ sLog.outError("an error occured while loading the table `waypoint_data` (maybe it doesn't exist ?)");
exit(1); // Stop server at loading non exited table or not accessable table
}
@@ -47,7 +47,7 @@ void WaypointStore::Load()
result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`action`,`action_chance` FROM `waypoint_data` ORDER BY `id`, `point`");
if(!result)
{
- sLog.outErrorDb("The table `creature_addon` is empty or corrupted");
+ sLog.outErrorDb("The table `waypoint_data` is empty or corrupted");
return;
}
@@ -87,22 +87,21 @@ void WaypointStore::Load()
path_data->push_back(wp);
- if(id != last_id)
- waypoint_map[id] = path_data;
+ if(id != last_id)
+ WaypointPathHolder[id] = path_data;
last_id = id;
} while(result->NextRow()) ;
-
delete result;
}
void WaypointStore::UpdatePath(uint32 id)
{
-
- if(waypoint_map.find(id)!= waypoint_map.end())
- waypoint_map[id]->clear();
+ // TODO: this will cause memory leak
+ if(WaypointPathHolder.find(id) != WaypointPathHolder.end())
+ WaypointPathHolder[id]->clear();
QueryResult *result;
@@ -145,7 +144,7 @@ void WaypointStore::UpdatePath(uint32 id)
}while (result->NextRow());
- waypoint_map[id] = path_data;
+ WaypointPathHolder[id] = path_data;
delete result;
}
diff --git a/src/game/WaypointManager.h b/src/game/WaypointManager.h
index 1c41617fff7..a8f2d5746e9 100644
--- a/src/game/WaypointManager.h
+++ b/src/game/WaypointManager.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,7 +34,9 @@ struct WaypointData
};
typedef std::vector<WaypointData*> WaypointPath;
-extern UNORDERED_MAP<uint32, WaypointPath*> waypoint_map;
+typedef UNORDERED_MAP<uint32, WaypointPath*> WaypointPathMap;
+
+extern WaypointPathMap WaypointPathHolder;
class WaypointStore
{
@@ -48,9 +50,10 @@ class WaypointStore
WaypointPath* GetPath(uint32 id)
{
- if(waypoint_map.find(id) != waypoint_map.end())
- return waypoint_map[id];
- else return 0;
+ WaypointPathMap::iterator itr = WaypointPathHolder.find(id);
+ if(itr != WaypointPathHolder.end())
+ return itr->second;
+ return NULL;
}
inline uint32 GetRecordsCount() { return records; }
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp
index f3702c1bc99..49d38799fe3 100644
--- a/src/game/WaypointMovementGenerator.cpp
+++ b/src/game/WaypointMovementGenerator.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
//Creature-specific headers
#include "Creature.h"
#include "CreatureAI.h"
+#include "CreatureGroups.h"
//Player-specific
#include "Player.h"
@@ -54,7 +55,7 @@ bool WaypointMovementGenerator<Creature>::GetDestination(float &x, float &y, flo
{
if(i_destinationHolder.HasArrived())
return false;
-
+
i_destinationHolder.GetDestination(x, y, z);
return true;
}
@@ -99,7 +100,7 @@ WaypointMovementGenerator<Creature>::Initialize(Creature &u)
//i_nextMoveTime.Reset(0);
StopedByPlayer = false;
if(!path_id)
- path_id = u.GetWaypointPath();
+ path_id = u.GetWaypointPathId();
waypoints = WaypointMgr.GetPath(path_id);
i_currentNode = 0;
if(waypoints && waypoints->size())
@@ -109,6 +110,10 @@ WaypointMovementGenerator<Creature>::Initialize(Creature &u)
InitTraveller(u, *node);
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
+
+ //Call for creature group update
+ if(u.GetFormation() && u.GetFormation()->getLeader() == &u)
+ u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
}
else
node = NULL;
@@ -180,6 +185,10 @@ WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
InitTraveller(unit, *node);
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
+
+ //Call for creature group update
+ if(unit.GetFormation() && unit.GetFormation()->getLeader() == &unit)
+ unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
}
else
{
@@ -217,14 +226,12 @@ template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32 &
template void WaypointMovementGenerator<Player>::MovementInform(Player &);
//----------------------------------------------------//
-void
-FlightPathMovementGenerator::LoadPath(Player &)
+void FlightPathMovementGenerator::SetWaypointPathId(Player &)
{
objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds);
}
-uint32
-FlightPathMovementGenerator::GetPathAtMapEnd() const
+uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
{
if(i_currentNode >= i_mapIds.size())
return i_mapIds.size();
@@ -239,13 +246,12 @@ FlightPathMovementGenerator::GetPathAtMapEnd() const
return i_mapIds.size();
}
-void
-FlightPathMovementGenerator::Initialize(Player &player)
+void FlightPathMovementGenerator::Initialize(Player &player)
{
player.getHostilRefManager().setOnlineOfflineState(false);
player.addUnitState(UNIT_STAT_IN_FLIGHT);
player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
- LoadPath(player);
+ SetWaypointPathId(player);
Traveller<Player> traveller(player);
// do not send movement, it was sent already
i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
@@ -255,28 +261,14 @@ FlightPathMovementGenerator::Initialize(Player &player)
void FlightPathMovementGenerator::Finalize(Player & player)
{
+ player.clearUnitState(UNIT_STAT_IN_FLIGHT);
float x, y, z;
i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z);
player.SetPosition(x, y, z, player.GetOrientation());
-
- player.clearUnitState(UNIT_STAT_IN_FLIGHT);
- player.Unmount();
- player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
-
- if(player.m_taxi.empty())
- {
- player.getHostilRefManager().setOnlineOfflineState(true);
- if(player.pvpInfo.inHostileArea)
- player.CastSpell(&player, 2479, true);
-
- player.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE);
- player.StopMoving();
- }
}
-bool
-FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
+bool FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
{
if( MovementInProgress() )
{
@@ -311,8 +303,7 @@ FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
return false;
}
-void
-FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
+void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
{
if(i_mapIds.empty())
return;
@@ -481,7 +472,7 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
break;
}
- for (i = 0; i < nodes[atNode].enodenum; i++) //loop through all the links for this node
+ for (i = 0; i < nodes[atNode].enodenum; ++i) //loop through all the links for this node
{
newnode = nodes[atNode].links[i].targetNode;
@@ -539,7 +530,7 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
parent[newnode] = atNode; //set the new parent for this node
gcost[newnode] = gc; //and the new g cost
- for (i = 1; i < numOpen; i++) //loop through all the items on the open list
+ for (i = 1; i < numOpen; ++i) //loop through all the items on the open list
{
if (openlist[i] == newnode) //find this node in the list
{
diff --git a/src/game/WaypointMovementGenerator.h b/src/game/WaypointMovementGenerator.h
index eec6ad70e5c..9c93486a675 100644
--- a/src/game/WaypointMovementGenerator.h
+++ b/src/game/WaypointMovementGenerator.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,9 +48,9 @@ class TRINITY_DLL_SPEC PathMovementBase
PathMovementBase() : i_currentNode(0) {}
virtual ~PathMovementBase() {};
- inline bool MovementInProgress(void) const { return i_currentNode < i_path.Size(); }
+ bool MovementInProgress(void) const { return i_currentNode < i_path.Size(); }
- void LoadPath(T &);
+ void SetWaypointPathId(T &);
void ReloadPath(T &);
uint32 GetCurrentNode() const { return i_currentNode; }
@@ -104,12 +104,12 @@ public PathMovementBase<Player>
bool Update(Player &, const uint32 &);
MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
- void LoadPath(Player &);
+ void SetWaypointPathId(Player &);
void ReloadPath(Player &) { /* don't reload flight path */ }
Path& GetPath() { return i_path; }
uint32 GetPathAtMapEnd() const;
- inline bool HasArrived() const { return (i_currentNode >= i_path.Size()); }
+ bool HasArrived() const { return (i_currentNode >= i_path.Size()); }
void SetCurrentNodeAfterTeleport();
void SkipCurrentNode() { ++i_currentNode; }
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; }
diff --git a/src/game/Weather.cpp b/src/game/Weather.cpp
index 498beab0412..5d8d1fbd9ba 100644
--- a/src/game/Weather.cpp
+++ b/src/game/Weather.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
#include "Weather.h"
#include "WorldPacket.h"
-#include "WorldSession.h"
#include "Player.h"
#include "World.h"
#include "Log.h"
@@ -38,11 +37,11 @@ Weather::Weather(uint32 zone, WeatherZoneChances const* weatherChances) : m_zone
m_type = WEATHER_TYPE_FINE;
m_grade = 0;
- sLog.outDetail("WORLD: Starting weather system for zone %u (change every %u minutes).", m_zone, (uint32)(m_timer.GetInterval() / (1000*MINUTE)) );
+ sLog.outDetail("WORLD: Starting weather system for zone %u (change every %u minutes).", m_zone, (uint32)(m_timer.GetInterval() / (MINUTE*IN_MILISECONDS)) );
}
/// Launch a weather update
-bool Weather::Update(time_t diff)
+bool Weather::Update(uint32 diff)
{
if (m_timer.GetCurrent()>=0)
m_timer.Update(diff);
diff --git a/src/game/Weather.h b/src/game/Weather.h
index cbd4daad1ad..e312f004060 100644
--- a/src/game/Weather.h
+++ b/src/game/Weather.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -62,7 +62,7 @@ class Weather
void SetWeather(WeatherType type, float grade);
/// For which zone is this weather?
uint32 GetZone() { return m_zone; };
- bool Update(time_t diff);
+ bool Update(uint32 diff);
private:
WeatherState GetWeatherState() const;
uint32 m_zone;
diff --git a/src/game/Wintergrasp.cpp b/src/game/Wintergrasp.cpp
new file mode 100644
index 00000000000..0103b32b35d
--- /dev/null
+++ b/src/game/Wintergrasp.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Wintergrasp.h"
+#include "SpellAuras.h"
+#include "Vehicle.h"
+
+bool OPvPWintergrasp::SetupOutdoorPvP()
+{
+ RegisterZone(ZONE_WINTERGRASP);
+
+ for(uint32 i = 0; i < sAreaPOIStore.GetNumRows(); ++i)
+ {
+ const AreaPOIEntry * poiInfo = sAreaPOIStore.LookupEntry(i);
+ if(poiInfo && poiInfo->zoneId == ZONE_WINTERGRASP)
+ areaPOIs.push_back(poiInfo);
+ }
+
+ m_defender = TeamId(rand()%2);
+
+ return true;
+}
+
+void OPvPWintergrasp::HandlePlayerEnterZone(Player * plr, uint32 zone)
+{
+ if(!plr->HasAura(SPELL_RECRUIT) && !plr->HasAura(SPELL_CORPORAL)
+ && !plr->HasAura(SPELL_LIEUTENANT))
+ plr->CastSpell(plr, SPELL_RECRUIT, true);
+
+ for(AreaPOIList::iterator itr = areaPOIs.begin(); itr != areaPOIs.end(); ++itr)
+ {
+ TeamId team = ((*itr)->x > POS_X_CENTER ? m_defender : OTHER_TEAM(m_defender));
+ plr->SendUpdateWorldState((*itr)->worldState, AreaPOIIconId[team][DAMAGE_INTACT]);
+ }
+
+ OutdoorPvP::HandlePlayerEnterZone(plr, zone);
+ UpdateTenacityStack();
+}
+
+void OPvPWintergrasp::HandlePlayerLeaveZone(Player * plr, uint32 zone)
+{
+ if(!plr->GetSession()->PlayerLogout() && plr->m_Vehicle) // dismiss in change zone case
+ plr->m_Vehicle->Dismiss();
+ plr->RemoveAura(SPELL_TENACITY);
+ OutdoorPvP::HandlePlayerLeaveZone(plr, zone);
+ UpdateTenacityStack();
+}
+
+void OPvPWintergrasp::HandleKill(Player *killer, Unit *victim)
+{
+ if(victim->GetTypeId() == TYPEID_PLAYER)
+ {
+ // We handle promotion here because player should not get promotion if he has buff but do the kill outside the zone
+ if(victim->getLevel() >= 70)
+ {
+ if(Aura *aur = killer->GetAura(SPELL_RECRUIT))
+ {
+ if(aur->GetStackAmount() >= 5)
+ {
+ killer->RemoveAura(SPELL_RECRUIT);
+ killer->CastSpell(killer, SPELL_CORPORAL, true);
+ }
+ else
+ killer->CastSpell(killer, SPELL_RECRUIT, true);
+ }
+ else if(Aura *aur = killer->GetAura(SPELL_CORPORAL))
+ {
+ if(aur->GetStackAmount() >= 5)
+ {
+ killer->RemoveAura(SPELL_CORPORAL);
+ killer->CastSpell(killer, SPELL_LIEUTENANT, true);
+ }
+ else
+ killer->CastSpell(killer, SPELL_CORPORAL, true);
+ }
+ else if(killer->HasAura(SPELL_LIEUTENANT))
+ killer->CastSpell(killer, SPELL_LIEUTENANT, true);
+ }
+ }
+}
+
+void OPvPWintergrasp::UpdateTenacityStack()
+{
+ uint32 allianceNum = m_players[TEAM_ALLIANCE].size();
+ uint32 hordeNum = m_players[TEAM_HORDE].size();
+
+ int32 newStack = 0;
+ if(allianceNum && hordeNum)
+ {
+ if(allianceNum > hordeNum)
+ newStack = allianceNum / hordeNum - 1;
+ else if(allianceNum < hordeNum)
+ newStack = 1 - int32(hordeNum / allianceNum);
+ }
+
+ if(newStack == m_tenacityStack)
+ return;
+
+ // Remove old buff
+ if(m_tenacityStack > 0)
+ {
+ if(newStack <= 0)
+ TeamCastSpell(TEAM_ALLIANCE, -SPELL_TENACITY);
+ }
+ else if(m_tenacityStack < 0)
+ {
+ if(newStack >= 0)
+ TeamCastSpell(TEAM_HORDE, -SPELL_TENACITY);
+ }
+ m_tenacityStack = newStack;
+
+ // Apply new buff
+ if(newStack)
+ {
+ TeamId team = newStack > 0 ? TEAM_ALLIANCE : TEAM_HORDE;
+ for(PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
+ (*itr)->SetAuraStack(SPELL_TENACITY, *itr, newStack);
+ }
+}
diff --git a/src/game/Wintergrasp.h b/src/game/Wintergrasp.h
new file mode 100644
index 00000000000..e95b7884efb
--- /dev/null
+++ b/src/game/Wintergrasp.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITY_WINTERGRASP_H
+#define TRINITY_WINTERGRASP_H
+
+#include "OutdoorPvPImpl.h"
+
+#define ZONE_WINTERGRASP 4197
+
+#define POS_X_CENTER 4700
+
+#define SPELL_RECRUIT 37795
+#define SPELL_CORPORAL 33280
+#define SPELL_LIEUTENANT 55629
+
+#define SPELL_TENACITY 58549
+#define SPELL_TENACITY_VEHICLE 59911
+
+enum DamageState
+{
+ DAMAGE_INTACT,
+ DAMAGE_DAMAGED,
+ DAMAGE_DESTROYED,
+};
+
+const uint32 AreaPOIIconId[3][3] = {{7,8,9},{4,5,6},{1,2,3}};
+
+struct BuildingState
+{
+ explicit BuildingState(uint32 _worldState, uint32 _health)
+ : worldState(_worldState), health(_health), team(TEAM_NEUTRAL), damageState(DAMAGE_INTACT)
+ {}
+ uint32 worldState;
+ uint32 health;
+ TeamId team;
+ DamageState damageState;
+};
+
+class OPvPWintergrasp : public OutdoorPvP
+{
+ protected:
+ typedef std::list<const AreaPOIEntry *> AreaPOIList;
+ typedef std::map<uint32, BuildingState *> BuildingStateMap;
+ public:
+ explicit OPvPWintergrasp() : m_tenacityStack(0) {}
+ bool SetupOutdoorPvP();
+ void HandlePlayerEnterZone(Player *plr, uint32 zone);
+ void HandlePlayerLeaveZone(Player *plr, uint32 zone);
+ void HandleKill(Player *killer, Unit *victim);
+ protected:
+ TeamId m_defender;
+ int32 m_tenacityStack;
+ AreaPOIList areaPOIs;
+ BuildingStateMap buildingStates;
+
+ void UpdateTenacityStack();
+};
+
+#endif
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 7517fb0b96d..ad6e54a64cf 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@
*/
#include "Common.h"
-//#include "WorldSocket.h"
#include "Database/DatabaseEnv.h"
#include "Config/ConfigEnv.h"
#include "SystemConfig.h"
@@ -33,15 +32,18 @@
#include "WorldPacket.h"
#include "Weather.h"
#include "Player.h"
+#include "Vehicle.h"
#include "SkillExtraItems.h"
#include "SkillDiscovery.h"
#include "World.h"
#include "AccountMgr.h"
+#include "AchievementMgr.h"
#include "AuctionHouseMgr.h"
#include "ObjectMgr.h"
+#include "CreatureEventAIMgr.h"
#include "SpellMgr.h"
#include "Chat.h"
-#include "Database/DBCStores.h"
+#include "DBCStores.h"
#include "LootMgr.h"
#include "ItemEnchantmentMgr.h"
#include "MapManager.h"
@@ -55,7 +57,8 @@
#include "WaypointMovementGenerator.h"
#include "VMapFactory.h"
#include "GlobalEvents.h"
-#include "GameEvent.h"
+#include "GameEventMgr.h"
+#include "PoolHandler.h"
#include "Database/DatabaseImpl.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
@@ -81,16 +84,6 @@ float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
float World::m_VisibleUnitGreyDistance = 0;
float World::m_VisibleObjectGreyDistance = 0;
-// ServerMessages.dbc
-enum ServerMessageType
-{
- SERVER_MSG_SHUTDOWN_TIME = 1,
- SERVER_MSG_RESTART_TIME = 2,
- SERVER_MSG_STRING = 3,
- SERVER_MSG_SHUTDOWN_CANCELLED = 4,
- SERVER_MSG_RESTART_CANCELLED = 5
-};
-
struct ScriptAction
{
uint64 sourceGUID;
@@ -118,6 +111,8 @@ World::World()
m_updateTimeSum = 0;
m_updateTimeCount = 0;
+
+ m_isClosed = false;
}
/// World destructor
@@ -132,7 +127,7 @@ World::~World()
}
///- Empty the WeatherMap
- for (WeatherMap::iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr)
+ for (WeatherMap::const_iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr)
delete itr->second;
m_weathers.clear();
@@ -151,7 +146,7 @@ World::~World()
Player* World::FindPlayerInZone(uint32 zone)
{
///- circle through active sessions and return the first player found in the zone
- SessionMap::iterator itr;
+ SessionMap::const_iterator itr;
for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if(!itr->second)
@@ -183,7 +178,7 @@ WorldSession* World::FindSession(uint32 id) const
bool World::RemoveSession(uint32 id)
{
///- Find the session, kick the user, but we can't delete session at this moment to prevent iterator invalidation
- SessionMap::iterator itr = m_sessions.find(id);
+ SessionMap::const_iterator itr = m_sessions.find(id);
if(itr != m_sessions.end() && itr->second)
{
@@ -238,7 +233,7 @@ World::AddSession_ (WorldSession* s)
uint32 Sessions = GetActiveAndQueuedSessionCount ();
uint32 pLimit = GetPlayerAmountLimit ();
- uint32 QueueSize = GetQueueSize (); //number of players in the queue
+ uint32 QueueSize = GetQueueSize (); //number of players in the queue
//so we don't count the user trying to
//login as a session and queue the socket that we are using
@@ -255,18 +250,19 @@ World::AddSession_ (WorldSession* s)
WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1);
packet << uint8 (AUTH_OK);
- packet << uint32 (0); // unknown random value...
- packet << uint8 (0);
- packet << uint32 (0);
- packet << uint8 (s->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
+ packet << uint32 (0); // BillingTimeRemaining
+ packet << uint8 (0); // BillingPlanFlags
+ packet << uint32 (0); // BillingTimeRested
+ packet << uint8 (s->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
s->SendPacket (&packet);
+ s->SendAddonsInfo();
UpdateMaxSessionCounters ();
// Updates the population
if (pLimit > 0)
{
- float popu = GetActiveSessionCount (); //updated number of users on the server
+ float popu = GetActiveSessionCount (); //updated number of users on the server
popu /= pLimit;
popu *= 2;
LoginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
@@ -280,12 +276,13 @@ bool World::HasRecentlyDisconnected(WorldSession* session)
if(uint32 tolerance = getConfig(CONFIG_INTERVAL_DISCONNECT_TOLERANCE))
{
- for(DisconnectMap::iterator i = m_disconnects.begin(); i != m_disconnects.end(); ++i)
+ for(DisconnectMap::iterator i = m_disconnects.begin(); i != m_disconnects.end(); )
{
if(difftime(i->second, time(NULL)) < tolerance)
{
if(i->first == session->GetAccountId())
return true;
+ ++i;
}
else
m_disconnects.erase(i);
@@ -298,7 +295,7 @@ int32 World::GetQueuePos(WorldSession* sess)
{
uint32 position = 1;
- for(Queue::iterator iter = m_QueuedPlayer.begin(); iter != m_QueuedPlayer.end(); ++iter, ++position)
+ for(Queue::const_iterator iter = m_QueuedPlayer.begin(); iter != m_QueuedPlayer.end(); ++iter, ++position)
if((*iter) == sess)
return position;
@@ -313,10 +310,10 @@ void World::AddQueuedPlayer(WorldSession* sess)
// The 1st SMSG_AUTH_RESPONSE needs to contain other info too.
WorldPacket packet (SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1);
packet << uint8 (AUTH_WAIT_QUEUE);
- packet << uint32 (0); // unknown random value...
- packet << uint8 (0);
- packet << uint32 (0);
- packet << uint8 (sess->Expansion () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account
+ packet << uint32 (0); // BillingTimeRemaining
+ packet << uint8 (0); // BillingPlanFlags
+ packet << uint32 (0); // BillingTimeRested
+ packet << uint8 (sess->Expansion () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account
packet << uint32(GetQueuePos (sess));
sess->SendPacket (&packet);
@@ -440,24 +437,30 @@ void World::LoadConfigSettings(bool reload)
rate_values[RATE_HEALTH] = sConfig.GetFloatDefault("Rate.Health", 1);
if(rate_values[RATE_HEALTH] < 0)
{
- sLog.outError("Rate.Health (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_HEALTH]);
+ sLog.outError("Rate.Health (%f) must be > 0. Using 1 instead.",rate_values[RATE_HEALTH]);
rate_values[RATE_HEALTH] = 1;
}
rate_values[RATE_POWER_MANA] = sConfig.GetFloatDefault("Rate.Mana", 1);
if(rate_values[RATE_POWER_MANA] < 0)
{
- sLog.outError("Rate.Mana (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_POWER_MANA]);
+ sLog.outError("Rate.Mana (%f) must be > 0. Using 1 instead.",rate_values[RATE_POWER_MANA]);
rate_values[RATE_POWER_MANA] = 1;
}
rate_values[RATE_POWER_RAGE_INCOME] = sConfig.GetFloatDefault("Rate.Rage.Income", 1);
rate_values[RATE_POWER_RAGE_LOSS] = sConfig.GetFloatDefault("Rate.Rage.Loss", 1);
if(rate_values[RATE_POWER_RAGE_LOSS] < 0)
{
- sLog.outError("Rate.Rage.Loss (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_POWER_RAGE_LOSS]);
+ sLog.outError("Rate.Rage.Loss (%f) must be > 0. Using 1 instead.",rate_values[RATE_POWER_RAGE_LOSS]);
rate_values[RATE_POWER_RAGE_LOSS] = 1;
}
+ rate_values[RATE_POWER_RUNICPOWER_INCOME] = sConfig.GetFloatDefault("Rate.RunicPower.Income", 1);
+ rate_values[RATE_POWER_RUNICPOWER_LOSS] = sConfig.GetFloatDefault("Rate.RunicPower.Loss", 1);
+ if(rate_values[RATE_POWER_RUNICPOWER_LOSS] < 0)
+ {
+ sLog.outError("Rate.RunicPower.Loss (%f) must be > 0. Using 1 instead.",rate_values[RATE_POWER_RUNICPOWER_LOSS]);
+ rate_values[RATE_POWER_RUNICPOWER_LOSS] = 1;
+ }
rate_values[RATE_POWER_FOCUS] = sConfig.GetFloatDefault("Rate.Focus", 1.0f);
- rate_values[RATE_LOYALTY] = sConfig.GetFloatDefault("Rate.Loyalty", 1.0f);
rate_values[RATE_SKILL_DISCOVERY] = sConfig.GetFloatDefault("Rate.Skill.Discovery", 1.0f);
rate_values[RATE_DROP_ITEM_POOR] = sConfig.GetFloatDefault("Rate.Drop.Item.Poor", 1.0f);
rate_values[RATE_DROP_ITEM_NORMAL] = sConfig.GetFloatDefault("Rate.Drop.Item.Normal", 1.0f);
@@ -471,8 +474,9 @@ void World::LoadConfigSettings(bool reload)
rate_values[RATE_XP_KILL] = sConfig.GetFloatDefault("Rate.XP.Kill", 1.0f);
rate_values[RATE_XP_QUEST] = sConfig.GetFloatDefault("Rate.XP.Quest", 1.0f);
rate_values[RATE_XP_EXPLORE] = sConfig.GetFloatDefault("Rate.XP.Explore", 1.0f);
- rate_values[RATE_XP_PAST_70] = sConfig.GetFloatDefault("Rate.XP.PastLevel70", 1.0f);
rate_values[RATE_REPUTATION_GAIN] = sConfig.GetFloatDefault("Rate.Reputation.Gain", 1.0f);
+ rate_values[RATE_REPUTATION_LOWLEVEL_KILL] = sConfig.GetFloatDefault("Rate.Reputation.LowLevel.Kill", 1.0f);
+ rate_values[RATE_REPUTATION_LOWLEVEL_QUEST] = sConfig.GetFloatDefault("Rate.Reputation.LowLevel.Quest", 1.0f);
rate_values[RATE_CREATURE_NORMAL_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Normal.Damage", 1.0f);
rate_values[RATE_CREATURE_ELITE_ELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.Damage", 1.0f);
rate_values[RATE_CREATURE_ELITE_RAREELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.Damage", 1.0f);
@@ -556,10 +560,10 @@ void World::LoadConfigSettings(bool reload)
}
m_configs[CONFIG_ADDON_CHANNEL] = sConfig.GetBoolDefault("AddonChannel", true);
m_configs[CONFIG_GRID_UNLOAD] = sConfig.GetBoolDefault("GridUnload", true);
- m_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 900000);
+ m_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 15 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_INTERVAL_DISCONNECT_TOLERANCE] = sConfig.GetIntDefault("DisconnectToleranceInterval", 0);
- m_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfig.GetIntDefault("GridCleanUpDelay", 300000);
+ m_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfig.GetIntDefault("GridCleanUpDelay", 5 * MINUTE * IN_MILISECONDS);
if(m_configs[CONFIG_INTERVAL_GRIDCLEAN] < MIN_GRID_DELAY)
{
sLog.outError("GridCleanUpDelay (%i) must be greater %u. Use this minimal value.",m_configs[CONFIG_INTERVAL_GRIDCLEAN],MIN_GRID_DELAY);
@@ -577,7 +581,7 @@ void World::LoadConfigSettings(bool reload)
if(reload)
MapManager::Instance().SetMapUpdateInterval(m_configs[CONFIG_INTERVAL_MAPUPDATE]);
- m_configs[CONFIG_INTERVAL_CHANGEWEATHER] = sConfig.GetIntDefault("ChangeWeatherInterval", 600000);
+ m_configs[CONFIG_INTERVAL_CHANGEWEATHER] = sConfig.GetIntDefault("ChangeWeatherInterval", 10 * MINUTE * IN_MILISECONDS);
if(reload)
{
@@ -592,7 +596,7 @@ void World::LoadConfigSettings(bool reload)
{
uint32 val = sConfig.GetIntDefault("SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME);
if(val!=m_configs[CONFIG_SOCKET_SELECTTIME])
- sLog.outError("SocketSelectTime option can't be changed at Trinityd.conf reload, using current value (%u).",m_configs[DEFAULT_SOCKET_SELECT_TIME]);
+ sLog.outError("SocketSelectTime option can't be changed at Trinityd.conf reload, using current value (%u).",m_configs[CONFIG_SOCKET_SELECTTIME]);
}
else
m_configs[CONFIG_SOCKET_SELECTTIME] = sConfig.GetIntDefault("SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME);
@@ -620,21 +624,21 @@ void World::LoadConfigSettings(bool reload)
else
m_configs[CONFIG_REALM_ZONE] = sConfig.GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT);
- m_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = sConfig.GetBoolDefault("AllowTwoSide.Accounts", false);
+ m_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = sConfig.GetBoolDefault("AllowTwoSide.Accounts", false);
m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Chat",false);
m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Channel",false);
m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Group",false);
m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Guild",false);
m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Auction",false);
m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Mail",false);
- m_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfig.GetBoolDefault("AllowTwoSide.WhoList", false);
- m_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = sConfig.GetBoolDefault("AllowTwoSide.AddFriend", false);
- m_configs[CONFIG_ALLOW_TWO_SIDE_TRADE] = sConfig.GetBoolDefault("AllowTwoSide.trade", false);
- m_configs[CONFIG_STRICT_PLAYER_NAMES] = sConfig.GetIntDefault("StrictPlayerNames", 0);
- m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault("StrictCharterNames", 0);
- m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault("StrictPetNames", 0);
+ m_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfig.GetBoolDefault("AllowTwoSide.WhoList", false);
+ m_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = sConfig.GetBoolDefault("AllowTwoSide.AddFriend", false);
+ m_configs[CONFIG_ALLOW_TWO_SIDE_TRADE] = sConfig.GetBoolDefault("AllowTwoSide.trade", false);
+ m_configs[CONFIG_STRICT_PLAYER_NAMES] = sConfig.GetIntDefault ("StrictPlayerNames", 0);
+ m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault ("StrictCharterNames", 0);
+ m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault ("StrictPetNames", 0);
- m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault("CharactersCreatingDisabled", 0);
+ m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault ("CharactersCreatingDisabled", 0);
m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10);
if(m_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_configs[CONFIG_CHARACTERS_PER_REALM] > 10)
@@ -651,8 +655,17 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] = m_configs[CONFIG_CHARACTERS_PER_REALM];
}
+ m_configs[CONFIG_HEROIC_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("HeroicCharactersPerRealm", 1);
+ if(int32(m_configs[CONFIG_HEROIC_CHARACTERS_PER_REALM]) < 0 || m_configs[CONFIG_HEROIC_CHARACTERS_PER_REALM] > 10)
+ {
+ sLog.outError("HeroicCharactersPerRealm (%i) must be in range 0..10. Set to 1.",m_configs[CONFIG_HEROIC_CHARACTERS_PER_REALM]);
+ m_configs[CONFIG_HEROIC_CHARACTERS_PER_REALM] = 1;
+ }
+
+ m_configs[CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING] = sConfig.GetIntDefault("MinLevelForHeroicCharacterCreating", 55);
+
m_configs[CONFIG_SKIP_CINEMATICS] = sConfig.GetIntDefault("SkipCinematics", 0);
- if(m_configs[CONFIG_SKIP_CINEMATICS] < 0 || m_configs[CONFIG_SKIP_CINEMATICS] > 2)
+ if(int32(m_configs[CONFIG_SKIP_CINEMATICS]) < 0 || m_configs[CONFIG_SKIP_CINEMATICS] > 2)
{
sLog.outError("SkipCinematics (%i) must be in range 0..2. Set to 0.",m_configs[CONFIG_SKIP_CINEMATICS]);
m_configs[CONFIG_SKIP_CINEMATICS] = 0;
@@ -660,12 +673,12 @@ void World::LoadConfigSettings(bool reload)
if(reload)
{
- uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", 60);
+ uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", 80);
if(val!=m_configs[CONFIG_MAX_PLAYER_LEVEL])
sLog.outError("MaxPlayerLevel option can't be changed at config reload, using current value (%u).",m_configs[CONFIG_MAX_PLAYER_LEVEL]);
}
else
- m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", 60);
+ m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", 80);
if(m_configs[CONFIG_MAX_PLAYER_LEVEL] > MAX_LEVEL)
{
@@ -685,8 +698,22 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_START_PLAYER_LEVEL] = m_configs[CONFIG_MAX_PLAYER_LEVEL];
}
+ m_configs[CONFIG_START_HEROIC_PLAYER_LEVEL] = sConfig.GetIntDefault("StartHeroicPlayerLevel", 55);
+ if(m_configs[CONFIG_START_HEROIC_PLAYER_LEVEL] < 1)
+ {
+ sLog.outError("StartHeroicPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to 55.",
+ m_configs[CONFIG_START_HEROIC_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]);
+ m_configs[CONFIG_START_HEROIC_PLAYER_LEVEL] = 55;
+ }
+ else if(m_configs[CONFIG_START_HEROIC_PLAYER_LEVEL] > m_configs[CONFIG_MAX_PLAYER_LEVEL])
+ {
+ sLog.outError("StartHeroicPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to %u.",
+ m_configs[CONFIG_START_HEROIC_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]);
+ m_configs[CONFIG_START_HEROIC_PLAYER_LEVEL] = m_configs[CONFIG_MAX_PLAYER_LEVEL];
+ }
+
m_configs[CONFIG_START_PLAYER_MONEY] = sConfig.GetIntDefault("StartPlayerMoney", 0);
- if(m_configs[CONFIG_START_PLAYER_MONEY] < 0)
+ if(int32(m_configs[CONFIG_START_PLAYER_MONEY]) < 0)
{
sLog.outError("StartPlayerMoney (%i) must be in range 0..%u. Set to %u.",m_configs[CONFIG_START_PLAYER_MONEY],MAX_MONEY_AMOUNT,0);
m_configs[CONFIG_START_PLAYER_MONEY] = 0;
@@ -699,18 +726,18 @@ void World::LoadConfigSettings(bool reload)
}
m_configs[CONFIG_MAX_HONOR_POINTS] = sConfig.GetIntDefault("MaxHonorPoints", 75000);
- if(m_configs[CONFIG_MAX_HONOR_POINTS] < 0)
+ if(int32(m_configs[CONFIG_MAX_HONOR_POINTS]) < 0)
{
sLog.outError("MaxHonorPoints (%i) can't be negative. Set to 0.",m_configs[CONFIG_MAX_HONOR_POINTS]);
m_configs[CONFIG_MAX_HONOR_POINTS] = 0;
}
m_configs[CONFIG_START_HONOR_POINTS] = sConfig.GetIntDefault("StartHonorPoints", 0);
- if(m_configs[CONFIG_START_HONOR_POINTS] < 0)
+ if(int32(m_configs[CONFIG_START_HONOR_POINTS]) < 0)
{
sLog.outError("StartHonorPoints (%i) must be in range 0..MaxHonorPoints(%u). Set to %u.",
m_configs[CONFIG_START_HONOR_POINTS],m_configs[CONFIG_MAX_HONOR_POINTS],0);
- m_configs[CONFIG_MAX_HONOR_POINTS] = 0;
+ m_configs[CONFIG_START_HONOR_POINTS] = 0;
}
else if(m_configs[CONFIG_START_HONOR_POINTS] > m_configs[CONFIG_MAX_HONOR_POINTS])
{
@@ -720,14 +747,14 @@ void World::LoadConfigSettings(bool reload)
}
m_configs[CONFIG_MAX_ARENA_POINTS] = sConfig.GetIntDefault("MaxArenaPoints", 5000);
- if(m_configs[CONFIG_MAX_ARENA_POINTS] < 0)
+ if(int32(m_configs[CONFIG_MAX_ARENA_POINTS]) < 0)
{
sLog.outError("MaxArenaPoints (%i) can't be negative. Set to 0.",m_configs[CONFIG_MAX_ARENA_POINTS]);
m_configs[CONFIG_MAX_ARENA_POINTS] = 0;
}
m_configs[CONFIG_START_ARENA_POINTS] = sConfig.GetIntDefault("StartArenaPoints", 0);
- if(m_configs[CONFIG_START_ARENA_POINTS] < 0)
+ if(int32(m_configs[CONFIG_START_ARENA_POINTS]) < 0)
{
sLog.outError("StartArenaPoints (%i) must be in range 0..MaxArenaPoints(%u). Set to %u.",
m_configs[CONFIG_START_ARENA_POINTS],m_configs[CONFIG_MAX_ARENA_POINTS],0);
@@ -745,30 +772,29 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_INSTANCE_IGNORE_LEVEL] = sConfig.GetBoolDefault("Instance.IgnoreLevel", false);
m_configs[CONFIG_INSTANCE_IGNORE_RAID] = sConfig.GetBoolDefault("Instance.IgnoreRaid", false);
- m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true);
- m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", true);
- m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false);
-
m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true);
m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4);
- m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000);
+ m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 30 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_MAX_PRIMARY_TRADE_SKILL] = sConfig.GetIntDefault("MaxPrimaryTradeSkill", 2);
m_configs[CONFIG_MIN_PETITION_SIGNS] = sConfig.GetIntDefault("MinPetitionSigns", 9);
if(m_configs[CONFIG_MIN_PETITION_SIGNS] > 9)
{
- sLog.outError("MinPetitionSigns (%i) must be in range 0..9. Set to 9.",m_configs[CONFIG_MIN_PETITION_SIGNS]);
+ sLog.outError("MinPetitionSigns (%i) must be in range 0..9. Set to 9.", m_configs[CONFIG_MIN_PETITION_SIGNS]);
m_configs[CONFIG_MIN_PETITION_SIGNS] = 9;
}
- m_configs[CONFIG_GM_LOGIN_STATE] = sConfig.GetIntDefault("GM.LoginState",2);
+ m_configs[CONFIG_GM_LOGIN_STATE] = sConfig.GetIntDefault("GM.LoginState", 2);
m_configs[CONFIG_GM_VISIBLE_STATE] = sConfig.GetIntDefault("GM.Visible", 2);
- m_configs[CONFIG_GM_CHAT] = sConfig.GetIntDefault("GM.Chat",2);
- m_configs[CONFIG_GM_WISPERING_TO] = sConfig.GetIntDefault("GM.WhisperingTo",2);
- m_configs[CONFIG_GM_IN_GM_LIST] = sConfig.GetBoolDefault("GM.InGMList",false);
- m_configs[CONFIG_GM_IN_WHO_LIST] = sConfig.GetBoolDefault("GM.InWhoList",false);
+ //m_configs[CONFIG_GM_ACCEPT_TICKETS] = sConfig.GetIntDefault("GM.AcceptTickets", 2);
+ m_configs[CONFIG_GM_CHAT] = sConfig.GetIntDefault("GM.Chat", 2);
+ m_configs[CONFIG_GM_WISPERING_TO] = sConfig.GetIntDefault("GM.WhisperingTo", 2);
+ m_configs[CONFIG_GM_IN_GM_LIST] = sConfig.GetBoolDefault("GM.InGMList", false);
+ m_configs[CONFIG_GM_IN_WHO_LIST] = sConfig.GetBoolDefault("GM.InWhoList", false);
m_configs[CONFIG_GM_LOG_TRADE] = sConfig.GetBoolDefault("GM.LogTrade", false);
- m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1);
+ m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1);
+ m_configs[CONFIG_ALLOW_GM_GROUP] = sConfig.GetBoolDefault("GM.AllowInvite", false);
+ m_configs[CONFIG_ALLOW_GM_FRIEND] = sConfig.GetBoolDefault("GM.AllowFriend", false);
if(m_configs[CONFIG_START_GM_LEVEL] < m_configs[CONFIG_START_PLAYER_LEVEL])
{
sLog.outError("GM.StartLevel (%i) must be in range StartPlayerLevel(%u)..%u. Set to %u.",
@@ -780,23 +806,41 @@ void World::LoadConfigSettings(bool reload)
sLog.outError("GM.StartLevel (%i) must be in range 1..%u. Set to %u.", m_configs[CONFIG_START_GM_LEVEL], MAX_LEVEL, MAX_LEVEL);
m_configs[CONFIG_START_GM_LEVEL] = MAX_LEVEL;
}
+ m_configs[CONFIG_GM_LOWER_SECURITY] = sConfig.GetBoolDefault("GM.LowerSecurity", false);
+ m_configs[CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS] = sConfig.GetBoolDefault("GM.AllowAchievementGain", true);
m_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("Visibility.GroupMode",0);
m_configs[CONFIG_MAIL_DELIVERY_DELAY] = sConfig.GetIntDefault("MailDeliveryDelay",HOUR);
m_configs[CONFIG_UPTIME_UPDATE] = sConfig.GetIntDefault("UpdateUptimeInterval", 10);
- if(m_configs[CONFIG_UPTIME_UPDATE]<=0)
+ if(int32(m_configs[CONFIG_UPTIME_UPDATE])<=0)
{
sLog.outError("UpdateUptimeInterval (%i) must be > 0, set to default 10.",m_configs[CONFIG_UPTIME_UPDATE]);
m_configs[CONFIG_UPTIME_UPDATE] = 10;
}
if(reload)
{
- m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000);
+ m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILISECONDS);
m_timers[WUPDATE_UPTIME].Reset();
}
+ // log db cleanup interval
+ m_configs[CONFIG_LOGDB_CLEARINTERVAL] = sConfig.GetIntDefault("LogDB.Opt.ClearInterval", 10);
+ if(int32(m_configs[CONFIG_LOGDB_CLEARINTERVAL]) <= 0)
+ {
+ sLog.outError("LogDB.Opt.ClearInterval (%i) must be > 0, set to default 10.", m_configs[CONFIG_LOGDB_CLEARINTERVAL]);
+ m_configs[CONFIG_LOGDB_CLEARINTERVAL] = 10;
+ }
+ if(reload)
+ {
+ m_timers[WUPDATE_CLEANDB].SetInterval(m_configs[CONFIG_LOGDB_CLEARINTERVAL] * MINUTE * IN_MILISECONDS);
+ m_timers[WUPDATE_CLEANDB].Reset();
+ }
+ m_configs[CONFIG_LOGDB_CLEARTIME] = sConfig.GetIntDefault("LogDB.Opt.ClearTime", 1209600); // 14 days default
+ sLog.outString("Will clear `logs` table of entries older than %i seconds every %u minutes.",
+ m_configs[CONFIG_LOGDB_CLEARTIME], m_configs[CONFIG_LOGDB_CLEARINTERVAL]);
+
m_configs[CONFIG_SKILL_CHANCE_ORANGE] = sConfig.GetIntDefault("SkillChance.Orange",100);
m_configs[CONFIG_SKILL_CHANCE_YELLOW] = sConfig.GetIntDefault("SkillChance.Yellow",75);
m_configs[CONFIG_SKILL_CHANCE_GREEN] = sConfig.GetIntDefault("SkillChance.Green",25);
@@ -806,6 +850,7 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_SKILL_CHANCE_SKINNING_STEPS] = sConfig.GetIntDefault("SkillChance.SkinningSteps",75);
m_configs[CONFIG_SKILL_PROSPECTING] = sConfig.GetBoolDefault("SkillChance.Prospecting",false);
+ m_configs[CONFIG_SKILL_MILLING] = sConfig.GetBoolDefault("SkillChance.Milling",false);
m_configs[CONFIG_SKILL_GAIN_CRAFTING] = sConfig.GetIntDefault("SkillGain.Crafting", 1);
if(m_configs[CONFIG_SKILL_GAIN_CRAFTING] < 0)
@@ -864,8 +909,10 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_EVENT_ANNOUNCE] = sConfig.GetIntDefault("Event.Announce",0);
+ m_configs[CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS] = sConfig.GetIntDefault("CreatureFamilyFleeAssistanceRadius",30);
m_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS] = sConfig.GetIntDefault("CreatureFamilyAssistanceRadius",10);
m_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY] = sConfig.GetIntDefault("CreatureFamilyAssistanceDelay",1500);
+ m_configs[CONFIG_CREATURE_FAMILY_FLEE_DELAY] = sConfig.GetIntDefault("CreatureFamilyFleeDelay",7000);
m_configs[CONFIG_WORLD_BOSS_LEVEL_DIFF] = sConfig.GetIntDefault("WorldBossLevelDiff",3);
@@ -879,23 +926,23 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_DETECT_POS_COLLISION] = sConfig.GetBoolDefault("DetectPosCollision", true);
- m_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfig.GetBoolDefault("Channel.RestrictedLfg", true);
+ m_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfig.GetBoolDefault("Channel.RestrictedLfg", true);
m_configs[CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL] = sConfig.GetBoolDefault("Channel.SilentlyGMJoin", false);
- m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true);
+ m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true);
m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false);
- m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60);
- m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300);
- m_configs[CONFIG_CORPSE_DECAY_ELITE] = sConfig.GetIntDefault("Corpse.Decay.ELITE", 300);
+ m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60);
+ m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300);
+ m_configs[CONFIG_CORPSE_DECAY_ELITE] = sConfig.GetIntDefault("Corpse.Decay.ELITE", 300);
m_configs[CONFIG_CORPSE_DECAY_RAREELITE] = sConfig.GetIntDefault("Corpse.Decay.RAREELITE", 300);
m_configs[CONFIG_CORPSE_DECAY_WORLDBOSS] = sConfig.GetIntDefault("Corpse.Decay.WORLDBOSS", 3600);
- m_configs[CONFIG_DEATH_SICKNESS_LEVEL] = sConfig.GetIntDefault("Death.SicknessLevel", 11);
+ m_configs[CONFIG_DEATH_SICKNESS_LEVEL] = sConfig.GetIntDefault ("Death.SicknessLevel", 11);
m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvP", true);
m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvE", true);
- m_configs[CONFIG_DEATH_BONES_WORLD] = sConfig.GetBoolDefault("Death.Bones.World", true);
- m_configs[CONFIG_DEATH_BONES_BG_OR_ARENA] = sConfig.GetBoolDefault("Death.Bones.BattlegroundOrArena", true);
+ m_configs[CONFIG_DEATH_BONES_WORLD] = sConfig.GetBoolDefault("Death.Bones.World", true);
+ m_configs[CONFIG_DEATH_BONES_BG_OR_ARENA] = sConfig.GetBoolDefault("Death.Bones.BattlegroundOrArena", true);
m_configs[CONFIG_THREAT_RADIUS] = sConfig.GetIntDefault("ThreatRadius", 60);
@@ -907,12 +954,22 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25);
m_configs[CONFIG_LISTEN_RANGE_YELL] = sConfig.GetIntDefault("ListenRange.Yell", 300);
- m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0);
- m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000);
- m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);
- m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault("Arena.AutoDistributeInterval", 7);
+ m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true);
+ m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", false);
+ m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false);
+ m_configs[CONFIG_BATTLEGROUND_INVITATION_TYPE] = sConfig.GetIntDefault ("Battleground.InvitationType", 0);
+ m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault ("BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILISECONDS);
+ m_configs[CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH] = sConfig.GetIntDefault ("BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILISECONDS);
+ m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault ("Arena.MaxRatingDifference", 150);
+ m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault ("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILISECONDS);
+ m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);
+ m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault ("Arena.AutoDistributeInterval", 7);
+ m_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Arena.QueueAnnouncer.Enable", false);
+ m_configs[CONFIG_ARENA_SEASON_ID] = sConfig.GetIntDefault ("Arena.ArenaSeason.ID", 1);
+ m_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfig.GetBoolDefault("Arena.ArenaSeason.InProgress", true);
+
+ m_configs[CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET] = sConfig.GetBoolDefault("OffhandCheckAtTalentsReset", false);
- m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault("BattleGround.PrematureFinishTimer", 0);
m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR);
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
@@ -953,7 +1010,7 @@ void World::LoadConfigSettings(bool reload)
}
m_MaxVisibleDistance = std::max(m_MaxVisibleDistanceForPlayer, m_MaxVisibleDistanceForCreature);
- m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Gameobject", DEFAULT_VISIBILITY_DISTANCE);
+ m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Object", DEFAULT_VISIBILITY_DISTANCE);
if(m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE)
{
sLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE));
@@ -1008,7 +1065,6 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_MAX_WHO] = sConfig.GetIntDefault("MaxWhoListReturns", 49);
- m_configs[CONFIG_PREMATURE_BG_REWARD] = sConfig.GetBoolDefault("Battleground.PrematureReward", true);
m_configs[CONFIG_BG_START_MUSIC] = sConfig.GetBoolDefault("MusicInBattleground", false);
m_configs[CONFIG_START_ALL_SPELLS] = sConfig.GetBoolDefault("PlayerStart.AllSpells", false);
m_configs[CONFIG_HONOR_AFTER_DUEL] = sConfig.GetIntDefault("HonorPointsAfterDuel", 0);
@@ -1041,6 +1097,17 @@ void World::LoadConfigSettings(bool reload)
token = strtok(NULL,delim);
}
delete[] forbiddenMaps;
+
+ // chat logging
+ m_configs[CONFIG_CHATLOG_CHANNEL] = sConfig.GetBoolDefault("ChatLogs.Channel", false);
+ m_configs[CONFIG_CHATLOG_WHISPER] = sConfig.GetBoolDefault("ChatLogs.Whisper", false);
+ m_configs[CONFIG_CHATLOG_SYSCHAN] = sConfig.GetBoolDefault("ChatLogs.SysChan", false);
+ m_configs[CONFIG_CHATLOG_PARTY] = sConfig.GetBoolDefault("ChatLogs.Party", false);
+ m_configs[CONFIG_CHATLOG_RAID] = sConfig.GetBoolDefault("ChatLogs.Raid", false);
+ m_configs[CONFIG_CHATLOG_GUILD] = sConfig.GetBoolDefault("ChatLogs.Guild", false);
+ m_configs[CONFIG_CHATLOG_PUBLIC] = sConfig.GetBoolDefault("ChatLogs.Public", false);
+ m_configs[CONFIG_CHATLOG_ADDON] = sConfig.GetBoolDefault("ChatLogs.Addon", false);
+ m_configs[CONFIG_CHATLOG_BGROUND] = sConfig.GetBoolDefault("ChatLogs.BattleGround", false);
}
/// Initialize the World
@@ -1071,7 +1138,7 @@ void World::SetInitialWorldSettings()
}
///- Loading strings. Getting no records means core load has to be canceled because no error message can be output.
- sLog.outString( "" );
+ sLog.outString();
sLog.outString( "Loading Trinity strings..." );
if (!objmgr.LoadTrinityStrings())
exit(1); // Error message displayed in function already
@@ -1095,7 +1162,7 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Script Names...");
objmgr.LoadScriptNames();
- sLog.outString( "Loading InstanceTemplate" );
+ sLog.outString( "Loading InstanceTemplate..." );
objmgr.LoadInstanceTemplate();
sLog.outString( "Loading SkillLineAbilityMultiMap Data..." );
@@ -1103,11 +1170,12 @@ void World::SetInitialWorldSettings()
///- Clean up and pack instances
sLog.outString( "Cleaning up instances..." );
- sInstanceSaveManager.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables
+ sInstanceSaveManager.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables
sLog.outString( "Packing instances..." );
sInstanceSaveManager.PackInstances();
+ sLog.outString();
sLog.outString( "Loading Localization strings..." );
objmgr.LoadCreatureLocales();
objmgr.LoadGameObjectLocales();
@@ -1116,7 +1184,10 @@ void World::SetInitialWorldSettings()
objmgr.LoadNpcTextLocales();
objmgr.LoadPageTextLocales();
objmgr.LoadNpcOptionLocales();
+ objmgr.LoadPointOfInterestLocales();
objmgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts)
+ sLog.outString( ">>> Localization strings loaded" );
+ sLog.outString();
sLog.outString( "Loading Page Texts..." );
objmgr.LoadPageTexts();
@@ -1145,6 +1216,9 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Spell Proc Event conditions..." );
spellmgr.LoadSpellProcEvents();
+ sLog.outString( "Loading Spell Bonus Data..." );
+ spellmgr.LoadSpellBonusess();
+
sLog.outString( "Loading Aggro Spells Definitions...");
spellmgr.LoadSpellThreats();
@@ -1178,8 +1252,8 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Creature Reputation OnKill Data..." );
objmgr.LoadReputationOnKill();
- sLog.outString( "Loading Pet Create Spells..." );
- objmgr.LoadPetCreateSpells();
+ sLog.outString( "Loading Points Of Interest Data..." );
+ objmgr.LoadPointsOfInterest();
sLog.outString( "Loading Creature Data..." );
objmgr.LoadCreatures();
@@ -1187,8 +1261,17 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Creature Linked Respawn..." );
objmgr.LoadCreatureLinkedRespawn(); // must be after LoadCreatures()
+ sLog.outString( "Loading pet levelup spells..." );
+ spellmgr.LoadPetLevelupSpellMap();
+
+ sLog.outString( "Loading pet default spell additional to levelup spells..." );
+ spellmgr.LoadPetDefaultSpells();
+
sLog.outString( "Loading Creature Addon Data..." );
+ sLog.outString();
objmgr.LoadCreatureAddons(); // must be after LoadCreatureTemplates() and LoadCreatures()
+ sLog.outString( ">>> Creature Addon Data loaded" );
+ sLog.outString();
sLog.outString( "Loading Creature Respawn Data..." ); // must be after PackInstances()
objmgr.LoadCreatureRespawnTimes();
@@ -1199,8 +1282,14 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances()
objmgr.LoadGameobjectRespawnTimes();
+ sLog.outString( "Loading Objects Pooling Data...");
+ poolhandler.LoadFromDB();
+
sLog.outString( "Loading Game Event Data...");
+ sLog.outString();
gameeventmgr.LoadFromDB();
+ sLog.outString( ">>> Game Event Data loaded" );
+ sLog.outString();
sLog.outString( "Loading Weather Data..." );
objmgr.LoadWeatherZoneChances();
@@ -1209,7 +1298,16 @@ void World::SetInitialWorldSettings()
objmgr.LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables
sLog.outString( "Loading Quests Relations..." );
+ sLog.outString();
objmgr.LoadQuestRelations(); // must be after quest load
+ sLog.outString( ">>> Quests Relations loaded" );
+ sLog.outString();
+
+ sLog.outString( "Loading UNIT_NPC_FLAG_SPELLCLICK Data..." );
+ objmgr.LoadNPCSpellClickSpells();
+
+ sLog.outString( "Loading SpellArea Data..." ); // must be after quest load
+ spellmgr.LoadSpellAreas();
sLog.outString( "Loading AreaTrigger definitions..." );
objmgr.LoadAreaTriggerTeleports();
@@ -1241,11 +1339,17 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading spell extra attributes...(TODO)" );
spellmgr.LoadSpellCustomAttr();
+ sLog.outString( "Loading enchant custom attributes..." );
+ spellmgr.LoadEnchantCustomAttr();
+
sLog.outString( "Loading linked spells..." );
spellmgr.LoadSpellLinked();
- sLog.outString( "Loading player Create Info & Level Stats..." );
+ sLog.outString( "Loading Player Create Info & Level Stats..." );
+ sLog.outString();
objmgr.LoadPlayerInfo();
+ sLog.outString( ">>> Player Create Info & Level Stats loaded" );
+ sLog.outString();
sLog.outString( "Loading Exploration BaseXP Data..." );
objmgr.LoadExplorationBaseXP();
@@ -1266,7 +1370,10 @@ void World::SetInitialWorldSettings()
objmgr.LoadSpellDisabledEntrys();
sLog.outString( "Loading Loot Tables..." );
+ sLog.outString();
LoadLootTables();
+ sLog.outString( ">>> Loot Tables loaded" );
+ sLog.outString();
sLog.outString( "Loading Skill Discovery Table..." );
LoadSkillDiscoveryTable();
@@ -1277,10 +1384,24 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Skill Fishing base level requirements..." );
objmgr.LoadFishingBaseSkillLevel();
+ sLog.outString( "Loading Achievements..." );
+ sLog.outString();
+ achievementmgr.LoadAchievementReferenceList();
+ achievementmgr.LoadAchievementCriteriaList();
+ achievementmgr.LoadAchievementCriteriaData();
+ achievementmgr.LoadRewards();
+ achievementmgr.LoadRewardLocales();
+ achievementmgr.LoadCompletedAchievements();
+ sLog.outString( ">>> Achievements loaded" );
+ sLog.outString();
+
///- Load dynamic data tables from the database
sLog.outString( "Loading Auctions..." );
+ sLog.outString();
auctionmgr.LoadAuctionItems();
auctionmgr.LoadAuctions();
+ sLog.outString( ">>> Auctions loaded" );
+ sLog.outString();
sLog.outString( "Loading Guilds..." );
objmgr.LoadGuilds();
@@ -1294,11 +1415,11 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading ReservedNames..." );
objmgr.LoadReservedPlayersNames();
- sLog.outString( "Loading GameObject for quests..." );
+ sLog.outString( "Loading GameObjects for quests..." );
objmgr.LoadGameObjectForQuests();
sLog.outString( "Loading BattleMasters..." );
- objmgr.LoadBattleMastersEntry();
+ sBattleGroundMgr.LoadBattleMastersEntry();
sLog.outString( "Loading GameTeleports..." );
objmgr.LoadGameTele();
@@ -1309,13 +1430,14 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Npc Options..." );
objmgr.LoadNpcOptions();
- sLog.outString( "Loading vendors..." );
+ sLog.outString( "Loading Vendors..." );
objmgr.LoadVendors(); // must be after load CreatureTemplate and ItemTemplate
- sLog.outString( "Loading trainers..." );
+ sLog.outString( "Loading Trainers..." );
objmgr.LoadTrainerSpell(); // must be after load CreatureTemplate
sLog.outString( "Loading Waypoints..." );
+ sLog.outString();
WaypointMgr.Load();
sLog.outString( "Loading Creature Formations..." );
@@ -1330,16 +1452,28 @@ void World::SetInitialWorldSettings()
///- Load and initialize scripts
sLog.outString( "Loading Scripts..." );
+ sLog.outString();
objmgr.LoadQuestStartScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
objmgr.LoadQuestEndScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
objmgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data)
objmgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data)
objmgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data)
objmgr.LoadWaypointScripts();
+ sLog.outString( ">>> Scripts loaded" );
+ sLog.outString();
sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls
objmgr.LoadDbScriptStrings();
+ sLog.outString( "Loading CreatureEventAI Texts...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Texts();
+
+ sLog.outString( "Loading CreatureEventAI Summons...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Summons();
+
+ sLog.outString( "Loading CreatureEventAI Scripts...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Scripts();
+
sLog.outString( "Initializing Scripts..." );
if(!LoadScriptingModule())
exit(1);
@@ -1357,23 +1491,26 @@ void World::SetInitialWorldSettings()
sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d",
local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
- WorldDatabase.PExecute("INSERT INTO uptime (startstring, starttime, uptime) VALUES('%s', " I64FMTD ", 0)",
- isoDate, uint64(m_startTime));
+ LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " I64FMTD ", '%s', 0)",
+ realmID, uint64(m_startTime), isoDate);
m_timers[WUPDATE_OBJECTS].SetInterval(0);
m_timers[WUPDATE_SESSIONS].SetInterval(0);
- m_timers[WUPDATE_WEATHERS].SetInterval(1000);
- m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*1000); //set auction update interval to 1 minute
- m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000);
+ m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILISECONDS);
+ m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILISECONDS);
+ m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILISECONDS);
//Update "uptime" table based on configuration entry in minutes.
- m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*1000); //erase corpses every 20 minutes
+ m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*IN_MILISECONDS);
+ //erase corpses every 20 minutes
+ m_timers[WUPDATE_CLEANDB].SetInterval(m_configs[CONFIG_LOGDB_CLEARINTERVAL]*MINUTE*IN_MILISECONDS);
+ // clean logs table every 14 days by default
//to set mailtimer to return mails every day between 4 and 5 am
//mailtimer is increased when updating auctions
//one second is 1000 -(tested on win system)
- mail_timer = ((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * 1000) / m_timers[WUPDATE_AUCTIONS].GetInterval() );
+ mail_timer = ((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * IN_MILISECONDS) / m_timers[WUPDATE_AUCTIONS].GetInterval() );
//1440
- mail_timer_expires = ( (DAY * 1000) / (m_timers[WUPDATE_AUCTIONS].GetInterval()));
+ mail_timer_expires = ( (DAY * IN_MILISECONDS) / (m_timers[WUPDATE_AUCTIONS].GetInterval()));
sLog.outDebug("Mail timer set to: %u, mail return is called every %u minutes", mail_timer, mail_timer_expires);
///- Initilize static helper structures
@@ -1406,6 +1543,9 @@ void World::SetInitialWorldSettings()
sLog.outString("Calculate next daily quest reset time..." );
InitDailyQuestResetTime();
+ sLog.outString("Starting objects Pooling system..." );
+ poolhandler.Initialize();
+
sLog.outString("Starting Game Event system..." );
uint32 nextGameEvent = gameeventmgr.Initialize();
m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); //depend on next event
@@ -1413,6 +1553,19 @@ void World::SetInitialWorldSettings()
sLog.outString("Initialize AuctionHouseBot...");
AuctionHouseBotInit();
+ // possibly enable db logging; avoid massive startup spam by doing it here.
+ if (sLog.GetLogDBLater())
+ {
+ sLog.outString("Enabling database logging...");
+ sLog.SetLogDBLater(false);
+ sLog.SetLogDB(true);
+ }
+ else
+ {
+ sLog.SetLogDB(false);
+ sLog.SetLogDBLater(false);
+ }
+
sLog.outString( "WORLD: World initialized" );
}
@@ -1457,6 +1610,7 @@ void World::DetectDBCLang()
m_defaultDbcLocale = LocaleConstant(default_locale);
sLog.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames[m_defaultDbcLocale],availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str());
+ sLog.outString();
}
void World::RecordTimeDiff(const char *text, ...)
@@ -1486,7 +1640,7 @@ void World::RecordTimeDiff(const char *text, ...)
}
/// Update the World !
-void World::Update(time_t diff)
+void World::Update(uint32 diff)
{
m_updateTime = uint32(diff);
if(m_configs[CONFIG_INTERVAL_LOG_UPDATE])
@@ -1505,7 +1659,7 @@ void World::Update(time_t diff)
}
///- Update the different timers
- for(int i = 0; i < WUPDATE_COUNT; i++)
+ for(int i = 0; i < WUPDATE_COUNT; ++i)
if(m_timers[i].GetCurrent()>=0)
m_timers[i].Update(diff);
else m_timers[i].SetCurrent(0);
@@ -1533,7 +1687,8 @@ void World::Update(time_t diff)
mail_timer = 0;
objmgr.ReturnOrDeleteOldMails(true);
}
- ///-Handle expired auctions
+
+ ///- Handle expired auctions
auctionmgr.Update();
}
@@ -1572,10 +1727,24 @@ void World::Update(time_t diff)
if (m_timers[WUPDATE_UPTIME].Passed())
{
uint32 tmpDiff = (m_gameTime - m_startTime);
- uint32 maxClientsNum = sWorld.GetMaxActiveSessionCount();
+ uint32 maxClientsNum = GetMaxActiveSessionCount();
m_timers[WUPDATE_UPTIME].Reset();
- WorldDatabase.PExecute("UPDATE uptime SET uptime = %d, maxplayers = %d WHERE starttime = " I64FMTD, tmpDiff, maxClientsNum, uint64(m_startTime));
+ LoginDatabase.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " I64FMTD, tmpDiff, maxClientsNum, realmID, uint64(m_startTime));
+ }
+
+ /// <li> Clean logs table
+ if(sWorld.getConfig(CONFIG_LOGDB_CLEARTIME) > 0) // if not enabled, ignore the timer
+ {
+ if (m_timers[WUPDATE_CLEANDB].Passed())
+ {
+ uint32 tmpDiff = (m_gameTime - m_startTime);
+ uint32 maxClientsNum = sWorld.GetMaxActiveSessionCount();
+
+ m_timers[WUPDATE_CLEANDB].Reset();
+ LoginDatabase.PExecute("DELETE FROM logs WHERE (time + %u) < "I64FMTD";",
+ sWorld.getConfig(CONFIG_LOGDB_CLEARTIME), uint64(time(0)));
+ }
}
/// <li> Handle all other objects
@@ -1727,6 +1896,9 @@ void World::ScriptsProcess()
case HIGHGUID_PET:
source = HashMapHolder<Pet>::Find(step.sourceGUID);
break;
+ case HIGHGUID_VEHICLE:
+ source = HashMapHolder<Vehicle>::Find(step.sourceGUID);
+ break;
case HIGHGUID_PLAYER:
source = HashMapHolder<Player>::Find(step.sourceGUID);
break;
@@ -1766,6 +1938,9 @@ void World::ScriptsProcess()
case HIGHGUID_PET:
target = HashMapHolder<Pet>::Find(step.targetGUID);
break;
+ case HIGHGUID_VEHICLE:
+ target = HashMapHolder<Vehicle>::Find(step.targetGUID);
+ break;
case HIGHGUID_PLAYER: // empty GUID case also
target = HashMapHolder<Player>::Find(step.targetGUID);
break;
@@ -1874,7 +2049,7 @@ void World::ScriptsProcess()
sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
break;
}
- ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, ((Unit *)source)->GetUnitMovementFlags(), step.script->datalong2 );
+ ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2 );
((Unit *)source)->GetMap()->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0);
break;
case SCRIPT_COMMAND_FLAG_SET:
@@ -1996,8 +2171,8 @@ void World::ScriptsProcess()
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
- Trinity::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong);
- Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(go,go_check);
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(summoner, go,go_check);
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
@@ -2010,7 +2185,6 @@ void World::ScriptsProcess()
}
if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
- go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
go->GetGoType()==GAMEOBJECT_TYPE_DOOR ||
go->GetGoType()==GAMEOBJECT_TYPE_BUTTON ||
go->GetGoType()==GAMEOBJECT_TYPE_TRAP )
@@ -2057,25 +2231,25 @@ void World::ScriptsProcess()
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
- Trinity::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
- Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(door,go_check);
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check);
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source));
- if ( !door )
+ if (!door)
{
sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong);
break;
}
- if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR )
+ if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR)
{
sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType());
break;
}
- if( !door->GetGoState() )
+ if (door->GetGoState() != GO_STATE_READY)
break; //door already open
door->UseDoorOrButton(time_to_close);
@@ -2113,8 +2287,8 @@ void World::ScriptsProcess()
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
- Trinity::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
- Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(door,go_check);
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check);
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
@@ -2131,7 +2305,7 @@ void World::ScriptsProcess()
break;
}
- if( door->GetGoState() )
+ if( door->GetGoState() == GO_STATE_READY )
break; //door already closed
door->UseDoorOrButton(time_to_open);
@@ -2266,24 +2440,40 @@ void World::ScriptsProcess()
break;
}
- Object* cmdTarget = step.script->datalong2 ? source : target;
+ Object* cmdTarget = step.script->datalong2 & 0x01 ? source : target;
if(!cmdTarget)
{
- sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 ? "source" : "target");
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x01 ? "source" : "target");
break;
}
if(!cmdTarget->isType(TYPEMASK_UNIT))
{
- sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId());
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x01 ? "source" : "target",cmdTarget->GetTypeId());
break;
}
Unit* spellTarget = (Unit*)cmdTarget;
+ Object* cmdSource = step.script->datalong2 & 0x02 ? target : source;
+
+ if(!cmdSource)
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x02 ? "target" : "source");
+ break;
+ }
+
+ if(!cmdSource->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x02 ? "target" : "source", cmdSource->GetTypeId());
+ break;
+ }
+
+ Unit* spellSource = (Unit*)cmdSource;
+
//TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast
- ((Unit*)source)->CastSpell(spellTarget,step.script->datalong,false);
+ spellSource->CastSpell(spellTarget,step.script->datalong,false);
break;
}
@@ -2330,7 +2520,7 @@ void World::ScriptsProcess()
//sLog.outDebug("Attempting to find Creature: Db GUID: %i", step.script->datalong);
Trinity::CreatureWithDbGUIDCheck target_check(((Unit*)source), step.script->datalong);
- Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(target,target_check);
+ Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(((Unit*)source), target, target_check);
TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
@@ -2381,15 +2571,6 @@ void World::ScriptsProcess()
break;
}
- case SCRIPT_COMMAND_PLAYSOUND:
- {
- if(!source)
- break;
- //datalong sound_id, datalong2 onlyself
- ((WorldObject*)source)->SendPlaySound(step.script->datalong, step.script->datalong2);
- break;
- }
-
case SCRIPT_COMMAND_KILL:
{
if(!source || ((Creature*)source)->isDead())
@@ -2405,6 +2586,47 @@ void World::ScriptsProcess()
break;
}
+ case SCRIPT_COMMAND_PLAY_SOUND:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for NULL creature.");
+ break;
+ }
+
+ WorldObject* pSource = dynamic_cast<WorldObject*>(source);
+ if(!pSource)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for non-world object (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ // bitmask: 0/1=anyone/target, 0/2=with distance dependent
+ Player* pTarget = NULL;
+ if(step.script->datalong2 & 1)
+ {
+ if(!target)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for NULL target.");
+ break;
+ }
+
+ if(target->GetTypeId()!=TYPEID_PLAYER)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for non-player (TypeId: %u), skipping.",target->GetTypeId());
+ break;
+ }
+
+ pTarget = (Player*)target;
+ }
+
+ // bitmask: 0/1=anyone/target, 0/2=with distance dependent
+ if(step.script->datalong2 & 2)
+ pSource->PlayDistanceSound(step.script->datalong,pTarget);
+ else
+ pSource->PlayDirectSound(step.script->datalong,pTarget);
+ break;
+ }
default:
sLog.outError("Unknown script command %u called.",step.script->command);
break;
@@ -2420,7 +2642,7 @@ void World::ScriptsProcess()
/// Send a packet to all players (except self if mentioned)
void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team)
{
- SessionMap::iterator itr;
+ SessionMap::const_iterator itr;
for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (itr->second &&
@@ -2434,16 +2656,17 @@ void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 te
}
}
+/// Send a packet to all GMs (except self if mentioned)
void World::SendGlobalGMMessage(WorldPacket *packet, WorldSession *self, uint32 team)
{
SessionMap::iterator itr;
- for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++)
+ for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (itr->second &&
itr->second->GetPlayer() &&
itr->second->GetPlayer()->IsInWorld() &&
itr->second != self &&
- itr->second->GetSecurity() >SEC_PLAYER &&
+ itr->second->GetSecurity() &&
(team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
{
itr->second->SendPacket(packet);
@@ -2451,115 +2674,105 @@ void World::SendGlobalGMMessage(WorldPacket *packet, WorldSession *self, uint32
}
}
-/// Send a System Message to all players (except self if mentioned)
-void World::SendWorldText(int32 string_id, ...)
+namespace MaNGOS
{
- std::vector<std::vector<WorldPacket*> > data_cache; // 0 = default, i => i-1 locale index
-
- for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
+ class WorldWorldTextBuilder
{
- if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() )
- continue;
+ public:
+ typedef std::vector<WorldPacket*> WorldPacketList;
+ explicit WorldWorldTextBuilder(int32 textId, va_list* args = NULL) : i_textId(textId), i_args(args) {}
+ void operator()(WorldPacketList& data_list, int32 loc_idx)
+ {
+ char const* text = objmgr.GetMangosString(i_textId,loc_idx);
- uint32 loc_idx = itr->second->GetSessionDbLocaleIndex();
- uint32 cache_idx = loc_idx+1;
+ if(i_args)
+ {
+ // we need copy va_list before use or original va_list will corrupted
+ va_list ap;
+ va_copy(ap,*i_args);
- std::vector<WorldPacket*>* data_list;
+ char str [2048];
+ vsnprintf(str,2048,text, ap );
+ va_end(ap);
- // create if not cached yet
- if(data_cache.size() < cache_idx+1 || data_cache[cache_idx].empty())
- {
- if(data_cache.size() < cache_idx+1)
- data_cache.resize(cache_idx+1);
+ do_helper(data_list,&str[0]);
+ }
+ else
+ do_helper(data_list,(char*)text);
+ }
+ private:
+ char* lineFromMessage(char*& pos) { char* start = strtok(pos,"\n"); pos = NULL; return start; }
+ void do_helper(WorldPacketList& data_list, char* text)
+ {
+ char* pos = text;
+
+ while(char* line = lineFromMessage(pos))
+ {
+ WorldPacket* data = new WorldPacket();
- data_list = &data_cache[cache_idx];
+ uint32 lineLength = (line ? strlen(line) : 0) + 1;
- char const* text = objmgr.GetTrinityString(string_id,loc_idx);
+ data->Initialize(SMSG_MESSAGECHAT, 100); // guess size
+ *data << uint8(CHAT_MSG_SYSTEM);
+ *data << uint32(LANG_UNIVERSAL);
+ *data << uint64(0);
+ *data << uint32(0); // can be chat msg group or something
+ *data << uint64(0);
+ *data << uint32(lineLength);
+ *data << line;
+ *data << uint8(0);
- char buf[1000];
+ data_list.push_back(data);
+ }
+ }
- va_list argptr;
- va_start( argptr, string_id );
- vsnprintf( buf,1000, text, argptr );
- va_end( argptr );
+ int32 i_textId;
+ va_list* i_args;
+ };
+} // namespace MaNGOS
- char* pos = &buf[0];
+/// Send a System Message to all players (except self if mentioned)
+void World::SendWorldText(int32 string_id, ...)
+{
+ va_list ap;
+ va_start(ap, string_id);
- while(char* line = ChatHandler::LineFromMessage(pos))
- {
- WorldPacket* data = new WorldPacket();
- ChatHandler::FillMessageData(data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL);
- data_list->push_back(data);
- }
- }
- else
- data_list = &data_cache[cache_idx];
+ MaNGOS::WorldWorldTextBuilder wt_builder(string_id, &ap);
+ MaNGOS::LocalizedPacketListDo<MaNGOS::WorldWorldTextBuilder> wt_do(wt_builder);
+ for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
+ {
+ if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() )
+ continue;
- for(int i = 0; i < data_list->size(); ++i)
- itr->second->SendPacket((*data_list)[i]);
+ wt_do(itr->second->GetPlayer());
}
- // free memory
- for(int i = 0; i < data_cache.size(); ++i)
- for(int j = 0; j < data_cache[i].size(); ++j)
- delete data_cache[i][j];
+ va_end(ap);
}
+/// Send a System Message to all GMs (except self if mentioned)
void World::SendGMText(int32 string_id, ...)
{
- std::vector<std::vector<WorldPacket*> > data_cache; // 0 = default, i => i-1 locale index
+ va_list ap;
+ va_start(ap, string_id);
+ MaNGOS::WorldWorldTextBuilder wt_builder(string_id, &ap);
+ MaNGOS::LocalizedPacketListDo<MaNGOS::WorldWorldTextBuilder> wt_do(wt_builder);
for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() )
continue;
- uint32 loc_idx = itr->second->GetSessionDbLocaleIndex();
- uint32 cache_idx = loc_idx+1;
-
- std::vector<WorldPacket*>* data_list;
-
- // create if not cached yet
- if(data_cache.size() < cache_idx+1 || data_cache[cache_idx].empty())
- {
- if(data_cache.size() < cache_idx+1)
- data_cache.resize(cache_idx+1);
-
- data_list = &data_cache[cache_idx];
-
- char const* text = objmgr.GetTrinityString(string_id,loc_idx);
-
- char buf[1000];
-
- va_list argptr;
- va_start( argptr, string_id );
- vsnprintf( buf,1000, text, argptr );
- va_end( argptr );
-
- char* pos = &buf[0];
-
- while(char* line = ChatHandler::LineFromMessage(pos))
- {
- WorldPacket* data = new WorldPacket();
- ChatHandler::FillMessageData(data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL);
- data_list->push_back(data);
- }
- }
- else
- data_list = &data_cache[cache_idx];
+ if(!itr->second->GetSecurity())
+ continue;
- for(int i = 0; i < data_list->size(); ++i)
- if(itr->second->GetSecurity() > SEC_PLAYER)
- itr->second->SendPacket((*data_list)[i]);
+ wt_do(itr->second->GetPlayer());
}
- // free memory
- for(int i = 0; i < data_cache.size(); ++i)
- for(int j = 0; j < data_cache[i].size(); ++j)
- delete data_cache[i][j];
+ va_end(ap);
}
-/// Send a System Message to all players (except self if mentioned)
+/// DEPRICATED, only for debug purpose. Send a System Message to all players (except self if mentioned)
void World::SendGlobalText(const char* text, WorldSession *self)
{
WorldPacket data;
@@ -2580,7 +2793,7 @@ void World::SendGlobalText(const char* text, WorldSession *self)
/// Send a packet to all players (or players selected team) in the zone (except self if mentioned)
void World::SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self, uint32 team)
{
- SessionMap::iterator itr;
+ SessionMap::const_iterator itr;
for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (itr->second &&
@@ -2609,7 +2822,7 @@ void World::KickAll()
m_QueuedPlayer.clear(); // prevent send queue update packet and login queued sessions
// session not removed at kick and will removed in next update tick
- for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
+ for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
itr->second->KickPlayer();
}
@@ -2617,36 +2830,11 @@ void World::KickAll()
void World::KickAllLess(AccountTypes sec)
{
// session not removed at kick and will removed in next update tick
- for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
+ for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
if(itr->second->GetSecurity() < sec)
itr->second->KickPlayer();
}
-/// Kick (and save) the designated player
-bool World::KickPlayer(const std::string& playerName)
-{
- SessionMap::iterator itr;
-
- // session not removed at kick and will removed in next update tick
- for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
- {
- if(!itr->second)
- continue;
- Player *player = itr->second->GetPlayer();
- if(!player)
- continue;
- if( player->IsInWorld() )
- {
- if (playerName == player->GetName())
- {
- itr->second->KickPlayer();
- return true;
- }
- }
- }
- return false;
-}
-
/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban
BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author)
{
@@ -2812,7 +3000,7 @@ void World::ShutdownMsg(bool show, Player* player)
{
std::string str = secsToTimeString(m_ShutdownTimer);
- uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME;
+ ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME;
SendServerMessage(msgid,str.c_str(),player);
DEBUG_LOG("Server is %s in %s",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"),str.c_str());
@@ -2826,7 +3014,7 @@ void World::ShutdownCancel()
if(!m_ShutdownTimer || m_stopEvent)
return;
- uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED;
+ ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED;
m_ShutdownMask = 0;
m_ShutdownTimer = 0;
@@ -2837,7 +3025,7 @@ void World::ShutdownCancel()
}
/// Send a server message to the user(s)
-void World::SendServerMessage(uint32 type, const char *text, Player* player)
+void World::SendServerMessage(ServerMessageType type, const char *text, Player* player)
{
WorldPacket data(SMSG_SERVER_MESSAGE, 50); // guess size
data << uint32(type);
@@ -2850,7 +3038,7 @@ void World::SendServerMessage(uint32 type, const char *text, Player* player)
SendGlobalMessage( &data );
}
-void World::UpdateSessions( time_t diff )
+void World::UpdateSessions( uint32 diff )
{
///- Add new sessions
while(!addSessQueue.empty())
@@ -2975,7 +3163,7 @@ void World::ResetDailyQuests()
{
sLog.outDetail("Daily quests reset for all characters.");
CharacterDatabase.Execute("DELETE FROM character_queststatus_daily");
- for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
+ for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
if(itr->second->GetPlayer())
itr->second->GetPlayer()->ResetDailyQuestStatus();
}
@@ -3003,14 +3191,20 @@ void World::UpdateMaxSessionCounters()
void World::LoadDBVersion()
{
QueryResult* result = WorldDatabase.Query("SELECT db_version FROM version LIMIT 1");
+ //QueryResult* result = WorldDatabase.Query("SELECT version, creature_ai_version FROM db_version LIMIT 1");
if(result)
{
Field* fields = result->Fetch();
- m_DBVersion = fields[0].GetString();
+ m_DBVersion = fields[0].GetCppString();
+ //m_CreatureEventAIVersion = fields[1].GetCppString();
delete result;
}
- else
- m_DBVersion = "unknown world database";
+
+ if(m_DBVersion.empty())
+ m_DBVersion = "Unknown world database.";
+
+ if(m_CreatureEventAIVersion.empty())
+ m_CreatureEventAIVersion = "Unknown creature EventAI.";
}
diff --git a/src/game/World.h b/src/game/World.h
index 01586b592e1..2c0889e0e9f 100644
--- a/src/game/World.h
+++ b/src/game/World.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,6 +45,16 @@ class SqlResultQueue;
class QueryResult;
class WorldSocket;
+// ServerMessages.dbc
+enum ServerMessageType
+{
+ SERVER_MSG_SHUTDOWN_TIME = 1,
+ SERVER_MSG_RESTART_TIME = 2,
+ SERVER_MSG_STRING = 3,
+ SERVER_MSG_SHUTDOWN_CANCELLED = 4,
+ SERVER_MSG_RESTART_CANCELLED = 5
+};
+
enum ShutdownMask
{
SHUTDOWN_MASK_RESTART = 1,
@@ -68,7 +78,8 @@ enum WorldTimers
WUPDATE_UPTIME = 4,
WUPDATE_CORPSES = 5,
WUPDATE_EVENTS = 6,
- WUPDATE_COUNT = 7
+ WUPDATE_CLEANDB = 7,
+ WUPDATE_COUNT = 8
};
/// Configuration elements
@@ -104,9 +115,12 @@ enum WorldConfigs
CONFIG_CHARACTERS_CREATING_DISABLED,
CONFIG_CHARACTERS_PER_ACCOUNT,
CONFIG_CHARACTERS_PER_REALM,
+ CONFIG_HEROIC_CHARACTERS_PER_REALM,
+ CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING,
CONFIG_SKIP_CINEMATICS,
CONFIG_MAX_PLAYER_LEVEL,
CONFIG_START_PLAYER_LEVEL,
+ CONFIG_START_HEROIC_PLAYER_LEVEL,
CONFIG_START_PLAYER_MONEY,
CONFIG_MAX_HONOR_POINTS,
CONFIG_START_HONOR_POINTS,
@@ -114,9 +128,6 @@ enum WorldConfigs
CONFIG_START_ARENA_POINTS,
CONFIG_INSTANCE_IGNORE_LEVEL,
CONFIG_INSTANCE_IGNORE_RAID,
- CONFIG_BATTLEGROUND_CAST_DESERTER,
- CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE,
- CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY,
CONFIG_INSTANCE_RESET_TIME_HOUR,
CONFIG_INSTANCE_UNLOAD_DELAY,
CONFIG_CAST_UNSTUCK,
@@ -124,12 +135,17 @@ enum WorldConfigs
CONFIG_MIN_PETITION_SIGNS,
CONFIG_GM_LOGIN_STATE,
CONFIG_GM_VISIBLE_STATE,
+ CONFIG_GM_ACCEPT_TICKETS,
CONFIG_GM_CHAT,
CONFIG_GM_WISPERING_TO,
CONFIG_GM_IN_GM_LIST,
CONFIG_GM_IN_WHO_LIST,
CONFIG_GM_LOG_TRADE,
+ CONFIG_ALLOW_GM_GROUP,
+ CONFIG_ALLOW_GM_FRIEND,
CONFIG_START_GM_LEVEL,
+ CONFIG_GM_LOWER_SECURITY,
+ CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS,
CONFIG_GROUP_VISIBILITY,
CONFIG_MAIL_DELIVERY_DELAY,
CONFIG_UPTIME_UPDATE,
@@ -153,8 +169,10 @@ enum WorldConfigs
CONFIG_CHATFLOOD_MESSAGE_DELAY,
CONFIG_CHATFLOOD_MUTE_TIME,
CONFIG_EVENT_ANNOUNCE,
+ CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS,
CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS,
CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY,
+ CONFIG_CREATURE_FAMILY_FLEE_DELAY,
CONFIG_WORLD_BOSS_LEVEL_DIFF,
CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF,
CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF,
@@ -182,12 +200,20 @@ enum WorldConfigs
CONFIG_LISTEN_RANGE_SAY,
CONFIG_LISTEN_RANGE_TEXTEMOTE,
CONFIG_LISTEN_RANGE_YELL,
+ CONFIG_SKILL_MILLING,
+ CONFIG_BATTLEGROUND_CAST_DESERTER,
+ CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE,
+ CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY,
+ CONFIG_BATTLEGROUND_INVITATION_TYPE,
+ CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER,
+ CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH,
CONFIG_ARENA_MAX_RATING_DIFFERENCE,
CONFIG_ARENA_RATING_DISCARD_TIMER,
CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS,
CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS,
- CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER,
-
+ CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE,
+ CONFIG_ARENA_SEASON_ID,
+ CONFIG_ARENA_SEASON_IN_PROGRESS,
CONFIG_MAX_WHO,
CONFIG_BG_START_MUSIC,
CONFIG_START_ALL_SPELLS,
@@ -204,8 +230,18 @@ enum WorldConfigs
CONFIG_INTERVAL_LOG_UPDATE,
CONFIG_MIN_LOG_UPDATE,
CONFIG_ENABLE_SINFO_LOGIN,
- CONFIG_PREMATURE_BG_REWARD,
-
+ CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET,
+ CONFIG_CHATLOG_CHANNEL,
+ CONFIG_CHATLOG_WHISPER,
+ CONFIG_CHATLOG_SYSCHAN,
+ CONFIG_CHATLOG_PARTY,
+ CONFIG_CHATLOG_RAID,
+ CONFIG_CHATLOG_GUILD,
+ CONFIG_CHATLOG_PUBLIC,
+ CONFIG_CHATLOG_ADDON,
+ CONFIG_CHATLOG_BGROUND,
+ CONFIG_LOGDB_CLEARINTERVAL,
+ CONFIG_LOGDB_CLEARTIME,
CONFIG_VALUE_COUNT
};
@@ -216,6 +252,8 @@ enum Rates
RATE_POWER_MANA,
RATE_POWER_RAGE_INCOME,
RATE_POWER_RAGE_LOSS,
+ RATE_POWER_RUNICPOWER_INCOME,
+ RATE_POWER_RUNICPOWER_LOSS,
RATE_POWER_FOCUS,
RATE_SKILL_DISCOVERY,
RATE_DROP_ITEM_POOR,
@@ -230,8 +268,9 @@ enum Rates
RATE_XP_KILL,
RATE_XP_QUEST,
RATE_XP_EXPLORE,
- RATE_XP_PAST_70,
RATE_REPUTATION_GAIN,
+ RATE_REPUTATION_LOWLEVEL_KILL,
+ RATE_REPUTATION_LOWLEVEL_QUEST,
RATE_CREATURE_NORMAL_HP,
RATE_CREATURE_ELITE_ELITE_HP,
RATE_CREATURE_ELITE_RAREELITE_HP,
@@ -259,7 +298,6 @@ enum Rates
RATE_MINING_AMOUNT,
RATE_MINING_NEXT,
RATE_TALENT,
- RATE_LOYALTY,
RATE_CORPSE_DECAY_LOOTED,
RATE_INSTANCE_RESET_TIME,
RATE_TARGET_POS_RECALCULATION_RANGE,
@@ -331,12 +369,11 @@ enum RealmZone
#define SCRIPT_COMMAND_CLOSE_DOOR 12 // source = unit, datalong=db_guid, datalong2=reset_delay
#define SCRIPT_COMMAND_ACTIVATE_OBJECT 13 // source = unit, target=GO
#define SCRIPT_COMMAND_REMOVE_AURA 14 // source (datalong2!=0) or target (datalong==0) unit, datalong = spell_id
-#define SCRIPT_COMMAND_CAST_SPELL 15 // source (datalong2!=0) or target (datalong==0) unit, datalong = spell_id
-#define SCRIPT_COMMAND_LOAD_PATH 16 // source = unit, path = datalong, repeatable datalong2
-#define SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT 17 // datalong scriptid, lowguid datalong2, dataint table
-#define SCRIPT_COMMAND_PLAYSOUND 18 // datalong soundid, datalong2 play only self
-#define SCRIPT_COMMAND_KILL 19 // datalong removecorpse
-
+#define SCRIPT_COMMAND_CAST_SPELL 15 // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s
+#define SCRIPT_COMMAND_PLAY_SOUND 16 // source = any object, target=any/player, datalong (sound_id), datalong2 (bitmask: 0/1=anyone/target, 0/2=with distance dependent, so 1|2 = 3 is target with distance dependent)
+#define SCRIPT_COMMAND_LOAD_PATH 20 // source = unit, path = datalong, repeatable datalong2
+#define SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT 21 // datalong scriptid, lowguid datalong2, dataint table
+#define SCRIPT_COMMAND_KILL 22 // datalong removecorpse
/// Storage class for commands issued for delayed execution
struct CliCommandHolder
@@ -383,6 +420,12 @@ class World
Weather* AddWeather(uint32 zone_id);
void RemoveWeather(uint32 zone_id);
+ /// Deny clients?
+ bool IsClosed() { return m_isClosed; }
+
+ /// Close world
+ void SetClosed(bool val) { m_isClosed = val; }
+
/// Get the active session server limit (or security level limitations)
uint32 GetPlayerAmountLimit() const { return m_playerLimit >= 0 ? m_playerLimit : 0; }
AccountTypes GetPlayerSecurityLimit() const { return m_playerLimit <= 0 ? AccountTypes(-m_playerLimit) : SEC_PLAYER; }
@@ -414,7 +457,7 @@ class World
/// Get the string for new characters (first login)
const std::string& GetNewCharString() const { return m_newCharString; }
- uint32 GetDefaultDbcLocale() const { return m_defaultDbcLocale; }
+ LocaleConstant GetDefaultDbcLocale() const { return m_defaultDbcLocale; }
/// Get the path where data (dbc, maps) are stored on disk
std::string GetDataPath() const { return m_dataPath; }
@@ -446,7 +489,7 @@ class World
void SendGlobalGMMessage(WorldPacket *packet, WorldSession *self = 0, uint32 team = 0);
void SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self = 0, uint32 team = 0);
void SendZoneText(uint32 zone, const char *text, WorldSession *self = 0, uint32 team = 0);
- void SendServerMessage(uint32 type, const char *text = "", Player* player = NULL);
+ 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; }
@@ -457,9 +500,9 @@ class World
static void StopNow(uint8 exitcode) { m_stopEvent = true; m_ExitCode = exitcode; }
static bool IsStopped() { return m_stopEvent; }
- void Update(time_t diff);
+ void Update(uint32 diff);
- void UpdateSessions( time_t diff );
+ void UpdateSessions( uint32 diff );
/// Set a server rate (see #Rates)
void setRate(Rates rate,float value) { rate_values[rate]=value; }
/// Get a server rate (see #Rates)
@@ -485,7 +528,6 @@ class World
bool IsPvPRealm() { return (getConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || getConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP || getConfig(CONFIG_GAME_TYPE) == REALM_TYPE_FFA_PVP); }
bool IsFFAPvPRealm() { return getConfig(CONFIG_GAME_TYPE) == REALM_TYPE_FFA_PVP; }
- bool KickPlayer(const std::string& playerName);
void KickAll();
void KickAllLess(AccountTypes sec);
BanReturn BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author);
@@ -521,6 +563,7 @@ class World
//used World DB version
void LoadDBVersion();
char const* GetDBVersion() { return m_DBVersion.c_str(); }
+ char const* GetCreatureEventAIVersion() { return m_CreatureEventAIVersion.c_str(); }
//used Script version
void SetScriptsVersion(char const* version) { m_ScriptsVersion = version ? version : "unknown scripting library"; }
@@ -541,6 +584,8 @@ class World
uint32 m_ShutdownTimer;
uint32 m_ShutdownMask;
+ bool m_isClosed;
+
time_t m_startTime;
time_t m_gameTime;
IntervalTimer m_timers[WUPDATE_COUNT];
@@ -584,7 +629,7 @@ class World
static float m_VisibleObjectGreyDistance;
// CLI command holder to be thread safe
- ZThread::LockedQueue<CliCommandHolder*, ZThread::FastMutex> cliCmdQueue;
+ ACE_Based::LockedQueue<CliCommandHolder*,ACE_Thread_Mutex> cliCmdQueue;
SqlResultQueue *m_resultQueue;
// next daily quests reset time
@@ -595,10 +640,11 @@ class World
//sessions that are added async
void AddSession_(WorldSession* s);
- ZThread::LockedQueue<WorldSession*, ZThread::FastMutex> addSessQueue;
+ ACE_Based::LockedQueue<WorldSession*, ACE_Thread_Mutex> addSessQueue;
//used versions
std::string m_DBVersion;
+ std::string m_CreatureEventAIVersion;
std::string m_ScriptsVersion;
};
diff --git a/src/game/WorldLog.cpp b/src/game/WorldLog.cpp
index a1065dced5c..978514ac7d7 100644
--- a/src/game/WorldLog.cpp
+++ b/src/game/WorldLog.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,13 +25,26 @@
#include "WorldLog.h"
#include "Policies/SingletonImp.h"
#include "Config/ConfigEnv.h"
+#include "Log.h"
-#define CLASS_LOCK Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex>
+#define CLASS_LOCK MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex>
INSTANTIATE_SINGLETON_2(WorldLog, CLASS_LOCK);
-INSTANTIATE_CLASS_MUTEX(WorldLog, ZThread::FastMutex);
+INSTANTIATE_CLASS_MUTEX(WorldLog, ACE_Thread_Mutex);
#define WORLD_LOG_FILE_STRING "world.log"
+WorldLog::WorldLog() : i_file(NULL)
+{
+ Initialize();
+}
+
+WorldLog::~WorldLog()
+{
+ if( i_file != NULL )
+ fclose(i_file);
+ i_file = NULL;
+}
+
/// Open the log file (if specified so in the configuration file)
void WorldLog::Initialize()
{
@@ -48,6 +61,63 @@ void WorldLog::Initialize()
{
i_file = fopen((logsDir+logname).c_str(), "w");
}
+
+ m_dbWorld = sConfig.GetBoolDefault("LogDB.World", false); // can be VERY heavy if enabled
+}
+
+void WorldLog::outTimestampLog(char const *fmt, ...)
+{
+ if( LogWorld() )
+ {
+ Guard guard(*this);
+ ASSERT(i_file);
+
+ Log::outTimestamp(i_file);
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(i_file, fmt, args);
+ //fprintf(i_file, "\n" );
+ va_end(args);
+
+ fflush(i_file);
+ }
+
+ if (sLog.GetLogDB() && m_dbWorld)
+ {
+ va_list ap2;
+ va_start(ap2, fmt);
+ char nnew_str[MAX_QUERY_LEN];
+ vsnprintf(nnew_str, MAX_QUERY_LEN, fmt, ap2);
+ sLog.outDB(LOG_TYPE_WORLD, nnew_str);
+ va_end(ap2);
+ }
+}
+
+void WorldLog::outLog(char const *fmt, ...)
+{
+ if( LogWorld() )
+ {
+ Guard guard(*this);
+ ASSERT(i_file);
+
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(i_file, fmt, args);
+ //fprintf(i_file, "\n" );
+ va_end(args);
+
+ fflush(i_file);
+ }
+
+ if (sLog.GetLogDB() && m_dbWorld)
+ {
+ va_list ap2;
+ va_start(ap2, fmt);
+ char nnew_str[MAX_QUERY_LEN];
+ vsnprintf(nnew_str, MAX_QUERY_LEN, fmt, ap2);
+ sLog.outDB(LOG_TYPE_WORLD, nnew_str);
+ va_end(ap2);
+ }
}
#define sWorldLog WorldLog::Instance()
diff --git a/src/game/WorldLog.h b/src/game/WorldLog.h
index 0a7c2a08067..e6b72e654f7 100644
--- a/src/game/WorldLog.h
+++ b/src/game/WorldLog.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,45 +32,29 @@
#include <stdarg.h>
/// %Log packets to a file
-class TRINITY_DLL_DECL WorldLog : public Trinity::Singleton<WorldLog, Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex> >
+class MANGOS_DLL_DECL WorldLog : public MaNGOS::Singleton<WorldLog, MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex> >
{
friend class Trinity::OperatorNew<WorldLog>;
- WorldLog() : i_file(NULL) { Initialize(); }
+ WorldLog();
WorldLog(const WorldLog &);
WorldLog& operator=(const WorldLog &);
- typedef Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex>::Lock Guard;
+ typedef MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex>::Lock Guard;
/// Close the file in destructor
- ~WorldLog()
- {
- if( i_file != NULL )
- fclose(i_file);
- i_file = NULL;
- }
+ ~WorldLog();
public:
void Initialize();
/// Is the world logger active?
- inline bool LogWorld(void) const { return (i_file != NULL); }
+ bool LogWorld(void) const { return (i_file != NULL); }
/// %Log to the file
- inline void Log(char const *fmt, ...)
- {
- if( LogWorld() )
- {
- Guard guard(*this);
- ASSERT(i_file);
-
- va_list args;
- va_start(args, fmt);
- vfprintf(i_file, fmt, args);
- va_end(args);
-
- fflush(i_file);
- }
- }
+ void outLog(char const *fmt, ...);
+ void outTimestampLog(char const *fmt, ...);
private:
FILE *i_file;
+
+ bool m_dbWorld;
};
#define sWorldLog WorldLog::Instance()
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp
index 5b1261e664a..36342c8dee1 100644
--- a/src/game/WorldSession.cpp
+++ b/src/game/WorldSession.cpp
@@ -34,16 +34,15 @@
#include "Group.h"
#include "Guild.h"
#include "World.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "BattleGroundMgr.h"
#include "OutdoorPvPMgr.h"
-#include "Language.h" // for CMSG_CANCEL_MOUNT_AURA handler
-#include "Chat.h"
+//#include "Language.h" // for CMSG_CANCEL_MOUNT_AURA handler
#include "SocialMgr.h"
+#include "zlib/zlib.h"
/// WorldSession constructor
-WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, uint8 expansion, time_t mute_time, LocaleConstant locale) :
+WorldSession::WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale) :
LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time),
_player(NULL), m_Socket(sock),_security(sec), _accountId(id), m_expansion(expansion),
m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(objmgr.GetIndexForLocale(locale)),
@@ -131,7 +130,7 @@ void WorldSession::SendPacket(WorldPacket const* packet)
sendLastPacketBytes = packet->wpos(); // wpos is real written size
}
- #endif // !MANGOS_DEBUG
+ #endif // !TRINITY_DEBUG
if (m_Socket->SendPacket (*packet) == -1)
m_Socket->CloseSocket ();
@@ -241,7 +240,7 @@ bool WorldSession::Update(uint32 /*diff*/)
void WorldSession::LogoutPlayer(bool Save)
{
// finish pending transfers before starting the logout
- while(_player && _player->IsBeingTeleported())
+ while(_player && _player->IsBeingTeleportedFar())
HandleMoveWorldportAckOpcode();
m_playerLogout = true;
@@ -298,25 +297,28 @@ void WorldSession::LogoutPlayer(bool Save)
else if(_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
{
// this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION
- _player->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
+ _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
//_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time
_player->KillPlayer();
_player->BuildPlayerRepop();
_player->RepopAtGraveyard();
}
+ //drop a flag if player is carrying it
+ if(BattleGround *bg = _player->GetBattleGround())
+ bg->EventPlayerLoggedOut(_player);
- ///- Remove player from battleground (teleport to entrance)
- if(_player->InBattleGround())
- _player->LeaveBattleground();
+ ///- Teleport to home if the player is in an invalid instance
+ if(!_player->m_InstanceValid && !_player->isGameMaster())
+ _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation());
sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId());
- for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
- if(int32 bgTypeId = _player->GetBattleGroundQueueId(i))
+ if(BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i))
{
- _player->RemoveBattleGroundQueueId(bgTypeId);
- sBattleGroundMgr.m_BattleGroundQueues[ bgTypeId ].RemovePlayer(_player->GetGUID(), true);
+ _player->RemoveBattleGroundQueueId(bgQueueTypeId);
+ sBattleGroundMgr.m_BattleGroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true);
}
}
@@ -468,6 +470,13 @@ void WorldSession::SendNotification(int32 string_id,...)
}
}
+void WorldSession::SendSetPhaseShift(uint32 PhaseShift)
+{
+ WorldPacket data(SMSG_SET_PHASE_SHIFT, 4);
+ data << uint32(PhaseShift);
+ SendPacket(&data);
+}
+
const char * WorldSession::GetTrinityString( int32 entry ) const
{
return objmgr.GetTrinityString(entry,GetSessionDbLocaleIndex());
@@ -518,3 +527,225 @@ void WorldSession::SendAuthWaitQue(uint32 position)
}
}
+void WorldSession::LoadAccountData()
+{
+ for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
+ {
+ AccountData data;
+ m_accountData[i] = data;
+ }
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT type, time, data FROM account_data WHERE account='%u'", GetAccountId());
+
+ if(!result)
+ return;
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ uint32 type = fields[0].GetUInt32();
+ if(type < NUM_ACCOUNT_DATA_TYPES)
+ {
+ m_accountData[type].Time = fields[1].GetUInt32();
+ m_accountData[type].Data = fields[2].GetCppString();
+ }
+ } while (result->NextRow());
+
+ delete result;
+}
+
+void WorldSession::SetAccountData(uint32 type, time_t time_, std::string data)
+{
+ m_accountData[type].Time = time_;
+ m_accountData[type].Data = data;
+
+ uint32 acc = GetAccountId();
+
+ CharacterDatabase.BeginTransaction ();
+ CharacterDatabase.PExecute("DELETE FROM account_data WHERE account='%u' AND type='%u'", acc, type);
+ CharacterDatabase.escape_string(data);
+ CharacterDatabase.PExecute("INSERT INTO account_data VALUES ('%u','%u','%u','%s')", acc, type, (uint32)time_, data.c_str());
+ CharacterDatabase.CommitTransaction ();
+}
+
+void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo *mi)
+{
+ CHECK_PACKET_SIZE(data, data.rpos()+4+2+4+4+4+4+4);
+ data >> mi->flags;
+ data >> mi->unk1;
+ data >> mi->time;
+ data >> mi->x;
+ data >> mi->y;
+ data >> mi->z;
+ data >> mi->o;
+
+ if(mi->flags & MOVEMENTFLAG_ONTRANSPORT)
+ {
+ CHECK_PACKET_SIZE(data, data.rpos()+8+4+4+4+4+4+1);
+ data >> mi->t_guid;
+ data >> mi->t_x;
+ data >> mi->t_y;
+ data >> mi->t_z;
+ data >> mi->t_o;
+ data >> mi->t_time;
+ data >> mi->t_seat;
+ }
+
+ if((mi->flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2)) || (mi->unk1 & 0x20))
+ {
+ CHECK_PACKET_SIZE(data, data.rpos()+4);
+ data >> mi->s_pitch;
+ }
+
+ CHECK_PACKET_SIZE(data, data.rpos()+4);
+ data >> mi->fallTime;
+
+ if(mi->flags & MOVEMENTFLAG_JUMPING)
+ {
+ CHECK_PACKET_SIZE(data, data.rpos()+4+4+4+4);
+ data >> mi->j_zspeed;
+ data >> mi->j_sinAngle;
+ data >> mi->j_cosAngle;
+ data >> mi->j_xyspeed;
+ }
+
+ if(mi->flags & MOVEMENTFLAG_SPLINE)
+ {
+ CHECK_PACKET_SIZE(data, data.rpos()+4);
+ data >> mi->u_unk1;
+ }
+}
+
+void WorldSession::OutMovementInfo(MovementInfo *mi)
+{
+ sLog.outString("MovementInfo: Flag %u, Unk1 %u, Time %u, Pos %f %f %f %f, Fall %u", mi->flags, (uint32)mi->unk1, mi->time, mi->x, mi->y, mi->z, mi->o, mi->fallTime);
+ if(mi->flags & MOVEMENTFLAG_ONTRANSPORT)
+ sLog.outString("Transport: GUID " I64FMT ", Pos %f %f %f %f, Time %u, Seat %d", mi->t_guid, mi->t_x, mi->t_y, mi->t_z, mi->t_o, mi->t_time, (int32)mi->t_seat);
+ if((mi->flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2)) || (mi->unk1 & 0x20))
+ sLog.outString("Pitch: %f", mi->s_pitch);
+ if(mi->flags & MOVEMENTFLAG_JUMPING)
+ sLog.outString("Jump: speedz %f, sin %f, cos %f, speedxy %f", mi->j_zspeed, mi->j_sinAngle, mi->j_cosAngle, mi->j_xyspeed);
+ if(mi->flags & MOVEMENTFLAG_SPLINE)
+ sLog.outString("Spline: %f", mi->u_unk1);
+}
+
+void WorldSession::ReadAddonsInfo(WorldPacket &data)
+{
+ if (data.rpos() + 4 > data.size())
+ return;
+ uint32 size;
+ data >> size;
+
+ if(!size)
+ return;
+
+ uLongf uSize = size;
+
+ uint32 pos = data.rpos();
+
+ ByteBuffer addonInfo;
+ addonInfo.resize(size);
+
+ if (uncompress(const_cast<uint8*>(addonInfo.contents()), &uSize, const_cast<uint8*>(data.contents() + pos), data.size() - pos) == Z_OK)
+ {
+ uint32 addonsCount;
+ addonInfo >> addonsCount; // addons count
+
+ for(uint32 i = 0; i < addonsCount; ++i)
+ {
+ std::string addonName;
+ uint8 enabled;
+ uint32 crc, unk1;
+
+ // check next addon data format correctness
+ if(addonInfo.rpos()+1 > addonInfo.size())
+ return;
+
+ addonInfo >> addonName;
+
+ // recheck next addon data format correctness
+ if(addonInfo.rpos()+1+4+4 > addonInfo.size())
+ return;
+
+ addonInfo >> enabled >> crc >> unk1;
+
+ sLog.outDebug("ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk1);
+
+ m_addonsList.push_back(AddonInfo(addonName, enabled, crc));
+ }
+
+ uint32 unk2;
+ addonInfo >> unk2;
+
+ if(addonInfo.rpos() != addonInfo.size())
+ sLog.outDebug("packet under read!");
+ }
+ else
+ sLog.outError("Addon packet uncompress error!");
+}
+
+void WorldSession::SendAddonsInfo()
+{
+ unsigned char tdata[256] =
+ {
+ 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54,
+ 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75,
+ 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34,
+ 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8,
+ 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8,
+ 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A,
+ 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3,
+ 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9,
+ 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22,
+ 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E,
+ 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB,
+ 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7,
+ 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0,
+ 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6,
+ 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A,
+ 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2
+ };
+
+ WorldPacket data(SMSG_ADDON_INFO, 4);
+
+ for(AddonsList::iterator itr = m_addonsList.begin(); itr != m_addonsList.end(); ++itr)
+ {
+ uint8 state = 2; // 2 is sent here
+ data << uint8(state);
+
+ uint8 unk1 = 1; // 1 is sent here
+ data << uint8(unk1);
+ if (unk1)
+ {
+ uint8 unk2 = (itr->CRC != 0x4c1c776d); // If addon is Standard addon CRC
+ data << uint8(unk2);
+ if (unk2) // if CRC is wrong, add public key (client need it)
+ data.append(tdata, sizeof(tdata));
+
+ data << uint32(0);
+ }
+
+ uint8 unk3 = 0; // 0 is sent here
+ data << uint8(unk3);
+ if (unk3)
+ {
+ // String, 256 (null terminated?)
+ data << uint8(0);
+ }
+ }
+
+ m_addonsList.clear();
+
+ uint32 count = 0;
+ data << uint32(count);
+ /*for(uint32 i = 0; i < count; ++i)
+ {
+ uint32
+ string (16 bytes)
+ string (16 bytes)
+ uint32
+ }*/
+
+ SendPacket(&data);
+}
diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h
index 1461d47fd2b..346afd99edc 100644
--- a/src/game/WorldSession.h
+++ b/src/game/WorldSession.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
#define __WORLDSESSION_H
#include "Common.h"
+#include "SharedDefines.h"
class MailItemsInfo;
struct ItemPrototype;
@@ -47,6 +48,32 @@ class CharacterHandler;
#define CHECK_PACKET_SIZE(P,S) if((P).size() < (S)) return SizeError((P),(S));
+#define NUM_ACCOUNT_DATA_TYPES 8
+
+struct AccountData
+{
+ AccountData() : Time(0), Data("") {}
+
+ time_t Time;
+ std::string Data;
+};
+
+struct AddonInfo
+{
+ AddonInfo(std::string name, uint8 enabled, uint32 crc)
+ {
+ Name = name;
+ Enabled = enabled;
+ CRC = crc;
+ }
+
+ std::string Name;
+ uint8 Enabled;
+ uint32 CRC;
+};
+
+typedef std::list<AddonInfo> AddonsList;
+
enum PartyOperation
{
PARTY_OP_INVITE = 0,
@@ -73,7 +100,7 @@ class TRINITY_DLL_SPEC WorldSession
{
friend class CharacterHandler;
public:
- WorldSession(uint32 id, WorldSocket *sock, uint32 sec, uint8 expansion, time_t mute_time, LocaleConstant locale);
+ WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale);
~WorldSession();
bool PlayerLoading() const { return m_playerLoading; }
@@ -81,6 +108,12 @@ class TRINITY_DLL_SPEC WorldSession
void SizeError(WorldPacket const& packet, uint32 size) const;
+ void ReadAddonsInfo(WorldPacket &data);
+ void SendAddonsInfo();
+
+ void ReadMovementInfo(WorldPacket &data, MovementInfo *mi);
+ void OutMovementInfo(MovementInfo *mi);
+
void SendPacket(WorldPacket const* packet);
void SendNotification(const char *format,...) ATTR_PRINTF(2,3);
void SendNotification(int32 string_id,...);
@@ -88,12 +121,13 @@ class TRINITY_DLL_SPEC WorldSession
void SendLfgResult(uint32 type, uint32 entry, uint8 lfg_type);
void SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res);
void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2,3);
+ void SendSetPhaseShift(uint32 phaseShift);
- uint32 GetSecurity() const { return _security; }
+ AccountTypes GetSecurity() const { return _security; }
uint32 GetAccountId() const { return _accountId; }
Player* GetPlayer() const { return _player; }
char const* GetPlayerName() const;
- void SetSecurity(uint32 security) { _security = security; }
+ void SetSecurity(AccountTypes security) { _security = security; }
std::string const& GetRemoteAddress() { return m_Address; }
void SetPlayer(Player *plr) { _player = plr; }
uint8 Expansion() const { return m_expansion; }
@@ -141,7 +175,7 @@ class TRINITY_DLL_SPEC WorldSession
void SendAttackStop(Unit const* enemy);
- void SendBattlegGroundList( uint64 guid, uint32 bgTypeId );
+ void SendBattlegGroundList( uint64 guid, BattleGroundTypeId bgTypeId );
void SendTradeStatus(uint32 status);
void SendCancelTrade();
@@ -153,6 +187,11 @@ class TRINITY_DLL_SPEC WorldSession
//pet
void SendPetNameQuery(uint64 guid, uint32 petnumber);
+ // Account Data
+ AccountData *GetAccountData(uint32 type) { return &m_accountData[type]; }
+ void SetAccountData(uint32 type, time_t time_, std::string data);
+ void LoadAccountData();
+
//mail
//used with item_page table
bool SendItemInfo( uint32 itemid, WorldPacket data );
@@ -309,6 +348,7 @@ class TRINITY_DLL_SPEC WorldSession
void HandleGameObjectUseOpcode(WorldPacket& recPacket);
void HandleMeetingStoneInfo(WorldPacket& recPacket);
+ void HandleGameobjectReportUse(WorldPacket& recvPacket);
void HandleNameQueryOpcode(WorldPacket& recvPacket);
@@ -322,9 +362,11 @@ class TRINITY_DLL_SPEC WorldSession
void HandleMoveWorldportAckOpcode(); // for server-side calls
void HandleMovementOpcodes(WorldPacket& recvPacket);
- void HandlePossessedMovement(WorldPacket& recv_data, MovementInfo& movementInfo, uint32& MovementFlags);
void HandleSetActiveMoverOpcode(WorldPacket &recv_data);
- void HandleNotActiveMoverOpcode(WorldPacket &recv_data);
+ void HandleMoveNotActiveMover(WorldPacket &recv_data);
+ void HandleDismissControlledVehicle(WorldPacket &recv_data);
+ void HandleRequestVehicleExit(WorldPacket &recv_data);
+ void HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data);
void HandleMoveTimeSkippedOpcode(WorldPacket &recv_data);
void HandleRequestRaidInfoOpcode( WorldPacket & recv_data );
@@ -385,7 +427,7 @@ class TRINITY_DLL_SPEC WorldSession
void HandleGuildSaveEmblemOpcode(WorldPacket& recvPacket);
void HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvPacket);
- void HandleTaxiQueryAvailableNodesOpcode(WorldPacket& recvPacket);
+ void HandleTaxiQueryAvailableNodes(WorldPacket& recvPacket);
void HandleActivateTaxiOpcode(WorldPacket& recvPacket);
void HandleActivateTaxiFarOpcode(WorldPacket& recvPacket);
void HandleTaxiNextDestinationOpcode(WorldPacket& recvPacket);
@@ -429,6 +471,7 @@ class TRINITY_DLL_SPEC WorldSession
void HandleAuctionRemoveItem( WorldPacket & recv_data );
void HandleAuctionListOwnerItems( WorldPacket & recv_data );
void HandleAuctionPlaceBid( WorldPacket & recv_data );
+ void HandleAuctionListPendingSales( WorldPacket & recv_data );
void HandleGetMail( WorldPacket & recv_data );
void HandleSendMail( WorldPacket & recv_data );
@@ -536,6 +579,7 @@ class TRINITY_DLL_SPEC WorldSession
//Pet
void HandlePetAction( WorldPacket & recv_data );
+ void HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2);
void HandlePetNameQuery( WorldPacket & recv_data );
void HandlePetSetAction( WorldPacket & recv_data );
void HandlePetAbandon( WorldPacket & recv_data );
@@ -544,6 +588,7 @@ class TRINITY_DLL_SPEC WorldSession
void HandlePetUnlearnOpcode( WorldPacket& recvPacket );
void HandlePetSpellAutocastOpcode( WorldPacket& recvPacket );
void HandlePetCastSpellOpcode( WorldPacket& recvPacket );
+ void HandlePetLearnTalent( WorldPacket& recvPacket );
void HandleSetActionBar(WorldPacket& recv_data);
@@ -580,10 +625,9 @@ class TRINITY_DLL_SPEC WorldSession
void HandleLfmSetNoneOpcode(WorldPacket& recv_data);
void HandleLfmSetOpcode(WorldPacket& recv_data);
void HandleLfgSetCommentOpcode(WorldPacket& recv_data);
- void HandleNewUnknownOpcode(WorldPacket& recv_data);
void HandleChooseTitleOpcode(WorldPacket& recv_data);
void HandleRealmStateRequestOpcode(WorldPacket& recv_data);
- void HandleAllowMoveAckOpcode(WorldPacket& recv_data);
+ void HandleTimeSyncResp(WorldPacket& recv_data);
void HandleWhoisOpcode(WorldPacket& recv_data);
void HandleResetInstancesOpcode(WorldPacket& recv_data);
@@ -629,6 +673,29 @@ class TRINITY_DLL_SPEC WorldSession
void HandleGuildBankBuyTab(WorldPacket& recv_data);
void HandleGuildBankTabText(WorldPacket& recv_data);
void HandleGuildBankSetTabText(WorldPacket& recv_data);
+
+ // Calendar
+ void HandleCalendarGetCalendar(WorldPacket& recv_data);
+ void HandleCalendarGetEvent(WorldPacket& recv_data);
+ void HandleCalendarGuildFilter(WorldPacket& recv_data);
+ void HandleCalendarArenaTeam(WorldPacket& recv_data);
+ void HandleCalendarAddEvent(WorldPacket& recv_data);
+ void HandleCalendarUpdateEvent(WorldPacket& recv_data);
+ void HandleCalendarRemoveEvent(WorldPacket& recv_data);
+ void HandleCalendarCopyEvent(WorldPacket& recv_data);
+ void HandleCalendarEventInvite(WorldPacket& recv_data);
+ void HandleCalendarEventRsvp(WorldPacket& recv_data);
+ void HandleCalendarEventRemoveInvite(WorldPacket& recv_data);
+ void HandleCalendarEventStatus(WorldPacket& recv_data);
+ void HandleCalendarEventModeratorStatus(WorldPacket& recv_data);
+ void HandleCalendarComplain(WorldPacket& recv_data);
+ void HandleCalendarGetNumPending(WorldPacket& recv_data);
+
+ void HandleSpellClick(WorldPacket& recv_data);
+ void HandleAlterAppearance(WorldPacket& recv_data);
+ void HandleRemoveGlyph(WorldPacket& recv_data);
+ void HandleCharCustomize(WorldPacket& recv_data);
+ void HandleInspectAchievements(WorldPacket& recv_data);
private:
// private trade methods
void moveItems(Item* myItems[], Item* hisItems[]);
@@ -639,7 +706,7 @@ class TRINITY_DLL_SPEC WorldSession
WorldSocket *m_Socket;
std::string m_Address;
- uint32 _security;
+ AccountTypes _security;
uint32 _accountId;
uint8 m_expansion;
@@ -651,8 +718,9 @@ class TRINITY_DLL_SPEC WorldSession
LocaleConstant m_sessionDbcLocale;
int m_sessionDbLocaleIndex;
uint32 m_latency;
-
- ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> _recvQueue;
+ AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES];
+ AddonsList m_addonsList;
+ ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue;
};
#endif
/// @}
diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp
index 9a5ec6c48c3..8bd4144b845 100644
--- a/src/game/WorldSocket.cpp
+++ b/src/game/WorldSocket.cpp
@@ -1,7 +1,7 @@
/*
-* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
-* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,7 +37,6 @@
#include "WorldPacket.h"
#include "SharedDefines.h"
#include "ByteBuffer.h"
-#include "AddonHandler.h"
#include "Opcodes.h"
#include "Database/DatabaseEnv.h"
#include "Auth/Sha1.h"
@@ -54,8 +53,37 @@
struct ServerPktHeader
{
- uint16 size;
- uint16 cmd;
+ /**
+ * size is the length of the payload _plus_ the length of the opcode
+ */
+ ServerPktHeader(uint32 size, uint16 cmd) : size(size)
+ {
+ uint8 headerIndex=0;
+ if(isLargePacket())
+ {
+ sLog.outDebug("initializing large server to client packet. Size: %u, cmd: %u", size, cmd);
+ header[headerIndex++] = 0x80|(0xFF &(size>>16));
+ }
+ header[headerIndex++] = 0xFF &(size>>8);
+ header[headerIndex++] = 0xFF &size;
+
+ header[headerIndex++] = 0xFF & cmd;
+ header[headerIndex++] = 0xFF & (cmd>>8);
+ }
+
+ uint8 getHeaderLength()
+ {
+ // cmd = 2 bytes, size= 2||3bytes
+ return 2+(isLargePacket()?3:2);
+ }
+
+ bool isLargePacket()
+ {
+ return size > 0x7FFF;
+ }
+
+ const uint32 size;
+ uint8 header[5];
};
struct ClientPktHeader
@@ -142,7 +170,7 @@ int WorldSocket::SendPacket (const WorldPacket& pct)
// Dump outgoing packet.
if (sWorldLog.LogWorld ())
{
- sWorldLog.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
+ sWorldLog.outTimestampLog ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
(uint32) get_handle (),
pct.size (),
LookupOpcodeName (pct.GetOpcode ()),
@@ -152,12 +180,11 @@ int WorldSocket::SendPacket (const WorldPacket& pct)
while (p < pct.size ())
{
for (uint32 j = 0; j < 16 && p < pct.size (); j++)
- sWorldLog.Log ("%.2X ", const_cast<WorldPacket&>(pct)[p++]);
+ sWorldLog.outLog ("%.2X ", const_cast<WorldPacket&>(pct)[p++]);
- sWorldLog.Log ("\n");
+ sWorldLog.outLog ("\n");
}
-
- sWorldLog.Log ("\n\n");
+ sWorldLog.outLog ("\n");
}
if (iSendPacket (pct) == -1)
@@ -272,7 +299,7 @@ int WorldSocket::handle_input (ACE_HANDLE)
}
case 0:
{
- DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n");
+ DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection");
errno = ECONNRESET;
return -1;
@@ -374,7 +401,7 @@ int WorldSocket::handle_input_header (void)
ACE_ASSERT (m_Header.length () == sizeof (ClientPktHeader));
- m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader));
+ m_Crypt.DecryptRecv ((uint8*) m_Header.rd_ptr (), sizeof (ClientPktHeader));
ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ());
@@ -433,7 +460,7 @@ int WorldSocket::handle_input_payload (void)
int WorldSocket::handle_input_missing_data (void)
{
- char buf [1024];
+ char buf [4096];
ACE_Data_Block db ( sizeof (buf),
ACE_Message_Block::MB_DATA,
@@ -574,7 +601,7 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
// Dump received packet.
if (sWorldLog.LogWorld ())
{
- sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
+ sWorldLog.outTimestampLog ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
(uint32) get_handle (),
new_pct->size (),
LookupOpcodeName (new_pct->GetOpcode ()),
@@ -584,10 +611,11 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
while (p < new_pct->size ())
{
for (uint32 j = 0; j < 16 && p < new_pct->size (); j++)
- sWorldLog.Log ("%.2X ", (*new_pct)[p++]);
- sWorldLog.Log ("\n");
+ sWorldLog.outLog ("%.2X ", (*new_pct)[p++]);
+
+ sWorldLog.outLog ("\n");
}
- sWorldLog.Log ("\n\n");
+ sWorldLog.outLog ("\n");
}
// like one switch ;)
@@ -626,7 +654,7 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
}
else
{
- sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode);
+ sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
return -1;
}
}
@@ -639,7 +667,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// NOTE: ATM the socket is singlethread, have this in mind ...
uint8 digest[20];
uint32 clientSeed;
- uint32 unk2;
+ uint32 unk2, unk3;
uint32 BuiltNumberClient;
uint32 id, security;
//uint8 expansion = 0;
@@ -657,10 +685,21 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
return -1;
}
+ if(sWorld.IsClosed())
+ {
+ packet.Initialize(SMSG_AUTH_RESPONSE, 1);
+ packet << uint8(AUTH_REJECT);
+ SendPacket (packet);
+
+ sLog.outError ("WorldSocket::HandleAuthSession: World closed, denying client (%s).", m_Session->GetRemoteAddress());
+ return -1;
+ }
+
// Read the content of the packet
recvPacket >> BuiltNumberClient; // for now no use
recvPacket >> unk2;
recvPacket >> account;
+ recvPacket >> unk3;
if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20))
{
@@ -684,17 +723,17 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
QueryResult *result =
LoginDatabase.PQuery ("SELECT "
- "id, " //0
- "gmlevel, " //1
- "sessionkey, " //2
- "last_ip, " //3
- "locked, " //4
- "sha_pass_hash, " //5
- "v, " //6
- "s, " //7
- "expansion, " //8
- "mutetime, " //9
- "locale " //10
+ "id, " //0
+ "gmlevel, " //1
+ "sessionkey, " //2
+ "last_ip, " //3
+ "locked, " //4
+ "sha_pass_hash, " //5
+ "v, " //6
+ "s, " //7
+ "expansion, " //8
+ "mutetime, " //9
+ "locale " //10
"FROM account "
"WHERE username = '%s'",
safe_account.c_str ());
@@ -788,6 +827,11 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
id = fields[0].GetUInt32 ();
security = fields[1].GetUInt16 ();
+ /*
+ if(security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB
+ security = SEC_ADMINISTRATOR;
+ */
+
K.SetHexStr (fields[2].GetString ());
time_t mutetime = time_t (fields[9].GetUInt64 ());
@@ -823,7 +867,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// Check locked state for server
AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit ();
- if (allowedAccountType > SEC_PLAYER && security < allowedAccountType)
+ if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
{
WorldPacket Packet (SMSG_AUTH_RESPONSE, 1);
Packet << uint8 (AUTH_UNAVAILABLE);
@@ -874,21 +918,20 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
address.c_str (),
safe_account.c_str ());
- // NOTE ATM the socket is singlethreaded, have this in mind ...
- ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1);
+ // NOTE ATM the socket is single-threaded, have this in mind ...
+ ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale), -1);
m_Crypt.SetKey (&K);
m_Crypt.Init ();
+ m_Session->LoadAccountData();
+ m_Session->ReadAddonsInfo(recvPacket);
+
// In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec
ACE_OS::sleep (ACE_Time_Value (0, 10000));
sWorld.AddSession (m_Session);
- // Create and send the Addon packet
- if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked))
- SendPacket (SendAddonPacked);
-
return 0;
}
@@ -963,23 +1006,17 @@ int WorldSocket::HandlePing (WorldPacket& recvPacket)
int WorldSocket::iSendPacket (const WorldPacket& pct)
{
- if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader))
+ ServerPktHeader header(pct.size()+2, pct.GetOpcode());
+ if (m_OutBuffer->space () < pct.size () + header.getHeaderLength())
{
errno = ENOBUFS;
return -1;
}
-
- ServerPktHeader header;
-
- header.cmd = pct.GetOpcode ();
- EndianConvert(header.cmd);
-
- header.size = (uint16) pct.size () + 2;
- EndianConvertReverse(header.size);
-
- m_Crypt.EncryptSend ((uint8*) & header, sizeof (header));
-
- if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1)
+
+
+ m_Crypt.EncryptSend ( header.header, header.getHeaderLength());
+
+ if (m_OutBuffer->copy ((char*) header.header, header.getHeaderLength()) == -1)
ACE_ASSERT (false);
if (!pct.empty ())
diff --git a/src/game/WorldSocket.h b/src/game/WorldSocket.h
index 7adf16373fe..94f57d8d636 100644
--- a/src/game/WorldSocket.h
+++ b/src/game/WorldSocket.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/WorldSocketMgr.cpp b/src/game/WorldSocketMgr.cpp
index e73b8993d0b..cc08962efa5 100644
--- a/src/game/WorldSocketMgr.cpp
+++ b/src/game/WorldSocketMgr.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2008,2007 MaNGOS <http://getmangos.com/>
*
-* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -134,7 +134,7 @@ class ReactorRunnable : protected ACE_Task_Base
if (m_NewSockets.empty ())
return;
- for (SocketSet::iterator i = m_NewSockets.begin (); i != m_NewSockets.end (); ++i)
+ for (SocketSet::const_iterator i = m_NewSockets.begin (); i != m_NewSockets.end (); ++i)
{
WorldSocket* sock = (*i);
@@ -176,14 +176,14 @@ class ReactorRunnable : protected ACE_Task_Base
if ((*i)->Update () == -1)
{
t = i;
- i++;
+ ++i;
(*t)->CloseSocket ();
(*t)->RemoveReference ();
--m_Connections;
m_Sockets.erase (t);
}
else
- i++;
+ ++i;
}
}
diff --git a/src/game/WorldSocketMgr.h b/src/game/WorldSocketMgr.h
index f6e55614d46..94cfa78324c 100644
--- a/src/game/WorldSocketMgr.h
+++ b/src/game/WorldSocketMgr.h
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/game/pchdef.cpp b/src/game/pchdef.cpp
new file mode 100644
index 00000000000..cbe8e8ad8aa
--- /dev/null
+++ b/src/game/pchdef.cpp
@@ -0,0 +1 @@
+//#include "pchdef.h" \ No newline at end of file
diff --git a/src/game/pchdef.h b/src/game/pchdef.h
new file mode 100644
index 00000000000..4b5b9dfbe3e
--- /dev/null
+++ b/src/game/pchdef.h
@@ -0,0 +1,16 @@
+//add here most rarely modified headers to speed up debug build compilation
+#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it
+#include "Common.h"
+
+#include "MapManager.h"
+#include "Log.h"
+#include "ObjectAccessor.h"
+#include "ObjectDefines.h"
+#include "Database/SQLStorage.h"
+#include "Opcodes.h"
+#include "SharedDefines.h"
+
+#ifdef FASTBUILD
+//add additional headers here to speed up compilation in release builds even more
+#include "ObjectMgr.h"
+#endif \ No newline at end of file