summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmake/compiler/msvc/settings.cmake2
-rw-r--r--src/common/Collision/Management/MMapManager.h2
-rw-r--r--src/common/Collision/Management/VMapManager2.cpp32
-rw-r--r--src/common/Collision/Management/VMapManager2.h25
-rw-r--r--src/common/Collision/Maps/TileAssembler.h2
-rw-r--r--src/common/Database/Implementation/CharacterDatabase.cpp2
-rw-r--r--src/common/Database/Implementation/LoginDatabase.cpp1
-rw-r--r--src/common/Database/Implementation/LoginDatabase.h1
-rw-r--r--src/common/Database/Implementation/WorldDatabase.cpp4
-rw-r--r--src/scripts/Commands/cs_mmaps.cpp305
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h2
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp101
-rw-r--r--src/server/game/Achievements/AchievementMgr.h24
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp2
-rw-r--r--src/server/game/CMakeLists.txt4
-rw-r--r--src/server/game/Chat/Chat.cpp4
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp2
-rw-r--r--src/server/game/DataStores/DBCStores.cpp69
-rw-r--r--src/server/game/DataStores/DBCStores.h9
-rw-r--r--src/server/game/DataStores/DBCStructure.h14
-rw-r--r--src/server/game/DataStores/DBCfmt.h4
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp2
-rw-r--r--src/server/game/Entities/Object/Object.cpp153
-rw-r--r--src/server/game/Entities/Object/Object.h118
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp1
-rw-r--r--src/server/game/Entities/Player/Player.cpp143
-rw-r--r--src/server/game/Entities/Player/Player.h8
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp26
-rw-r--r--src/server/game/Entities/Unit/Unit.h4
-rw-r--r--src/server/game/Events/GameEventMgr.cpp133
-rw-r--r--src/server/game/Events/GameEventMgr.h4
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp78
-rw-r--r--src/server/game/Globals/ObjectMgr.h1
-rw-r--r--src/server/game/Grids/GridDefines.h4
-rw-r--r--src/server/game/Handlers/CalendarHandler.cpp8
-rw-r--r--src/server/game/Handlers/ChannelHandler.cpp2
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp56
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp4
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp14
-rw-r--r--src/server/game/Instances/InstanceScript.h3
-rw-r--r--src/server/game/Loot/LootMgr.cpp56
-rw-r--r--src/server/game/Loot/LootMgr.h6
-rw-r--r--src/server/game/Maps/Map.cpp192
-rw-r--r--src/server/game/Maps/Map.h37
-rw-r--r--src/server/game/Maps/MapManager.h14
-rw-r--r--src/server/game/Misc/WhoListCache.cpp2
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h19
-rw-r--r--src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp14
-rw-r--r--src/server/game/Movement/MovementGenerators/PathGenerator.cpp27
-rw-r--r--src/server/game/Movement/MovementGenerators/PathGenerator.h2
-rw-r--r--src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp17
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp31
-rw-r--r--src/server/game/Scripting/ScriptMgr.h28
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp15
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp2
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h2
-rw-r--r--src/server/game/Spells/Spell.cpp38
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp6
-rw-r--r--src/server/game/Spells/SpellMgr.cpp8
-rw-r--r--src/server/game/World/World.cpp45
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/scripts/CMakeLists.txt4
-rw-r--r--src/server/scripts/Commands/CMakeLists.txt1
-rw-r--r--src/server/scripts/Commands/cs_gm.cpp5
-rw-r--r--src/server/scripts/Commands/cs_go.cpp4
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp1
-rw-r--r--src/server/scripts/Commands/cs_lookup.cpp4
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp48
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp1
-rw-r--r--src/server/scripts/Custom/README.md15
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h5
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp13
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp11
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp254
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp133
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h9
-rw-r--r--src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp2
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp65
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp5
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp20
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp20
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp21
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp19
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp14
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp19
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp15
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp15
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp16
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp18
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_noth.cpp19
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp16
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp17
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp19
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp20
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp226
-rw-r--r--src/server/scripts/Northrend/Naxxramas/naxxramas.h32
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp104
-rw-r--r--src/server/scripts/Northrend/zone_dalaran.cpp4
-rw-r--r--src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp2
-rw-r--r--src/server/scripts/Pet/pet_mage.cpp30
-rw-r--r--src/server/scripts/ScriptLoader.cpp14
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp29
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp5
-rw-r--r--src/server/scripts/Spells/spell_warrior.cpp2
-rw-r--r--src/server/scripts/World/achievement_scripts.cpp11
-rw-r--r--src/server/worldserver/CMakeLists.txt2
-rw-r--r--src/server/worldserver/worldserver.conf.dist10
-rw-r--r--src/tools/map_extractor/CMakeLists.txt2
-rw-r--r--src/tools/map_extractor/System.cpp226
-rw-r--r--src/tools/map_extractor/adt.cpp27
-rw-r--r--src/tools/map_extractor/adt.h50
-rw-r--r--src/tools/map_extractor/loadlib.cpp8
-rw-r--r--src/tools/map_extractor/loadlib/loadlib.h4
-rw-r--r--src/tools/mesh_extractor/Utils.h2
-rw-r--r--src/tools/mmaps_generator/MapBuilder.cpp112
-rw-r--r--src/tools/mmaps_generator/MapBuilder.h30
-rw-r--r--src/tools/mmaps_generator/PathCommon.h26
-rw-r--r--src/tools/mmaps_generator/PathGenerator.cpp5
-rw-r--r--src/tools/mmaps_generator/TerrainBuilder.cpp14
-rw-r--r--src/tools/mmaps_generator/TerrainBuilder.h8
-rw-r--r--src/tools/vmap4_extractor/loadlib/loadlib.h4
-rw-r--r--src/tools/vmap4_extractor/model.cpp23
127 files changed, 2455 insertions, 1350 deletions
diff --git a/src/cmake/compiler/msvc/settings.cmake b/src/cmake/compiler/msvc/settings.cmake
index caca79ee37..7ce1f7f200 100644
--- a/src/cmake/compiler/msvc/settings.cmake
+++ b/src/cmake/compiler/msvc/settings.cmake
@@ -59,7 +59,7 @@ endif()
# Fixes a compiler-problem when using PCH - the /Ym flag is adjusted by the compiler in MSVC2012, hence we need to set an upper limit with /Zm to avoid discrepancies)
# (And yes, this is a verified , unresolved bug with MSVC... *sigh*)
string(REGEX REPLACE "/Zm[0-9]+ *" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm500" CACHE STRING "" FORCE)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm500")
# Enable and treat as errors the following warnings to easily detect virtual function signature failures:
# 'function' : member function does not override any base class virtual member function
diff --git a/src/common/Collision/Management/MMapManager.h b/src/common/Collision/Management/MMapManager.h
index f12cd11841..842fe47fbf 100644
--- a/src/common/Collision/Management/MMapManager.h
+++ b/src/common/Collision/Management/MMapManager.h
@@ -14,7 +14,7 @@
#include "World.h"
// memory management
-inline void* dtCustomAlloc(int size, dtAllocHint /*hint*/)
+inline void* dtCustomAlloc(size_t size, dtAllocHint /*hint*/)
{
return (void*)new unsigned char[size];
}
diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp
index 8dc9d770de..6897ffa56a 100644
--- a/src/common/Collision/Management/VMapManager2.cpp
+++ b/src/common/Collision/Management/VMapManager2.cpp
@@ -1,7 +1,19 @@
/*
- * Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
- * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ * Copyright (C)
+ * Copyright (C)
+ *
+ * This 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, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
@@ -26,6 +38,7 @@ namespace VMAP
{
VMapManager2::VMapManager2()
{
+ GetLiquidFlagsPtr = &GetLiquidFlagsDummy;
}
VMapManager2::~VMapManager2(void)
@@ -76,7 +89,7 @@ namespace VMAP
}
// load one tile (internal use only)
- bool VMapManager2::_loadMap(unsigned int mapId, const std::string& basePath, uint32 tileX, uint32 tileY)
+ bool VMapManager2::_loadMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY)
{
InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId);
if (instanceTree == iInstanceMapTrees.end())
@@ -84,10 +97,10 @@ namespace VMAP
std::string mapFileName = getMapFileName(mapId);
StaticMapTree* newTree = new StaticMapTree(mapId, basePath);
if (!newTree->InitMap(mapFileName, this))
- {
- delete newTree;
+ {
+ delete newTree;
return false;
- }
+ }
instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, newTree)).first;
}
@@ -236,7 +249,7 @@ namespace VMAP
floor = info.ground_Z;
ASSERT(floor < std::numeric_limits<float>::max());
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
- if (reqLiquidType && !(GetLiquidFlags(type) & reqLiquidType))
+ if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
return false;
if (info.hitInstance->GetLiquidLevel(pos, info, level))
return true;
@@ -276,7 +289,6 @@ namespace VMAP
{
//! Critical section, thread safe access to iLoadedModelFiles
TRINITY_GUARD(ACE_Thread_Mutex, LoadedModelFilesLock);
-
ModelFileMap::iterator model = iLoadedModelFiles.find(filename);
if (model == iLoadedModelFiles.end())
{
@@ -298,4 +310,4 @@ namespace VMAP
return StaticMapTree::CanLoadMap(std::string(basePath), mapId, x, y);
}
-} // namespace VMAP
+} // namespace VMAP \ No newline at end of file
diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h
index f4455fc72d..ac07d79458 100644
--- a/src/common/Collision/Management/VMapManager2.h
+++ b/src/common/Collision/Management/VMapManager2.h
@@ -1,7 +1,19 @@
/*
- * Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
- * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ * Copyright (C)
+ * Copyright (C)
+ *
+ * This 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _VMAPMANAGER2_H
@@ -66,6 +78,8 @@ namespace VMAP
bool _loadMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY);
/* void _unloadMap(uint32 pMapId, uint32 x, uint32 y); */
+ static uint32 GetLiquidFlagsDummy(uint32) { return 0; }
+
public:
// public for debug
G3D::Vector3 convertPositionToInternalRep(float x, float y, float z) const;
@@ -102,7 +116,10 @@ namespace VMAP
virtual bool existsMap(const char* basePath, unsigned int mapId, int x, int y);
public:
void getInstanceMapTree(InstanceTreeMap &instanceMapTree);
+
+ typedef uint32(*GetLiquidFlagsFn)(uint32 liquidType);
+ GetLiquidFlagsFn GetLiquidFlagsPtr;
};
}
-#endif
+#endif \ No newline at end of file
diff --git a/src/common/Collision/Maps/TileAssembler.h b/src/common/Collision/Maps/TileAssembler.h
index be11c256b5..d93662d7fc 100644
--- a/src/common/Collision/Maps/TileAssembler.h
+++ b/src/common/Collision/Maps/TileAssembler.h
@@ -34,7 +34,7 @@ namespace VMAP
float iScale;
void init()
{
- iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iDir.y/180.f, G3D::pi()*iDir.x/180.f, G3D::pi()*iDir.z/180.f);
+ iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pif()*iDir.y/180.f, G3D::pif()*iDir.x/180.f, G3D::pif()*iDir.z/180.f);
}
G3D::Vector3 transform(const G3D::Vector3& pIn) const;
void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; }
diff --git a/src/common/Database/Implementation/CharacterDatabase.cpp b/src/common/Database/Implementation/CharacterDatabase.cpp
index a656b66884..c1ace0ccaa 100644
--- a/src/common/Database/Implementation/CharacterDatabase.cpp
+++ b/src/common/Database/Implementation/CharacterDatabase.cpp
@@ -136,7 +136,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES, "DELETE FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES, "INSERT INTO account_instance_times (accountId, instanceId, releaseTime) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_MATCH_MAKER_RATING, "SELECT matchMakerRating, maxMMR FROM character_arena_stats WHERE guid = ? AND slot = ?", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_CHARACTER_COUNT, "SELECT account, COUNT(guid) FROM characters WHERE account = ? GROUP BY account", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_COUNT, "SELECT ? AS account,(SELECT COUNT(*) FROM characters WHERE account =?) AS cnt", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_NAME, "UPDATE characters set name = ?, at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_DECLINED_NAME, "DELETE FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC);
diff --git a/src/common/Database/Implementation/LoginDatabase.cpp b/src/common/Database/Implementation/LoginDatabase.cpp
index 2f24eb49e0..66d1755c7a 100644
--- a/src/common/Database/Implementation/LoginDatabase.cpp
+++ b/src/common/Database/Implementation/LoginDatabase.cpp
@@ -57,6 +57,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = online | (1<<(?-1)) WHERE id = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_UPTIME_PLAYERS, "UPDATE uptime SET uptime = ?, maxplayers = ? WHERE realmid = ? AND starttime = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_OLD_LOGS, "DELETE FROM logs WHERE (time + ?) < ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_ACCOUNT_ACCESS, "DELETE FROM account_access WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM, "DELETE FROM account_access WHERE id = ? AND (RealmID = ? OR RealmID = -1)", CONNECTION_ASYNC);
diff --git a/src/common/Database/Implementation/LoginDatabase.h b/src/common/Database/Implementation/LoginDatabase.h
index d745d44c8f..0bde70d161 100644
--- a/src/common/Database/Implementation/LoginDatabase.h
+++ b/src/common/Database/Implementation/LoginDatabase.h
@@ -77,6 +77,7 @@ enum LoginDatabaseStatements
LOGIN_UPD_MUTE_TIME_LOGIN,
LOGIN_UPD_LAST_IP,
LOGIN_UPD_ACCOUNT_ONLINE,
+ LOGIN_UPD_UPTIME_PLAYERS,
LOGIN_DEL_OLD_LOGS,
LOGIN_DEL_ACCOUNT_ACCESS,
LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM,
diff --git a/src/common/Database/Implementation/WorldDatabase.cpp b/src/common/Database/Implementation/WorldDatabase.cpp
index 77b3ca2a62..2dd28018ed 100644
--- a/src/common/Database/Implementation/WorldDatabase.cpp
+++ b/src/common/Database/Implementation/WorldDatabase.cpp
@@ -70,8 +70,8 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH);
- PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH);
- PrepareStatement(WORLD_SEL_CREATURE_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM creature WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH);
+ PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? AND (phaseMask & ?) <> 0 ORDER BY order_", CONNECTION_SYNCH);
+ PrepareStatement(WORLD_SEL_CREATURE_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM creature WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? AND (phaseMask & ?) <> 0 ORDER BY order_", CONNECTION_SYNCH);
PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnMask, phaseMask, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(WORLD_DEL_GAME_EVENT_CREATURE, "DELETE FROM game_event_creature WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_DEL_GAME_EVENT_MODEL_EQUIP, "DELETE FROM game_event_model_equip WHERE guid = ?", CONNECTION_ASYNC);
diff --git a/src/scripts/Commands/cs_mmaps.cpp b/src/scripts/Commands/cs_mmaps.cpp
new file mode 100644
index 0000000000..831539ce2f
--- /dev/null
+++ b/src/scripts/Commands/cs_mmaps.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+* @file cs_mmaps.cpp
+* @brief .mmap related commands
+*
+* This file contains the CommandScripts for all
+* mmap sub-commands
+*/
+
+#include "ScriptMgr.h"
+#include "Chat.h"
+#include "DisableMgr.h"
+#include "ObjectMgr.h"
+#include "Player.h"
+#include "PointMovementGenerator.h"
+#include "PathGenerator.h"
+#include "MMapFactory.h"
+#include "Map.h"
+#include "TargetedMovementGenerator.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
+#include "CellImpl.h"
+
+class mmaps_commandscript : public CommandScript
+{
+public:
+ mmaps_commandscript() : CommandScript("mmaps_commandscript") { }
+
+ std::vector<ChatCommand> GetCommands() const override
+ {
+ static std::vector<ChatCommand> mmapCommandTable =
+ {
+ { "loadedtiles", SEC_ADMINISTRATOR, false, &HandleMmapLoadedTilesCommand, "" },
+ { "loc", SEC_ADMINISTRATOR, false, &HandleMmapLocCommand, "" },
+ { "path", SEC_ADMINISTRATOR, false, &HandleMmapPathCommand, "" },
+ { "stats", SEC_ADMINISTRATOR, false, &HandleMmapStatsCommand, "" },
+ { "testarea", SEC_ADMINISTRATOR, false, &HandleMmapTestArea, "" },
+ };
+
+ static std::vector<ChatCommand> commandTable =
+ {
+ { "mmap", SEC_ADMINISTRATOR, true, NULL, "", mmapCommandTable },
+ };
+ return commandTable;
+ }
+
+ static bool HandleMmapPathCommand(ChatHandler* handler, char const* args)
+ {
+ if (!MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()))
+ {
+ handler->PSendSysMessage("NavMesh not loaded for current map.");
+ return true;
+ }
+
+ handler->PSendSysMessage("mmap path:");
+
+ // units
+ Player* player = handler->GetSession()->GetPlayer();
+ Unit* target = handler->getSelectedUnit();
+ if (!player || !target)
+ {
+ handler->PSendSysMessage("Invalid target/source selection.");
+ return true;
+ }
+
+ char* para = strtok((char*)args, " ");
+
+ bool useStraightPath = false;
+ if (para && strcmp(para, "true") == 0)
+ useStraightPath = true;
+
+ bool useStraightLine = false;
+ if (para && strcmp(para, "line") == 0)
+ useStraightLine = true;
+
+ // unit locations
+ float x, y, z;
+ player->GetPosition(x, y, z);
+
+ // path
+ PathGenerator path(target);
+ path.SetUseStraightPath(useStraightPath);
+ bool result = path.CalculatePath(x, y, z, false);
+
+ Movement::PointsArray const& pointPath = path.GetPath();
+ handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str());
+ handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : useStraightLine ? "Raycast" : "SmoothPath");
+ handler->PSendSysMessage("Result: %s - Length: %zu - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType());
+
+ G3D::Vector3 const &start = path.GetStartPosition();
+ G3D::Vector3 const &end = path.GetEndPosition();
+ G3D::Vector3 const &actualEnd = path.GetActualEndPosition();
+
+ handler->PSendSysMessage("StartPosition (%.3f, %.3f, %.3f)", start.x, start.y, start.z);
+ handler->PSendSysMessage("EndPosition (%.3f, %.3f, %.3f)", end.x, end.y, end.z);
+ handler->PSendSysMessage("ActualEndPosition (%.3f, %.3f, %.3f)", actualEnd.x, actualEnd.y, actualEnd.z);
+
+ if (!player->IsGameMaster())
+ handler->PSendSysMessage("Enable GM mode to see the path points.");
+
+ for (uint32 i = 0; i < pointPath.size(); ++i)
+ player->SummonCreature(VISUAL_WAYPOINT, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9000);
+
+ return true;
+ }
+
+ static bool HandleMmapLocCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ handler->PSendSysMessage("mmap tileloc:");
+
+ // grid tile location
+ Player* player = handler->GetSession()->GetPlayer();
+
+ int32 gx = 32 - player->GetPositionX() / SIZE_OF_GRIDS;
+ int32 gy = 32 - player->GetPositionY() / SIZE_OF_GRIDS;
+
+ handler->PSendSysMessage("%03u%02i%02i.mmtile", player->GetMapId(), gx, gy);
+ handler->PSendSysMessage("gridloc [%i, %i]", gy, gx);
+
+ // calculate navmesh tile location
+ dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
+ dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId());
+ if (!navmesh || !navmeshquery)
+ {
+ handler->PSendSysMessage("NavMesh not loaded for current map.");
+ return true;
+ }
+
+ float const* min = navmesh->getParams()->orig;
+ float x, y, z;
+ player->GetPosition(x, y, z);
+ float location[VERTEX_SIZE] = {y, z, x};
+ float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f};
+
+ int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS);
+ int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS);
+
+ handler->PSendSysMessage("Calc [%02i, %02i]", tilex, tiley);
+
+ // navmesh poly -> navmesh tile location
+ dtQueryFilter filter = dtQueryFilter();
+ dtPolyRef polyRef = INVALID_POLYREF;
+ if (dtStatusFailed(navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL)))
+ {
+ handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)");
+ return true;
+ }
+
+ if (polyRef == INVALID_POLYREF)
+ handler->PSendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)");
+ else
+ {
+ dtMeshTile const* tile;
+ dtPoly const* poly;
+ if (dtStatusSucceed(navmesh->getTileAndPolyByRef(polyRef, &tile, &poly)))
+ {
+ if (tile)
+ {
+ handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y);
+ return false;
+ }
+ }
+
+ handler->PSendSysMessage("Dt [??,??] (no tile loaded)");
+ }
+
+ return true;
+ }
+
+ static bool HandleMmapLoadedTilesCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ uint32 mapid = handler->GetSession()->GetPlayer()->GetMapId();
+ dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(mapid);
+ dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId());
+ if (!navmesh || !navmeshquery)
+ {
+ handler->PSendSysMessage("NavMesh not loaded for current map.");
+ return true;
+ }
+
+ handler->PSendSysMessage("mmap loadedtiles:");
+
+ for (int32 i = 0; i < navmesh->getMaxTiles(); ++i)
+ {
+ dtMeshTile const* tile = navmesh->getTile(i);
+ if (!tile || !tile->header)
+ continue;
+
+ handler->PSendSysMessage("[%02i, %02i]", tile->header->x, tile->header->y);
+ }
+
+ return true;
+ }
+
+ static bool HandleMmapStatsCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ handler->PSendSysMessage("mmap stats:");
+ //handler->PSendSysMessage(" global mmap pathfinding is %sabled", DisableMgr::IsPathfindingEnabled(mapId) ? "en" : "dis");
+
+ MMAP::MMapManager* manager = MMAP::MMapFactory::createOrGetMMapManager();
+ handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
+
+ dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
+ if (!navmesh)
+ {
+ handler->PSendSysMessage("NavMesh not loaded for current map.");
+ return true;
+ }
+
+ uint32 tileCount = 0;
+ uint32 nodeCount = 0;
+ uint32 polyCount = 0;
+ uint32 vertCount = 0;
+ uint32 triCount = 0;
+ uint32 triVertCount = 0;
+ uint32 dataSize = 0;
+ for (int32 i = 0; i < navmesh->getMaxTiles(); ++i)
+ {
+ dtMeshTile const* tile = navmesh->getTile(i);
+ if (!tile || !tile->header)
+ continue;
+
+ tileCount++;
+ nodeCount += tile->header->bvNodeCount;
+ polyCount += tile->header->polyCount;
+ vertCount += tile->header->vertCount;
+ triCount += tile->header->detailTriCount;
+ triVertCount += tile->header->detailVertCount;
+ dataSize += tile->dataSize;
+ }
+
+ handler->PSendSysMessage("Navmesh stats:");
+ handler->PSendSysMessage(" %u tiles loaded", tileCount);
+ handler->PSendSysMessage(" %u BVTree nodes", nodeCount);
+ handler->PSendSysMessage(" %u polygons (%u vertices)", polyCount, vertCount);
+ handler->PSendSysMessage(" %u triangles (%u vertices)", triCount, triVertCount);
+ handler->PSendSysMessage(" %.2f MB of data (not including pointers)", ((float)dataSize / sizeof(unsigned char)) / 1048576);
+
+ return true;
+ }
+
+ static bool HandleMmapTestArea(ChatHandler* handler, char const* /*args*/)
+ {
+ float radius = 40.0f;
+ WorldObject* object = handler->GetSession()->GetPlayer();
+
+ CellCoord pair(Trinity::ComputeCellCoord(object->GetPositionX(), object->GetPositionY()));
+ Cell cell(pair);
+ cell.SetNoCreate();
+
+ std::list<Creature*> creatureList;
+
+ Trinity::AnyUnitInObjectRangeCheck go_check(object, radius);
+ Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck> go_search(object, creatureList, go_check);
+ TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck>, GridTypeMapContainer> go_visit(go_search);
+
+ // Get Creatures
+ cell.Visit(pair, go_visit, *(object->GetMap()), *object, radius);
+
+ if (!creatureList.empty())
+ {
+ handler->PSendSysMessage("Found %zu Creatures.", creatureList.size());
+
+ uint32 paths = 0;
+ uint32 uStartTime = getMSTime();
+
+ float gx, gy, gz;
+ object->GetPosition(gx, gy, gz);
+ for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
+ {
+ PathGenerator path(*itr);
+ path.CalculatePath(gx, gy, gz);
+ ++paths;
+ }
+
+ uint32 uPathLoadTime = getMSTimeDiff(uStartTime, getMSTime());
+ handler->PSendSysMessage("Generated %i paths in %i ms", paths, uPathLoadTime);
+ }
+ else
+ handler->PSendSysMessage("No creatures in %f yard range.", radius);
+
+ return true;
+ }
+};
+
+void AddSC_mmaps_commandscript()
+{
+ new mmaps_commandscript();
+}
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 3af8f9adc3..f133d0b35e 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -429,7 +429,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map);
return false;
}
- if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area))
+ if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !sAreaTableStore.LookupEntry(e.event.respawn.area))
{
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area);
return false;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 66b713d594..3b02da9c64 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -1731,7 +1731,7 @@ class SmartAIMgr
bool IsItemValid(SmartScriptHolder const& e, uint32 entry)
{
- if (!sItemStore.LookupEntry(entry))
+ if (!sObjectMgr->GetItemTemplate(entry))
{
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Item entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
return false;
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp
index 881bc09ce2..ac8d218c1b 100644
--- a/src/server/game/Achievements/AchievementMgr.cpp
+++ b/src/server/game/Achievements/AchievementMgr.cpp
@@ -167,7 +167,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
return true;
}
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
- if (!GetAreaEntryByAreaID(area.id))
+ if (!sAreaTableStore.LookupEntry(area.id))
{
sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) has wrong area id in value1 (%u), ignored.",
criteria->ID, criteria->requiredType, dataType, area.id);
@@ -358,12 +358,18 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
return false;
return target->getGender() == gender.gender;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT:
- return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(target));
+ return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(target), criteria_id);
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY:
+ {
if (source->GetMap()->IsRaid())
if (source->GetMap()->Is25ManRaid() != ((difficulty.difficulty & RAID_DIFFICULTY_MASK_25MAN) != 0))
return false;
- return source->GetMap()->GetSpawnMode() >= difficulty.difficulty;
+
+ AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(criteria_id);
+ uint8 spawnMode = source->GetMap()->GetSpawnMode();
+ // Dungeons completed on heroic mode count towards both in general achievement, but not in statistics.
+ return sAchievementMgr->IsStatisticCriteria(criteria) ? spawnMode == difficulty.difficulty : spawnMode >= difficulty.difficulty;
+ }
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT:
return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM:
@@ -1277,17 +1283,15 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
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
+ AreaTableEntry const* area = sAreaTableStore.LookupEntry(worldOverlayEntry->areatableID[j]);
+ if (!area)
break;
- int32 exploreFlag = GetAreaFlagByAreaID(area_id);
- if (exploreFlag < 0)
+ uint32 playerIndexOffset = uint32(area->exploreFlag) / 32;
+ if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE)
continue;
- uint32 playerIndexOffset = uint32(exploreFlag) / 32;
- uint32 mask = 1<< (uint32(exploreFlag) % 32);
-
+ uint32 mask = 1 << (uint32(area->exploreFlag) % 32);
if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
{
matchFound = true;
@@ -1661,8 +1665,14 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
}
+ case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
{
+ // those requirements couldn't be found in the dbc
+ AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
+ if (!data || !data->Meets(GetPlayer(), NULL))
+ continue;
+
// Check map id requirement
if (miscValue1 == achievementCriteria->win_arena.mapID)
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
@@ -1678,7 +1688,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
break;
// FIXME: not triggered in code as result, need to implement
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
- case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
break; // Not implemented yet :(
@@ -1876,6 +1885,7 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
+ case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
default:
break;
}
@@ -2163,9 +2173,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
}
}
- // 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))
+ if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
sAchievementMgr->SetRealmCompleted(achievement);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, achievement->ID);
@@ -2307,6 +2315,61 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria,
return true;
}
+bool AchievementGlobalMgr::IsStatisticCriteria(AchievementCriteriaEntry const* achievementCriteria) const
+{
+ return isStatisticAchievement(sAchievementStore.LookupEntry(achievementCriteria->referredAchievement));
+}
+
+bool AchievementGlobalMgr::isStatisticAchievement(AchievementEntry const* achievement) const
+{
+ if (!achievement)
+ return false;
+
+ AchievementCategoryEntry const* cat = sAchievementCategoryStore.LookupEntry(achievement->categoryId);
+ do {
+ switch(cat->ID) {
+ case ACHIEVEMENT_CATEGORY_STATISTICS:
+ return true;
+ case ACHIEVEMENT_CATEOGRY_GENERAL:
+ return false;
+ default:
+ cat = sAchievementCategoryStore.LookupEntry(cat->parentCategory);
+ break;
+ }
+ } while (cat);
+
+ return false;
+}
+
+bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) const
+{
+ auto itr = m_allCompletedAchievements.find(achievement->ID);
+ if (itr == m_allCompletedAchievements.end())
+ return false;
+
+ if (itr->second == std::chrono::system_clock::time_point::min())
+ return false;
+
+ if (itr->second == std::chrono::system_clock::time_point::max())
+ return true;
+
+ // Allow completing the realm first kill for entire minute after first person did it
+ // it may allow more than one group to achieve it (highly unlikely)
+ // but apparently this is how blizz handles it as well
+ if (achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)
+ return (std::chrono::system_clock::now() - itr->second) > std::chrono::minutes(1);
+
+ return true;
+}
+
+void AchievementGlobalMgr::SetRealmCompleted(AchievementEntry const* achievement)
+{
+ if (IsRealmCompleted(achievement))
+ return;
+
+ m_allCompletedAchievements[achievement->ID] = std::chrono::system_clock::now();
+}
+
//==========================================================
void AchievementGlobalMgr::LoadAchievementCriteriaList()
{
@@ -2628,6 +2691,14 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
QueryResult result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement");
+ // Populate _allCompletedAchievements with all realm first achievement ids to make multithreaded access safer
+ // while it will not prevent races, it will prevent crashes that happen because std::unordered_map key was added
+ // instead the only potential race will happen on value associated with the key
+ for (uint32 i = 0; i < sAchievementStore.GetNumRows(); ++i)
+ if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(i))
+ if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
+ m_allCompletedAchievements[achievement->ID] = std::chrono::system_clock::time_point::min();
+
if (!result)
{
sLog->outString(">> Loaded 0 completed achievements. DB table `character_achievement` is empty.");
@@ -2655,7 +2726,7 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
continue;
}
else if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
- m_allCompletedAchievements.insert(achievementId);
+ m_allCompletedAchievements[achievementId] = std::chrono::system_clock::time_point::max();
} while (result->NextRow());
sLog->outString(">> Loaded %lu completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h
index 390a0cb589..74fe0046ef 100644
--- a/src/server/game/Achievements/AchievementMgr.h
+++ b/src/server/game/Achievements/AchievementMgr.h
@@ -8,6 +8,7 @@
#include <map>
#include <string>
+#include <chrono>
#include "Common.h"
#include <ace/Singleton.h>
@@ -55,9 +56,14 @@ enum AchievementCriteriaDataType
ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY = 22, // N login on day of N-th Birthday
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23 // title_id known (pvp) title, values from dbc
};
-
#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 24 // maximum value in AchievementCriteriaDataType enum
+enum AchievementCommonCategories
+{
+ ACHIEVEMENT_CATEOGRY_GENERAL = -1,
+ ACHIEVEMENT_CATEGORY_STATISTICS = 1
+};
+
class Player;
class Unit;
@@ -294,6 +300,9 @@ class AchievementGlobalMgr
~AchievementGlobalMgr() {}
public:
+ bool IsStatisticCriteria(AchievementCriteriaEntry const* achievementCriteria) const;
+ bool isStatisticAchievement(AchievementEntry const* achievement) const;
+
AchievementCriteriaEntryList const* GetAchievementCriteriaByType(AchievementCriteriaTypes type) const
{
return &m_AchievementCriteriasByType[type];
@@ -348,15 +357,8 @@ class AchievementGlobalMgr
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);
- }
+ bool IsRealmCompleted(AchievementEntry const* achievement) const;
+ void SetRealmCompleted(AchievementEntry const* achievement);
void LoadAchievementCriteriaList();
void LoadAchievementCriteriaData();
@@ -375,7 +377,7 @@ class AchievementGlobalMgr
// store achievements by referenced achievement id to speed up lookup
AchievementListByReferencedId m_AchievementListByReferencedId;
- typedef std::set<uint32> AllCompletedAchievements;
+ typedef UNORDERED_MAP<uint32 /*achievementId*/, std::chrono::system_clock::time_point /*completionTime*/> AllCompletedAchievements;
AllCompletedAchievements m_allCompletedAchievements;
AchievementRewards m_achievementRewards;
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 144eb65465..e4ac0d3901 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -956,6 +956,8 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
// Arena lost => reset the win_rated_arena having the "no_lose" condition
player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE, 0);
}
+
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA, GetMapId());
}
uint32 winner_kills = player->GetRandomWinner() ? BG_REWARD_WINNER_HONOR_LAST : BG_REWARD_WINNER_HONOR_FIRST;
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index 2d6aae341a..2b4f7c26ae 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -111,8 +111,8 @@ set(game_STAT_SRCS
include_directories(
${game_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}
- ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Detour
- ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Recast
+ ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Detour/Include
+ ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/deps/g3dlite/include
${CMAKE_SOURCE_DIR}/deps/SFMT
${CMAKE_SOURCE_DIR}/deps/zlib
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index 9e94ec8ee3..79986a7538 100644
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -301,11 +301,11 @@ bool ChatHandler::ExecuteCommandInTable(std::vector<ChatCommand> const& table, c
uint32 areaId = player->GetAreaId();
std::string areaName = "Unknown";
std::string zoneName = "Unknown";
- if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId))
+ if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
{
int locale = GetSessionDbcLocale();
areaName = area->area_name[locale];
- if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone))
+ if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone))
zoneName = zone->area_name[locale];
}
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index ee334106c2..ccf36914cf 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -1658,7 +1658,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
}
case CONDITION_ZONEID:
{
- AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->ConditionValue1);
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1);
if (!areaEntry)
{
sLog->outErrorDb("ZoneID condition has non existing area (%u), skipped", cond->ConditionValue1);
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index f9c2648116..d92d3f78a2 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -38,15 +38,14 @@ struct WMOAreaTableTripple
typedef std::map<WMOAreaTableTripple, WMOAreaTableEntry const*> WMOAreaInfoByTripple;
-DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
+DBCStorage <AreaTableEntry> sAreaTableStore(AreaTableEntryfmt);
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt);
-static AreaFlagByAreaID sAreaFlagByAreaID;
-static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
static WMOAreaInfoByTripple sWMOAreaInfoByTripple;
DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt);
+DBCStorage <AchievementCategoryEntry> sAchievementCategoryStore(AchievementCategoryfmt);
DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt);
@@ -100,7 +99,6 @@ DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptf
DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
-DBCStorage <ItemEntry> sItemStore(Itemfmt);
DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt);
@@ -255,23 +253,10 @@ void LoadDBCStores(const std::string& dataPath)
StoreProblemList bad_dbc_files;
uint32 availableDbcLocales = 0xFFFFFFFF;
- LoadDBC(availableDbcLocales, 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, bad_dbc_files, sAreaTableStore, dbcPath, "AreaTable.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex);
+ LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCategoryStore, dbcPath, "Achievement_Category.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaGroupStore, dbcPath, "AreaGroup.dbc");
@@ -346,7 +331,6 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sHolidaysStore, dbcPath, "Holidays.dbc");
- LoadDBC(availableDbcLocales, bad_dbc_files, sItemStore, dbcPath, "Item.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sItemBagFamilyStore, dbcPath, "ItemBagFamily.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sItemDisplayInfoStore, dbcPath, "ItemDisplayInfo.dbc");
//LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sItemCondExtCostsStore, dbcPath, "ItemCondExtCosts.dbc");
@@ -626,10 +610,9 @@ void LoadDBCStores(const std::string& dataPath)
}
// Check loaded DBC files proper version
- if (!sAreaStore.LookupEntry(3617) || // last area (areaflag) added in 3.3.5a
+ if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a
!sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a
!sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a
- !sItemStore.LookupEntry(56806) || // last gem property added in 3.3.5a
!sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a
!sMapStore.LookupEntry(724) || // last map added in 3.3.5a
!sSpellStore.LookupEntry(80864) ) // last client known item added in 3.3.5a
@@ -678,50 +661,12 @@ uint32 GetTalentSpellCost(uint32 spellId)
return 0;
}
-int32 GetAreaFlagByAreaID(uint32 area_id)
-{
- AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
- if (i == sAreaFlagByAreaID.end())
- return -1;
-
- return i->second;
-}
-
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)
{
WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid));
- if (i == sWMOAreaInfoByTripple.end())
- return NULL;
- return i->second;
-}
-
-AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
-{
- int32 areaflag = GetAreaFlagByAreaID(area_id);
- if (areaflag < 0)
+ if (i == sWMOAreaInfoByTripple.end())
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;
+ return i->second;
}
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index d69d2132b9..5b241f6fcb 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -20,11 +20,6 @@ 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);
-
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid);
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId);
@@ -58,7 +53,8 @@ uint32 GetDefaultMapLight(uint32 mapId);
extern DBCStorage <AchievementEntry> sAchievementStore;
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
-extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
+extern DBCStorage <AchievementCategoryEntry> sAchievementCategoryStore;
+extern DBCStorage <AreaTableEntry> sAreaTableStore;
extern DBCStorage <AreaGroupEntry> sAreaGroupStore;
extern DBCStorage <AreaPOIEntry> sAreaPOIStore;
extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
@@ -104,7 +100,6 @@ extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore;
extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
extern DBCStorage <HolidaysEntry> sHolidaysStore;
-extern DBCStorage <ItemEntry> sItemStore;
extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore;
extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore;
extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 3b7ecee547..e43351b9dd 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -46,7 +46,7 @@ struct AchievementEntry
struct AchievementCategoryEntry
{
uint32 ID; // 0
- uint32 parentCategory; // 1 -1 for main category
+ int32 parentCategory; // 1 -1 for main category
//char *name[16]; // 2-17
//uint32 name_flags; // 18
//uint32 sortOrder; // 19
@@ -1092,18 +1092,6 @@ struct HolidaysEntry
//uint32 flags; // 54 m_flags (0 = Darkmoon Faire, Fishing Contest and Wotlk Launch, rest is 1)
};
-struct ItemEntry
-{
- uint32 ID; // 0
- uint32 Class; // 1
- uint32 SubClass; // 2 some items have strange subclasses
- int32 SoundOverrideSubclass; // 3
- int32 Material; // 4
- uint32 DisplayId; // 5
- uint32 InventoryType; // 6
- uint32 Sheath; // 7
-};
-
struct ItemBagFamilyEntry
{
uint32 ID; // 0
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index 395de0fe9d..8e1a6c3395 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -10,8 +10,9 @@
char const Achievementfmt[] = "niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp";
const std::string CustomAchievementIndex = "ID";
+char const AchievementCategoryfmt[] = "nixxxxxxxxxxxxxxxxxx";
char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix";
-char const AreaTableEntryfmt[] = "iiinixxxxxissssssssssssssssxiiiiixxx";
+char const AreaTableEntryfmt[] = "niiiixxxxxissssssssssssssssxiiiiixxx";
char const AreaGroupEntryfmt[] = "niiiiiii";
char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix";
char const AreaTriggerEntryfmt[] = "niffffffff";
@@ -57,7 +58,6 @@ char const GtOCTRegenHPfmt[] = "f";
char const GtRegenHPPerSptfmt[] = "f";
char const GtRegenMPPerSptfmt[] = "f";
char const Holidaysfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
-char const Itemfmt[] = "niiiiiii";
char const ItemBagFamilyfmt[] = "nxxxxxxxxxxxxxxxxx";
char const ItemDisplayTemplateEntryfmt[] = "nxxxxsxxxxxxxxxxxxxxxxxxx";
//char const ItemCondExtCostsEntryfmt[] = "xiii";
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 176315d742..8a2a0f3a13 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -353,7 +353,7 @@ bool Creature::InitEntry(uint32 Entry, const CreatureData* data)
// Load creature equipment
if (!data || data->equipmentId == 0) // use default from the template
- LoadEquipment(GetCreatureData() ? GetOriginalEquipmentId() : 1);
+ LoadEquipment();
else if (data && data->equipmentId != 0) // override, 0 means no equipment
{
m_originalEquipmentId = data->equipmentId;
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index f3091758f6..d1731510ea 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1095,9 +1095,13 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
if (!IsInMap(obj))
return false;
- float ox, oy, oz;
- obj->GetPosition(ox, oy, oz);
- return IsWithinLOS(ox, oy, oz);
+ float x, y, z;
+ if (obj->GetTypeId() == TYPEID_PLAYER)
+ obj->GetPosition(x, y, z);
+ else
+ obj->GetHitSpherePointFor(GetPosition(), x, y, z);
+
+ return IsWithinLOS(x, y, z);
}
bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
@@ -1107,11 +1111,36 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
VMAP::IVMapManager* vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);*/
if (IsInWorld())
- return GetMap()->isInLineOfSight(GetPositionX(), GetPositionY(), GetPositionZ()+2.f, ox, oy, oz+2.f, GetPhaseMask());
+ {
+ float x, y, z;
+ if (GetTypeId() == TYPEID_PLAYER)
+ GetPosition(x, y, z);
+ else
+ GetHitSpherePointFor({ ox, oy, oz }, x, y, z);
+
+ return GetMap()->isInLineOfSight(x, y, z + 2.0f, ox, oy, oz + 2.0f, GetPhaseMask());
+ }
return true;
}
+Position WorldObject::GetHitSpherePointFor(Position const& dest) const
+{
+ G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ());
+ G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
+ G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(this), GetObjectSize());
+
+ return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y));
+}
+
+void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const
+{
+ Position pos = GetHitSpherePointFor(dest);
+ x = pos.GetPositionX();
+ y = pos.GetPositionY();
+ z = pos.GetPositionZ();
+}
+
bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const
{
float dx1 = GetPositionX() - obj1->GetPositionX();
@@ -2402,123 +2431,33 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y,
else
UpdateAllowedPositionZ(x, y, z);
- /*
// if detection disabled, return first point
- if (!sWorld->getIntConfig(CONFIG_DETECT_POS_COLLISION))
- {
- UpdateGroundPositionZ(x, y, z); // update to LOS height if available
+ if (!sWorld->getBoolConfig(CONFIG_DETECT_POS_COLLISION))
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
- {
- CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()));
- Cell cell(p);
- cell.SetNoCreate();
-
- Trinity::NearUsedPosDo u_do(*this, searcher, absAngle, selector);
- Trinity::WorldObjectWorker<Trinity::NearUsedPosDo> worker(this, u_do);
-
- TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::NearUsedPosDo>, GridTypeMapContainer > grid_obj_worker(worker);
- TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::NearUsedPosDo>, WorldTypeMapContainer > world_obj_worker(worker);
-
- CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap(), *this, distance2d);
- cell_lock->Visit(cell_lock, world_obj_worker, *GetMap(), *this, distance2d);
- }
-
- // 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 if the point is already in LoS
+ if (IsWithinLOS(x, y, z))
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();
+ // remember first point
+ float first_x = x;
+ float first_y = y;
+ float first_z = z;
- // select in positions after current nodes (selection one by one)
- while (selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
+ // loop in a circle to look for a point in LoS using small steps
+ for (float angle = float(M_PI) / 8; angle < float(M_PI) * 2; angle += float(M_PI) / 8)
{
- GetNearPoint2D(x, y, distance2d, absAngle+angle);
+ GetNearPoint2D(x, y, distance2d + searcher_size, absAngle + angle);
z = GetPositionZ();
- UpdateGroundPositionZ(x, y, z); // update to LOS height if available
-
+ UpdateAllowedPositionZ(x, y, z);
if (IsWithinLOS(x, y, z))
return;
}
- // BAD BAD NEWS: all found pos (free and used) have LOS problem :(
+ // still not in LoS, give up and return first position found
x = first_x;
y = first_y;
-
- UpdateGroundPositionZ(x, y, z); // update to LOS height if available
- */
+ z = first_z;
}
bool WorldObject::GetClosePoint(float &x, float &y, float &z, float size, float distance2d, float angle, const WorldObject* forWho, bool force) const
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 123b1aa08e..68b8bda28c 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -365,6 +365,17 @@ class Object
struct Position
{
+ Position(float x = 0, float y = 0, float z = 0, float o = 0)
+ : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { }
+
+ Position(Position const& loc) { Relocate(loc); }
+
+ struct PositionXYStreamer
+ {
+ explicit PositionXYStreamer(Position& pos) : Pos(&pos) { }
+ Position* Pos;
+ };
+
struct PositionXYZStreamer
{
explicit PositionXYZStreamer(Position& pos) : m_pos(&pos) {}
@@ -382,19 +393,38 @@ struct Position
float m_positionZ;
float m_orientation;
+ bool operator==(Position const &a);
+
+ inline bool operator!=(Position const &a)
+ {
+ return !(operator==(a));
+ }
+
void Relocate(float x, float y)
- { m_positionX = x; m_positionY = y;}
+ {
+ m_positionX = x; m_positionY = y;
+ }
void Relocate(float x, float y, float z)
- { m_positionX = x; m_positionY = y; m_positionZ = z; }
+ {
+ m_positionX = x; m_positionY = y; m_positionZ = z;
+ }
void Relocate(float x, float y, float z, float orientation)
- { m_positionX = x; m_positionY = y; m_positionZ = z; m_orientation = orientation; }
+ {
+ m_positionX = x; m_positionY = y; m_positionZ = z; m_orientation = orientation;
+ }
void Relocate(const Position &pos)
- { m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; m_orientation = pos.m_orientation; }
+ {
+ m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; m_orientation = pos.m_orientation;
+ }
void Relocate(const Position* pos)
- { m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; m_orientation = pos->m_orientation; }
+ {
+ m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; m_orientation = pos->m_orientation;
+ }
void RelocateOffset(const Position &offset);
void SetOrientation(float orientation)
- { m_orientation = orientation; }
+ {
+ m_orientation = orientation;
+ }
float GetPositionX() const { return m_positionX; }
float GetPositionY() const { return m_positionY; }
@@ -402,17 +432,26 @@ struct Position
float GetOrientation() const { return m_orientation; }
void GetPosition(float &x, float &y) const
- { x = m_positionX; y = m_positionY; }
+ {
+ x = m_positionX; y = m_positionY;
+ }
void GetPosition(float &x, float &y, float &z) const
- { x = m_positionX; y = m_positionY; z = m_positionZ; }
+ {
+ x = m_positionX; y = m_positionY; z = m_positionZ;
+ }
void GetPosition(float &x, float &y, float &z, float &o) const
- { x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation; }
+ {
+ x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation;
+ }
void GetPosition(Position* pos) const
{
if (pos)
pos->Relocate(m_positionX, m_positionY, m_positionZ, m_orientation);
}
+ Position GetPosition() const { return *this; }
+
+
Position::PositionXYZStreamer PositionXYZStream()
{
return PositionXYZStreamer(*this);
@@ -425,39 +464,65 @@ struct Position
bool IsPositionValid() const;
float GetExactDist2dSq(float x, float y) const
- { float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; }
+ {
+ float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy;
+ }
float GetExactDist2d(const float x, const float y) const
- { return sqrt(GetExactDist2dSq(x, y)); }
+ {
+ return sqrt(GetExactDist2dSq(x, y));
+ }
float GetExactDist2dSq(const Position* pos) const
- { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; }
+ {
+ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy;
+ }
float GetExactDist2d(const Position* pos) const
- { return sqrt(GetExactDist2dSq(pos)); }
+ {
+ return sqrt(GetExactDist2dSq(pos));
+ }
float GetExactDistSq(float x, float y, float z) const
- { float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; }
+ {
+ float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz;
+ }
float GetExactDist(float x, float y, float z) const
- { return sqrt(GetExactDistSq(x, y, z)); }
+ {
+ return sqrt(GetExactDistSq(x, y, z));
+ }
float GetExactDistSq(const Position* pos) const
- { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; }
+ {
+ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz;
+ }
float GetExactDist(const Position* pos) const
- { return sqrt(GetExactDistSq(pos)); }
+ {
+ return sqrt(GetExactDistSq(pos));
+ }
void GetPositionOffsetTo(const Position & endPos, Position & retOffset) const;
float GetAngle(const Position* pos) const;
float GetAngle(float x, float y) const;
float GetRelativeAngle(const Position* pos) const
- { return GetAngle(pos) - m_orientation; }
+ {
+ return GetAngle(pos) - m_orientation;
+ }
float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
void GetSinCos(float x, float y, float &vsin, float &vcos) const;
bool IsInDist2d(float x, float y, float dist) const
- { return GetExactDist2dSq(x, y) < dist * dist; }
+ {
+ return GetExactDist2dSq(x, y) < dist * dist;
+ }
bool IsInDist2d(const Position* pos, float dist) const
- { return GetExactDist2dSq(pos) < dist * dist; }
+ {
+ return GetExactDist2dSq(pos) < dist * dist;
+ }
bool IsInDist(float x, float y, float z, float dist) const
- { return GetExactDistSq(x, y, z) < dist * dist; }
+ {
+ return GetExactDistSq(x, y, z) < dist * dist;
+ }
bool IsInDist(const Position* pos, float dist) const
- { return GetExactDistSq(pos) < dist * dist; }
+ {
+ return GetExactDistSq(pos) < dist * dist;
+ }
bool IsWithinBox(const Position& center, float xradius, float yradius, float zradius) const;
bool HasInArc(float arcangle, const Position* pos, float targetRadius = 0.0f) const;
@@ -479,10 +544,13 @@ struct Position
return fmod(o, 2.0f * static_cast<float>(M_PI));
}
};
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
+ByteBuffer& operator >> (ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
+ByteBuffer& operator >> (ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
+ByteBuffer& operator >> (ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
+
struct MovementInfo
{
@@ -785,6 +853,8 @@ class WorldObject : public Object, public WorldLocation
}
bool IsWithinLOS(float x, float y, float z) const;
bool IsWithinLOSInMap(const WorldObject* obj) const;
+ Position GetHitSpherePointFor(Position const& dest) const;
+ void GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) 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;
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 4d064f5afc..e887d6cb60 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -960,6 +960,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetCreateHealth(4 * petlevel);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - 30 - (petlevel / 4) + m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.006f));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel - 30 + (petlevel / 4) + m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.006f));
+ SetReactState(REACT_DEFENSIVE);
break;
}
case NPC_ARMY_OF_THE_DEAD:
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 41c4f3a1af..ece890078a 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -2189,8 +2189,8 @@ void Player::SendTeleportAckPacket()
GetSession()->SendPacket(&data);
}
-bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options)
-{
+bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options /*= 0*/, Unit *target /*= nullptr*/)
+{
if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation))
{
sLog->outError("TeleportTo: invalid map (%d) or invalid coordinates (X: %f, Y: %f, Z: %f, O: %f) given when teleporting player (GUID: %u, name: %s, map: %d, X: %f, Y: %f, Z: %f, O: %f).",
@@ -2288,6 +2288,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if (duel && GetMapId() != mapid && GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER)))
DuelComplete(DUEL_FLED);
+ if (!sScriptMgr->OnBeforePlayerTeleport(this, mapid, x, y, z, orientation, options, target))
+ return false;
+
if (GetMapId() == mapid)
{
//lets reset far teleport flag if it wasn't reset during chained teleports
@@ -3026,11 +3029,7 @@ void Player::SetGameMaster(bool on)
else
{
// restore phase
- uint32 newPhase = 0;
- AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
- if (!phases.empty())
- for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
- newPhase |= (*itr)->GetMiscValue();
+ uint32 newPhase = GetPhaseByAuras();
if (!newPhase)
newPhase = PHASEMASK_NORMAL;
@@ -3063,14 +3062,21 @@ void Player::SetGameMaster(bool on)
}
void Player::SetGMVisible(bool on)
-{
+{
+ const uint32 VISUAL_AURA = 37800;
+
if (on)
{
+ if (HasAura(VISUAL_AURA, 0))
+ RemoveAurasDueToSpell(VISUAL_AURA);
+
m_ExtraFlags &= ~PLAYER_EXTRA_GM_INVISIBLE; //remove flag
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER);
}
else
{
+ AddAura(VISUAL_AURA, this);
+
m_ExtraFlags |= PLAYER_EXTRA_GM_INVISIBLE; //add flag
SetAcceptWhispers(false);
@@ -5286,7 +5292,7 @@ void Player::CreateCorpse()
return;
}
- _uf = GetUInt32Value(UNIT_FIELD_BYTES_0);
+ _uf = getRace();
_pb = GetUInt32Value(PLAYER_BYTES);
_pb2 = GetUInt32Value(PLAYER_BYTES_2);
@@ -5577,11 +5583,11 @@ void Player::RepopAtGraveyard()
// note: this can be called also when the player is alive
// for example from WorldSession::HandleMovementOpcodes
- AreaTableEntry const* zone = GetAreaEntryByAreaID(GetAreaId());
+ AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());
// Such zones are considered unreachable as a ghost and the player must be automatically revived
// Xinef: Get Transport Check is not needed
- if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) /*|| GetTransport()*/ || GetPositionZ() < -500.0f)
+ if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) /*|| GetTransport()*/ || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
{
ResurrectPlayer(0.5f);
SpawnCorpseBones();
@@ -5618,8 +5624,10 @@ void Player::RepopAtGraveyard()
GetSession()->SendPacket(&data);
}
}
- else if (GetPositionZ() < -500.0f)
+ else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
+
+ RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
}
bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone)
@@ -5671,7 +5679,7 @@ void Player::UpdateLocalChannels(uint32 newZone)
if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar())
return; // The client handles it automatically after loading, but not after teleporting
- AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone);
+ AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(newZone);
if (!current_zone)
return;
@@ -6894,45 +6902,46 @@ void Player::CheckAreaExploreAndOutdoor()
return;
bool isOutdoor = IsOutdoors();
- uint32 areaFlag = GetAreaFlagByAreaID(GetAreaId());
-
+ uint32 areaId = GetBaseMap()->GetAreaId(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor);
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
+
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY);
- if (areaFlag == 0xffff)
+ if (!areaId)
return;
- int offset = areaFlag / 32;
+
+ if (!areaEntry)
+ {
+ sLog->outError("Player '%s' (%u) discovered unknown area (x: %f y: %f z: %f map: %u)",
+ GetName().c_str(), GetGUIDLow(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
+ return;
+ }
+
+ uint32 offset = areaEntry->exploreFlag / 32;
if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
{
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
- 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 < %u ).", areaFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE);
+ 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 < %u ).", areaEntry->flags, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE);
#endif
return;
}
- uint32 val = (uint32)(1 << (areaFlag % 32));
+ uint32 val = (uint32)(1 << (areaEntry->exploreFlag % 32));
uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
if (!(currFields & val))
{
SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val));
- UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA, GetAreaId());
-
- AreaTableEntry const* areaEntry = GetAreaEntryByAreaFlagAndMap(areaFlag, GetMapId());
- if (!areaEntry)
- {
- sLog->outError("Player %u discovered unknown area (x: %f y: %f z: %f map: %u", GetGUIDLow(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
- return;
- }
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA, areaId);
if (areaEntry->area_level > 0)
{
- uint32 area = areaEntry->ID;
if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
{
- SendExplorationExperience(area, 0);
+ SendExplorationExperience(areaId, 0);
}
else
{
@@ -6958,10 +6967,10 @@ void Player::CheckAreaExploreAndOutdoor()
}
GiveXP(XP, NULL);
- SendExplorationExperience(area, XP);
+ SendExplorationExperience(areaId, XP);
}
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
- sLog->outDetail("Player %u discovered a new area: %u", GetGUIDLow(), area);
+ sLog->outDetail("Player %u discovered a new area: %u", GetGUIDLow(), areaId);
#endif
}
}
@@ -7528,12 +7537,14 @@ void Player::UpdateArea(uint32 newArea)
// pussywizard: inform instance, needed for Icecrown Citadel
if (InstanceScript* instance = GetInstanceScript())
instance->OnPlayerAreaUpdate(this, m_areaUpdateId, newArea);
+
+ sScriptMgr->OnPlayerUpdateArea(this, m_areaUpdateId, newArea);
// FFA_PVP flags are area and not zone id dependent
// so apply them accordingly
m_areaUpdateId = newArea;
- AreaTableEntry const* area = GetAreaEntryByAreaID(newArea);
+ AreaTableEntry const* area = sAreaTableStore.LookupEntry(newArea);
bool oldFFAPvPArea = pvpInfo.IsInFFAPvPArea;
pvpInfo.IsInFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);
UpdatePvPState(true);
@@ -7568,7 +7579,7 @@ void Player::UpdateArea(uint32 newArea)
}
// Xinef: area should inherit zone flags
- AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone);
+ AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone);
uint32 areaFlags = area->flags;
bool isSanctuary = area->IsSanctuary();
bool isInn = area->IsInn(GetTeamId(true));
@@ -7656,7 +7667,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
// zone changed, so area changed as well, update it
UpdateArea(newArea);
- AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone);
+ AreaTableEntry const* zone = sAreaTableStore.LookupEntry(newZone);
if (!zone)
return;
@@ -9258,6 +9269,12 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true);
permission = OWNER_PERMISSION;
+ //Inform instance if creature is skinned.
+ if (InstanceScript* mapInstance = creature->GetInstanceScript())
+ {
+ mapInstance->CreatureLooted(creature, LOOT_SKINNING);
+ }
+
// Xinef: Set new loot recipient
creature->SetLootRecipient(this, false);
}
@@ -20736,7 +20753,7 @@ void Player::Say(const std::string& text, const uint32 language)
sScriptMgr->OnPlayerChat(this, CHAT_MSG_SAY, language, _text);
WorldPacket data;
- ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, Language(language), this, this, text);
+ ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, Language(language), this, this, _text);
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true);
}
@@ -20746,7 +20763,7 @@ void Player::Yell(const std::string& text, const uint32 language)
sScriptMgr->OnPlayerChat(this, CHAT_MSG_YELL, language, _text);
WorldPacket data;
- ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, Language(language), this, this, text);
+ ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, Language(language), this, this, _text);
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true);
}
@@ -20756,7 +20773,7 @@ void Player::TextEmote(const std::string& text)
sScriptMgr->OnPlayerChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text);
WorldPacket data;
- ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, text);
+ ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text);
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT));
}
@@ -20773,14 +20790,14 @@ void Player::Whisper(const std::string& text, uint32 language, uint64 receiver)
sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, language, _text, rPlayer);
WorldPacket data;
- ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, Language(language), this, this, text);
+ ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, Language(language), this, this, _text);
rPlayer->GetSession()->SendPacket(&data);
// rest stuff shouldn't happen in case of addon message
if (isAddonMessage)
return;
- ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, Language(language), rPlayer, rPlayer, text);
+ ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, Language(language), rPlayer, rPlayer, _text);
GetSession()->SendPacket(&data);
if (!isAcceptWhispers() && !IsGameMaster() && !rPlayer->IsGameMaster())
@@ -22658,19 +22675,30 @@ bool Player::IsVisibleGloballyFor(Player const* u) const
}
template<class T>
-inline void UpdateVisibilityOf_helper(T* /*target*/, std::vector<Unit*>& /*v*/)
+inline void UpdateVisibilityOf_helper(Player::ClientGUIDs& s64, T* target, std::vector<Unit*>& /*v*/)
+{
+ s64.insert(target->GetGUID());
+}
+
+template<>
+inline void UpdateVisibilityOf_helper(Player::ClientGUIDs& s64, GameObject* target, std::vector<Unit*>& /*v*/)
{
+ // @HACK: This is to prevent objects like deeprun tram from disappearing when player moves far from its spawn point while riding it
+ if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
+ s64.insert(target->GetGUID());
}
template<>
-inline void UpdateVisibilityOf_helper(Creature* target, std::vector<Unit*>& v)
+inline void UpdateVisibilityOf_helper(Player::ClientGUIDs& s64, Creature* target, std::vector<Unit*>& v)
{
+ s64.insert(target->GetGUID());
v.push_back(target);
}
template<>
-inline void UpdateVisibilityOf_helper(Player* target, std::vector<Unit*>& v)
+inline void UpdateVisibilityOf_helper(Player::ClientGUIDs& s64, Player* target, std::vector<Unit*>& v)
{
+ s64.insert(target->GetGUID());
v.push_back(target);
}
@@ -22784,9 +22812,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::vector<Unit*>&
if (CanSeeOrDetect(target, false, true))
{
target->BuildCreateUpdateBlockForPlayer(&data, this);
- m_clientGUIDs.insert(target->GetGUID());
-
- UpdateVisibilityOf_helper(target, visibleNow);
+ UpdateVisibilityOf_helper(m_clientGUIDs, target, visibleNow);
}
}
}
@@ -23610,8 +23636,8 @@ void Player::UpdateForQuestWorldObjects()
GetSession()->SendPacket(&packet);
}
-void Player::SummonIfPossible(bool agree)
-{
+void Player::SummonIfPossible(bool agree, uint32 summoner_guid)
+{
if (!agree)
{
m_summon_expire = 0;
@@ -23631,7 +23657,7 @@ void Player::SummonIfPossible(bool agree)
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS, 1);
- TeleportTo(m_summon_mapid, m_summon_x, m_summon_y, m_summon_z, GetOrientation());
+ TeleportTo(m_summon_mapid, m_summon_x, m_summon_y, m_summon_z, GetOrientation(), 0, ObjectAccessor::FindPlayer(summoner_guid));
}
void Player::RemoveItemDurations(Item* item)
@@ -25226,22 +25252,19 @@ void Player::_LoadSkills(PreparedQueryResult result)
}
uint32 Player::GetPhaseMaskForSpawn() const
-{
- uint32 phase = PHASEMASK_NORMAL;
- if (!IsGameMaster())
- phase = GetPhaseMask();
- else
- {
- AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
- if (!phases.empty())
- phase = phases.front()->GetMiscValue();
- }
+{
+ uint32 phase = IsGameMaster() ? GetPhaseByAuras() : GetPhaseMask();
+
+ if (!phase)
+ phase = PHASEMASK_NORMAL;
+
// some aura phases include 1 normal map in addition to phase itself
- if (uint32 n_phase = phase & ~PHASEMASK_NORMAL)
+ uint32 n_phase = phase & ~PHASEMASK_NORMAL;
+ if (n_phase > 0)
return n_phase;
- return PHASEMASK_NORMAL;
+ return phase;
}
InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) const
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index a0f3ec042d..3e879bf1e6 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1096,10 +1096,10 @@ class Player : public Unit, public GridObject<Player>
SetFloatValue(UNIT_FIELD_COMBATREACH, scale * DEFAULT_COMBAT_REACH);
}
- bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0);
- bool TeleportTo(WorldLocation const &loc, uint32 options = 0)
+ bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0, Unit *target = nullptr);
+ bool TeleportTo(WorldLocation const &loc, uint32 options = 0, Unit *target = nullptr)
{
- return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options);
+ return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options, target);
}
bool TeleportToEntryPoint();
@@ -1114,7 +1114,7 @@ class Player : public Unit, public GridObject<Player>
}
bool IsSummonAsSpectator() const { return m_summon_asSpectator && m_summon_expire >= time(NULL); }
void SetSummonAsSpectator(bool on) { m_summon_asSpectator = on; }
- void SummonIfPossible(bool agree);
+ void SummonIfPossible(bool agree, uint32 summoner_guid);
time_t GetSummonExpireTimer() const { return m_summon_expire; }
bool Create(uint32 guidlow, CharacterCreateInfo* createInfo);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 5166c71504..d0bcf5d290 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -3395,6 +3395,15 @@ int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
return 0;
}
+bool Unit::CanMoveDuringChannel() const
+{
+ if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
+ if (spell->getState() != SPELL_STATE_FINISHED)
+ return spell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) && spell->IsChannelActive();
+
+ return false;
+}
+
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
{
return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
@@ -13690,7 +13699,7 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell*
if (!spellInfo || castTime < 0)
return;
- if (spellInfo->IsChanneled() && !(spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION))
+ if (spellInfo->IsChanneled() && spellInfo->HasAura(SPELL_AURA_MOUNTED))
return;
// called from caster
@@ -14493,7 +14502,7 @@ void CharmInfo::InitPossessCreateSpells()
{
uint32 spellId = _unit->ToCreature()->m_spells[i];
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (spellInfo && !spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
+ if (spellInfo)
{
if (spellInfo->IsPassive())
_unit->CastSpell(_unit, spellInfo, true);
@@ -14523,7 +14532,7 @@ void CharmInfo::InitCharmCreateSpells()
uint32 spellId = _unit->ToCreature()->m_spells[x];
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (!spellInfo || spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
+ if (!spellInfo)
{
_charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
continue;
@@ -17547,6 +17556,17 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, i
return missChance;
}
+uint32 Unit::GetPhaseByAuras() const
+{
+ uint32 currentPhase = 0;
+ AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
+ if (!phases.empty())
+ for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
+ currentPhase |= (*itr)->GetMiscValue();
+
+ return currentPhase;
+}
+
void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
{
if (newPhaseMask == GetPhaseMask())
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index a390a6359d..bb8dca9134 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -2048,6 +2048,9 @@ class Unit : public WorldObject
// delayed+channeled spells are always interrupted
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true, bool bySelf = false);
+ // Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
+ bool CanMoveDuringChannel() const;
+
Spell* GetCurrentSpell(CurrentSpellTypes spellType) const { return m_currentSpells[spellType]; }
Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; }
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
@@ -2122,6 +2125,7 @@ class Unit : public WorldObject
void SetModelVisible(bool on);
// common function for visibility checks for player/creatures with detection code
+ uint32 GetPhaseByAuras() const;
void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask
void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false);
diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp
index 096825803b..26670a333a 100644
--- a/src/server/game/Events/GameEventMgr.cpp
+++ b/src/server/game/Events/GameEventMgr.cpp
@@ -19,6 +19,8 @@
#include "GameObjectAI.h"
#include "Transport.h"
+#include <time.h>
+
bool GameEventMgr::CheckOneGameEvent(uint16 entry) const
{
switch (mGameEvent[entry].state)
@@ -194,8 +196,8 @@ void GameEventMgr::LoadFromDB()
{
{
uint32 oldMSTime = getMSTime();
- // 1 2 3 4 5 6 7 8
- QueryResult result = WorldDatabase.Query("SELECT eventEntry, UNIX_TIMESTAMP(start_time), UNIX_TIMESTAMP(end_time), occurence, length, holiday, description, world_event FROM game_event");
+ // 1 2 3 4 5 6 7 8 9
+ QueryResult result = WorldDatabase.Query("SELECT eventEntry, UNIX_TIMESTAMP(start_time), UNIX_TIMESTAMP(end_time), occurence, length, holiday, holidayStage, description, world_event FROM game_event");
if (!result)
{
mGameEvent.clear();
@@ -225,9 +227,13 @@ void GameEventMgr::LoadFromDB()
pGameEvent.length = fields[4].GetUInt64();
pGameEvent.holiday_id = HolidayIds(fields[5].GetUInt32());
- pGameEvent.state = (GameEventState)(fields[7].GetUInt8());
+ pGameEvent.holidayStage = fields[6].GetUInt8();
+ pGameEvent.description = fields[7].GetString();
+ pGameEvent.state = (GameEventState)(fields[8].GetUInt8());
pGameEvent.nextstart = 0;
+ ++count;
+
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);
@@ -241,11 +247,10 @@ void GameEventMgr::LoadFromDB()
sLog->outErrorDb("`game_event` game event id (%i) have not existed holiday id %u.", event_id, pGameEvent.holiday_id);
pGameEvent.holiday_id = HOLIDAY_NONE;
}
- }
- pGameEvent.description = fields[6].GetString();
+ SetHolidayEventTime(pGameEvent);
+ }
- ++count;
}
while (result->NextRow());
@@ -951,6 +956,45 @@ void GameEventMgr::LoadFromDB()
}
}
+void GameEventMgr::LoadHolidayDates()
+{
+ uint32 oldMSTime = getMSTime();
+
+ // 0 1 2
+ QueryResult result = WorldDatabase.Query("SELECT id, date_id, date_value FROM holiday_dates");
+
+ if (!result)
+ {
+ sLog->outString(">> Loaded 0 holiday dates. DB table `holiday_dates` is empty.");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 holidayId = fields[0].GetUInt32();
+ HolidaysEntry* entry = const_cast<HolidaysEntry*>(sHolidaysStore.LookupEntry(holidayId));
+ if (!entry)
+ {
+ sLog->outErrorDb("holiday_dates entry has invalid holiday id %u.", holidayId);
+ continue;
+ }
+ uint8 dateId = fields[1].GetUInt8();
+ if (dateId >= MAX_HOLIDAY_DATES)
+ {
+ sLog->outErrorDb("holiday_dates entry has out of range date_id %u.", dateId);
+ continue;
+ }
+ entry->Date[dateId] = fields[2].GetUInt32();
+ modifiedHolidays.insert(entry->Id);
+ ++count;
+
+ } while (result->NextRow());
+
+ sLog->outString(">> Loaded %u holiday dates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
uint32 GameEventMgr::GetNPCFlag(Creature* cr)
{
uint32 mask = 0;
@@ -1669,6 +1713,83 @@ void GameEventMgr::RunSmartAIScripts(uint16 event_id, bool activate)
}
}
+void GameEventMgr::SetHolidayEventTime(GameEventData& event)
+{
+ if (!event.holidayStage) // Ignore holiday
+ return;
+
+ const HolidaysEntry* holiday = sHolidaysStore.LookupEntry(event.holiday_id);
+
+ if (!holiday->Date[0] || !holiday->Duration[0]) // Invalid definitions
+ {
+ sLog->outErrorDb("Missing date or duration for holiday %u.", event.holiday_id);
+ return;
+ }
+
+ uint8 stageIndex = event.holidayStage - 1;
+ event.length = holiday->Duration[stageIndex] * HOUR / MINUTE;
+
+ time_t stageOffset = 0;
+ for (int i = 0; i < stageIndex; ++i)
+ stageOffset += holiday->Duration[i] * HOUR;
+
+ switch (holiday->CalendarFilterType)
+ {
+ case -1: // Yearly
+ event.occurence = YEAR / MINUTE; // Not all too useful
+ break;
+ case 0: // Weekly
+ event.occurence = WEEK / MINUTE;
+ break;
+ case 1: // Defined dates only (Darkmoon Faire)
+ break;
+ case 2: // Only used for looping events (Call to Arms)
+ break;
+ }
+
+ if (holiday->Looping)
+ {
+ event.occurence = 0;
+ for (int i = 0; i < MAX_HOLIDAY_DURATIONS && holiday->Duration[i]; ++i)
+ event.occurence += holiday->Duration[i] * HOUR / MINUTE;
+ }
+
+ bool singleDate = ((holiday->Date[0] >> 24) & 0x1F) == 31; // Events with fixed date within year have - 1
+
+ time_t curTime = time(NULL);
+ for (int i = 0; i < MAX_HOLIDAY_DATES && holiday->Date[i]; ++i)
+ {
+ uint32 date = holiday->Date[i];
+
+ tm timeInfo;
+ if (singleDate)
+ timeInfo.tm_year = localtime(&curTime)->tm_year - 1; // First try last year (event active through New Year)
+ else
+ timeInfo.tm_year = ((date >> 24) & 0x1F) + 100;
+ timeInfo.tm_mon = (date >> 20) & 0xF;
+ timeInfo.tm_mday = ((date >> 14) & 0x3F) + 1;
+ timeInfo.tm_hour = (date >> 6) & 0x1F;
+ timeInfo.tm_min = date & 0x3F;
+ timeInfo.tm_sec = 0;
+ timeInfo.tm_isdst = -1;
+ tm tmCopy = timeInfo;
+
+ time_t startTime = mktime(&timeInfo);
+ if (curTime < startTime + event.length * MINUTE)
+ {
+ event.start = startTime + stageOffset;
+ return;
+ }
+ else if (singleDate)
+ {
+ tmCopy.tm_year = localtime(&curTime)->tm_year; // This year
+ event.start = mktime(&tmCopy) + stageOffset;
+ return;
+ }
+ }
+ sLog->outString("No suitable start date found for holiday %u.", event.holiday_id);
+}
+
bool IsHolidayActive(HolidayIds id)
{
if (id == HOLIDAY_NONE)
diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h
index 91eb981102..64f1659882 100644
--- a/src/server/game/Events/GameEventMgr.h
+++ b/src/server/game/Events/GameEventMgr.h
@@ -50,6 +50,7 @@ struct GameEventData
uint32 occurence; // time between end and start
uint32 length; // length of the event (minutes) after finishing all conditions
HolidayIds holiday_id;
+ uint8 holidayStage;
GameEventState state; // state of the game event, these are saved into the game_event table on change!
GameEventConditionMap conditions; // conditions to finish
std::set<uint16 /*gameevent id*/> prerequisite_events; // events that must be completed before starting this event
@@ -95,6 +96,7 @@ class GameEventMgr
bool CheckOneGameEvent(uint16 entry) const;
uint32 NextCheck(uint16 entry) const;
void LoadFromDB();
+ void LoadHolidayDates();
uint32 Update();
bool IsActiveEvent(uint16 event_id) { return (m_ActiveEvents.find(event_id) != m_ActiveEvents.end()); }
uint32 StartSystem();
@@ -128,6 +130,7 @@ class GameEventMgr
bool hasGameObjectQuestActiveEventExcept(uint32 quest_id, uint16 event_id);
bool hasCreatureActiveEventExcept(uint32 creature_guid, uint16 event_id);
bool hasGameObjectActiveEventExcept(uint32 go_guid, uint16 event_id);
+ void SetHolidayEventTime(GameEventData& event);
typedef std::list<uint32> GuidList;
typedef std::list<uint32> IdList;
@@ -162,6 +165,7 @@ class GameEventMgr
public:
GameEventGuidMap mGameEventCreatureGuids;
GameEventGuidMap mGameEventGameobjectGuids;
+ std::set<uint32> modifiedHolidays;
};
#define sGameEventMgr ACE_Singleton<GameEventMgr, ACE_Null_Mutex>::instance()
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 125b6d6c7c..c82ad20e9c 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1171,9 +1171,9 @@ void ObjectMgr::LoadEquipmentTemplates()
if (!equipmentInfo.ItemEntry[i])
continue;
- ItemEntry const* dbcItem = sItemStore.LookupEntry(equipmentInfo.ItemEntry[i]);
+ const ItemTemplate* item = GetItemTemplate(equipmentInfo.ItemEntry[i]);
- if (!dbcItem)
+ if (!item)
{
sLog->outErrorDb("Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u, forced to 0.",
equipmentInfo.ItemEntry[i], i+1, entry);
@@ -1181,15 +1181,15 @@ void ObjectMgr::LoadEquipmentTemplates()
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)
+ if (item->InventoryType != INVTYPE_WEAPON &&
+ item->InventoryType != INVTYPE_SHIELD &&
+ item->InventoryType != INVTYPE_RANGED &&
+ item->InventoryType != INVTYPE_2HWEAPON &&
+ item->InventoryType != INVTYPE_WEAPONMAINHAND &&
+ item->InventoryType != INVTYPE_WEAPONOFFHAND &&
+ item->InventoryType != INVTYPE_HOLDABLE &&
+ item->InventoryType != INVTYPE_THROWN &&
+ item->InventoryType != INVTYPE_RANGEDRIGHT)
{
sLog->outErrorDb("Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u is not equipable in a hand, forced to 0.",
equipmentInfo.ItemEntry[i], i+1, entry);
@@ -2266,7 +2266,6 @@ void ObjectMgr::LoadItemTemplates()
_itemTemplateStore.rehash(result->GetRowCount());
uint32 count = 0;
- bool enforceDBCAttributes = sWorld->getBoolConfig(CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES);
do
{
@@ -2383,53 +2382,6 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.FlagsCu = fields[137].GetUInt32();
// Checks
-
- ItemEntry const* dbcitem = sItemStore.LookupEntry(entry);
-
- if (dbcitem)
- {
- if (itemTemplate.Class != dbcitem->Class)
- {
- sLog->outErrorDb("Item (Entry: %u) does not have a correct class %u, must be %u .", entry, itemTemplate.Class, dbcitem->Class);
- if (enforceDBCAttributes)
- itemTemplate.Class = dbcitem->Class;
- }
-
- if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclass)
- {
- sLog->outError("Item (Entry: %u) does not have a correct SoundOverrideSubclass (%i), must be %i .", entry, itemTemplate.SoundOverrideSubclass, dbcitem->SoundOverrideSubclass);
- if (enforceDBCAttributes)
- itemTemplate.SoundOverrideSubclass = dbcitem->SoundOverrideSubclass;
- }
- if (itemTemplate.Material != dbcitem->Material)
- {
- sLog->outErrorDb("Item (Entry: %u) does not have a correct material (%i), must be %i .", entry, itemTemplate.Material, dbcitem->Material);
- if (enforceDBCAttributes)
- itemTemplate.Material = dbcitem->Material;
- }
- if (itemTemplate.InventoryType != dbcitem->InventoryType)
- {
- sLog->outErrorDb("Item (Entry: %u) does not have a correct inventory type (%u), must be %u .", entry, itemTemplate.InventoryType, dbcitem->InventoryType);
- if (enforceDBCAttributes)
- itemTemplate.InventoryType = dbcitem->InventoryType;
- }
- if (itemTemplate.DisplayInfoID != dbcitem->DisplayId)
- {
- sLog->outErrorDb("Item (Entry: %u) does not have a correct display id (%u), must be %u .", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayId);
- if (enforceDBCAttributes)
- itemTemplate.DisplayInfoID = dbcitem->DisplayId;
- }
- if (itemTemplate.Sheath != dbcitem->Sheath)
- {
- sLog->outErrorDb("Item (Entry: %u) does not have a correct sheathid (%u), must be %u .", entry, itemTemplate.Sheath, dbcitem->Sheath);
- if (enforceDBCAttributes)
- itemTemplate.Sheath = dbcitem->Sheath;
- }
-
- }
- else
- sLog->outErrorDb("Item (Entry: %u) does not exist in item.dbc! (not correct id?).", entry);
-
if (itemTemplate.Class >= MAX_ITEM_CLASS)
{
sLog->outErrorDb("Item (Entry: %u) has wrong Class value (%u)", entry, itemTemplate.Class);
@@ -2720,7 +2672,7 @@ void ObjectMgr::LoadItemTemplates()
itemTemplate.ItemSet = 0;
}
- if (itemTemplate.Area && !GetAreaEntryByAreaID(itemTemplate.Area))
+ if (itemTemplate.Area && !sAreaTableStore.LookupEntry(itemTemplate.Area))
sLog->outErrorDb("Item (Entry: %u) has wrong Area (%u)", entry, itemTemplate.Area);
if (itemTemplate.Map && !sMapStore.LookupEntry(itemTemplate.Map))
@@ -4022,7 +3974,7 @@ void ObjectMgr::LoadQuests()
// client quest log visual (area case)
if (qinfo->ZoneOrSort > 0)
{
- if (!GetAreaEntryByAreaID(qinfo->ZoneOrSort))
+ if (!sAreaTableStore.LookupEntry(qinfo->ZoneOrSort))
{
sLog->outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
qinfo->GetQuestId(), qinfo->ZoneOrSort);
@@ -5845,7 +5797,7 @@ void ObjectMgr::LoadGraveyardZones()
continue;
}
- AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId);
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId);
if (!areaEntry)
{
sLog->outErrorDb("Table `game_graveyard_zone` has a record for not existing zone id (%u), skipped.", zoneId);
@@ -7893,7 +7845,7 @@ void ObjectMgr::LoadFishingBaseSkillLevel()
uint32 entry = fields[0].GetUInt32();
int32 skill = fields[1].GetInt16();
- AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry);
+ AreaTableEntry const* fArea = sAreaTableStore.LookupEntry(entry);
if (!fArea)
{
sLog->outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist", entry);
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index d85705b00c..1340400aa6 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -721,6 +721,7 @@ class ObjectMgr
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry);
ItemTemplate const* GetItemTemplate(uint32 entry);
ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; }
+ std::vector<ItemTemplate*> const* GetItemTemplateStoreFast() const { return &_itemTemplateStoreFast; }
ItemSetNameEntry const* GetItemSetNameEntry(uint32 itemId)
{
diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h
index ab35c901fd..5554a731e4 100644
--- a/src/server/game/Grids/GridDefines.h
+++ b/src/server/game/Grids/GridDefines.h
@@ -23,7 +23,7 @@ class Player;
#define MAX_NUMBER_OF_GRIDS 64
-#define SIZE_OF_GRIDS 533.33333f
+#define SIZE_OF_GRIDS 533.3333f
#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2)
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
@@ -213,7 +213,7 @@ namespace Trinity
inline bool IsValidMapCoord(float x, float y, float z)
{
- return IsValidMapCoord(x, y) && isfinite(z);
+ return IsValidMapCoord(x, y) && IsValidMapCoord(z);
}
inline bool IsValidMapCoord(float x, float y, float z, float o)
diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp
index 888bf00d77..c09ce07a12 100644
--- a/src/server/game/Handlers/CalendarHandler.cpp
+++ b/src/server/game/Handlers/CalendarHandler.cpp
@@ -34,6 +34,7 @@ Copied events should probably have a new owner
#include "GuildMgr.h"
#include "ArenaTeamMgr.h"
#include "WorldSession.h"
+#include "GameEventMgr.h"
void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/)
{
@@ -139,11 +140,10 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/)
data.append(dataBuffer);
// TODO: Fix this, how we do know how many and what holidays to send?
- uint32 holidayCount = 0;
- data << uint32(holidayCount);
- for (uint32 i = 0; i < holidayCount; ++i)
+ data << uint32(sGameEventMgr->modifiedHolidays.size());
+ for (uint32 entry : sGameEventMgr->modifiedHolidays)
{
- HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(666);
+ HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(entry);
data << uint32(holiday->Id); // m_ID
data << uint32(holiday->Region); // m_region, might be looping
diff --git a/src/server/game/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp
index 9b0cddccfc..a74a3e91c6 100644
--- a/src/server/game/Handlers/ChannelHandler.cpp
+++ b/src/server/game/Handlers/ChannelHandler.cpp
@@ -27,7 +27,7 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
if (!channel)
return;
- AreaTableEntry const* zone = GetAreaEntryByAreaID(GetPlayer()->GetZoneId());
+ AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());
if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))
return;
}
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 5abcd8a8e9..3679c824ca 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -1979,30 +1979,50 @@ void WorldSession::HandleEquipmentSetUse(WorldPacket &recvData)
item = _player->GetItemByGuid(itemGuid);
uint16 dstpos = i | (INVENTORY_SLOT_BAG_0 << 8);
+
+ InventoryResult msg;
+
+ Item* uItem = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
+ if (uItem) {
+ if (uItem->IsEquipped()) {
+ msg = _player->CanUnequipItem(dstpos, true);
+ if (msg != EQUIP_ERR_OK) {
+ _player->SendEquipError(msg, uItem, NULL);
+ continue;
+ }
+ }
- if (!item)
- {
- Item* uItem = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
- if (!uItem)
- continue;
-
- ItemPosCountVec sDest;
- InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sDest, uItem, false);
- if (msg == EQUIP_ERR_OK)
+ if (!item)
{
- _player->RemoveItem(INVENTORY_SLOT_BAG_0, i, true);
- _player->StoreItem(sDest, uItem, true);
- }
- else
- _player->SendEquipError(msg, uItem, NULL);
+ ItemPosCountVec sDest;
+ msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sDest, uItem, false);
+ if (msg == EQUIP_ERR_OK)
+ {
+ _player->RemoveItem(INVENTORY_SLOT_BAG_0, i, true);
+ _player->StoreItem(sDest, uItem, true);
+ }
+ else
+ _player->SendEquipError(msg, uItem, NULL);
- continue;
+ continue;
+ }
}
- if (item->GetPos() == dstpos)
- continue;
+ if (item) {
+ if (item->GetPos() == dstpos)
+ continue;
- _player->SwapItem(item->GetPos(), dstpos);
+ if (!item->IsEquipped()) {
+ uint16 _candidatePos;
+ msg = _player->CanEquipItem(NULL_SLOT, _candidatePos, item, true);
+ if (msg != EQUIP_ERR_OK) {
+ _player->SendEquipError(msg, item, NULL);
+ continue;
+ }
+ }
+
+ _player->SwapItem(item->GetPos(), dstpos);
+ }
}
WorldPacket data(SMSG_EQUIPMENT_SET_USE_RESULT, 1);
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index bf15832c50..ec48d7221b 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -360,7 +360,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData)
continue;
std::string aname;
- if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
+ if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(itr->second->GetZoneId()))
aname = areaEntry->area_name[GetSessionDbcLocale()];
bool s_show = true;
@@ -1934,7 +1934,7 @@ void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recv_data*/)
return;
}
- AreaTableEntry const* atEntry = GetAreaEntryByAreaID(_player->GetAreaId());
+ AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId());
if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2))
return;
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 1feb9ac65e..8d435b303d 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -474,16 +474,26 @@ void WorldSession::HandleMovementOpcodes(WorldPacket & recvData)
plrMover->UpdateFallInformationIfNeed(movementInfo, opcode);
- if (movementInfo.pos.GetPositionZ() < -500.0f)
+ if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()))
if (!plrMover->GetBattleground() || !plrMover->GetBattleground()->HandlePlayerUnderMap(_player))
{
if (plrMover->IsAlive())
{
+ plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
// player can be alive if GM
if (plrMover->IsAlive())
plrMover->KillPlayer();
}
+ else if (!plrMover->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS))
+ {
+ WorldSafeLocsEntry const* grave = sObjectMgr->GetClosestGraveyard(plrMover->GetPositionX(), plrMover->GetPositionY(), plrMover->GetPositionZ(), plrMover->GetMapId(), plrMover->GetTeamId());
+
+ if ( grave)
+ plrMover->TeleportTo(grave->map_id, grave->x, grave->y, grave->z, plrMover->GetOrientation());
+ plrMover->Relocate(grave->x, grave->y, grave->z, plrMover->GetOrientation());
+ }
+
plrMover->StopMovingOnCurrentPos(); // pussywizard: moving corpse can't release spirit
}
}
@@ -711,5 +721,5 @@ void WorldSession::HandleSummonResponseOpcode(WorldPacket& recvData)
agree = false;
}
_player->SetSummonAsSpectator(false);
- _player->SummonIfPossible(agree);
+ _player->SummonIfPossible(agree, summoner_guid);
}
diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h
index 70c1b5c176..3d1958d604 100644
--- a/src/server/game/Instances/InstanceScript.h
+++ b/src/server/game/Instances/InstanceScript.h
@@ -134,6 +134,9 @@ class InstanceScript : public ZoneScript
//On load
virtual void Load(char const* data) { LoadBossState(data); }
+ //Called when creature is Looted
+ virtual void CreatureLooted(Creature* /*creature*/, LootType) {}
+
//When save is needed, this function generates the data
virtual std::string GetSaveData() { return GetBossSaveData(); }
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index f1f2875dcf..e25cd1c362 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -84,7 +84,7 @@ class LootTemplate::LootGroup // A set of loot def
bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
bool HasQuestDropForPlayer(Player const* player) const;
// The same for active quests of the player
- void Process(Loot& loot, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
+ void Process(Loot& loot, Player const *player, LootStore const& lootstore, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
float TotalChance() const; // Overall chance for the group
@@ -98,7 +98,7 @@ class LootTemplate::LootGroup // A set of loot def
LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
- LootStoreItem const* Roll(Loot& loot, uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances
+ LootStoreItem const* Roll(Loot& loot, Player const *player, LootStore const& store, uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances
// This class must never be copied - storing pointers
LootGroup(LootGroup const&);
@@ -279,19 +279,23 @@ 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(bool rate) const
+bool LootStoreItem::Roll(bool rate, Player const *player, Loot& loot, LootStore const& store) const
{
- if (chance >= 100.0f)
+ float _chance = chance;
+
+ sScriptMgr->OnItemRoll(player, this, _chance, loot, store);
+
+ if (_chance >= 100.0f)
return true;
if (mincountOrRef < 0) // reference case
- return roll_chance_f(chance* (rate ? sWorld->getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
+ return roll_chance_f(_chance* (rate ? sWorld->getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
float qualityModifier = pProto && rate ? sWorld->getRate(qualityToRate[pProto->Quality]) : 1.0f;
- return roll_chance_f(chance*qualityModifier);
+ return roll_chance_f(_chance*qualityModifier);
}
// Checks correctness of values
@@ -462,7 +466,7 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
items.reserve(MAX_NR_LOOT_ITEMS);
quest_items.reserve(MAX_NR_QUEST_ITEMS);
- tab->Process(*this, store.IsRatesAllowed(), lootMode, lootOwner); // Processing is done there, callback via Loot::AddItem()
+ tab->Process(*this, store, lootMode, lootOwner); // Processing is done there, callback via Loot::AddItem()
// Setting access rights for group loot case
Group* group = lootOwner->GetGroup();
@@ -1102,7 +1106,7 @@ void LootTemplate::LootGroup::AddEntry(LootStoreItem* item)
}
// Rolls an item from the group, returns NULL if all miss their chances
-LootStoreItem const* LootTemplate::LootGroup::Roll(Loot& loot, uint16 lootMode) const
+LootStoreItem const* LootTemplate::LootGroup::Roll(Loot& loot, Player const *player, LootStore const& store, uint16 lootMode) const
{
LootStoreItemList possibleLoot = ExplicitlyChanced;
possibleLoot.remove_if(LootGroupInvalidSelector(loot, lootMode));
@@ -1114,10 +1118,14 @@ LootStoreItem const* LootTemplate::LootGroup::Roll(Loot& loot, uint16 lootMode)
for (LootStoreItemList::const_iterator itr = possibleLoot.begin(); itr != possibleLoot.end(); ++itr) // check each explicitly chanced entry in the template and modify its chance based on quality.
{
LootStoreItem* item = *itr;
- if (item->chance >= 100.0f)
+ float chance = item->chance;
+
+ sScriptMgr->OnItemRoll(player, item, chance, loot, store);
+
+ if (chance >= 100.0f)
return item;
- roll -= item->chance;
+ roll -= chance;
if (roll < 0)
return item;
}
@@ -1169,9 +1177,9 @@ void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/)
}
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
-void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const
+void LootTemplate::LootGroup::Process(Loot& loot, Player const *player, LootStore const& store, uint16 lootMode) const
{
- if (LootStoreItem const* item = Roll(loot, lootMode))
+ if (LootStoreItem const* item = Roll(loot, player, store, lootMode))
loot.AddItem(*item);
}
@@ -1297,8 +1305,10 @@ void LootTemplate::CopyConditions(LootItem* li) const
}
// Rolls for every item in the template and adds the rolled items the the loot
-void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const* player, uint8 groupId) const
+void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId) const
{
+ bool rate = store.IsRatesAllowed();
+
if (groupId) // Group reference uses own processing of the group
{
if (groupId > Groups.size())
@@ -1307,7 +1317,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const*
if (!Groups[groupId - 1])
return;
- Groups[groupId-1]->Process(loot, lootMode);
+ Groups[groupId-1]->Process(loot, player, store, lootMode);
return;
}
@@ -1318,7 +1328,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const*
if (!(item->lootmode & lootMode)) // Do not add if mode mismatch
continue;
- if (!item->Roll(rate))
+ if (!item->Roll(rate, player, loot, store))
continue; // Bad luck for the entry
if (item->mincountOrRef < 0) // References processing
@@ -1328,12 +1338,12 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const*
continue; // Error message already printed at loading stage
uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
- sScriptMgr->OnAfterRefCount(item, maxcount);
+ sScriptMgr->OnAfterRefCount(player, loot, rate, lootMode, item, maxcount, store);
for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
- Referenced->Process(loot, rate, lootMode, player, item->group);
+ Referenced->Process(loot, store, lootMode, player, item->group);
} else {
// Plain entries (not a reference, not grouped)
- sScriptMgr->OnBeforeDropAddItem(player, loot, item);
+ sScriptMgr->OnBeforeDropAddItem(player, loot, rate, lootMode, item, store);
loot.AddItem(*item); // Chance is already checked, just add
}
}
@@ -1341,7 +1351,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const*
// Now processing groups
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
if (LootGroup* group = *i)
- group->Process(loot, lootMode);
+ group->Process(loot, player, store, lootMode);
}
// True if template includes at least 1 quest drop entry
@@ -1598,8 +1608,8 @@ void LoadLootTemplates_Fishing()
uint32 count = LootTemplates_Fishing.LoadAndCollectLootIds(lootIdSet);
// remove real entries and check existence loot
- for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i)
- if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
+ for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i)
+ if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i))
if (lootIdSet.find(areaEntry->ID) != lootIdSet.end())
lootIdSet.erase(areaEntry->ID);
@@ -1784,8 +1794,8 @@ void LoadLootTemplates_Mail()
uint32 count = LootTemplates_Mail.LoadAndCollectLootIds(lootIdSet);
// remove real entries and check existence loot
- for (uint32 i = 1; i < sMailTemplateStore.GetNumRows(); ++i)
- if (sMailTemplateStore.LookupEntry(i))
+ for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i)
+ if (sAreaTableStore.LookupEntry(i))
if (lootIdSet.find(i) != lootIdSet.end())
lootIdSet.erase(i);
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index 4af00d3f8b..fc08f030af 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -110,6 +110,7 @@ enum LootSlotType
class Player;
class LootStore;
class ConditionMgr;
+struct Loot;
struct LootStoreItem
{
@@ -129,7 +130,7 @@ struct LootStoreItem
group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount)
{}
- bool Roll(bool rate) const; // Checks if the entry takes it's chance (at loot generation)
+ bool Roll(bool rate, Player const *player, Loot& loot, LootStore const& store) const; // Checks if the entry takes it's chance (at loot generation)
bool IsValid(LootStore const& store, uint32 entry) const;
// Checks correctness of values
};
@@ -178,7 +179,6 @@ struct QuestItem
: index(_index), is_looted(_islooted) {}
};
-struct Loot;
class LootTemplate;
typedef std::vector<QuestItem> QuestItemList;
@@ -237,7 +237,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, bool rate, uint16 lootMode, Player const* player, uint8 groupId = 0) const;
+ void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0) const;
void CopyConditions(ConditionList conditions);
void CopyConditions(LootItem* li) const;
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index a14b89306d..4e6a595a55 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -32,7 +32,7 @@ union u_map_magic
};
u_map_magic MapMagic = { {'M','A','P','S'} };
-u_map_magic MapVersionMagic = { {'v','1','.','3'} };
+u_map_magic MapVersionMagic = { {'v','1','.','8'} };
u_map_magic MapAreaMagic = { {'A','R','E','A'} };
u_map_magic MapHeightMagic = { {'M','H','G','T'} };
u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
@@ -1200,13 +1200,15 @@ GridMap::GridMap()
_flags = 0;
// Area data
_gridArea = 0;
- _areaMap = NULL;
+ _areaMap = nullptr;
// Height level data
_gridHeight = INVALID_HEIGHT;
_gridGetHeight = &GridMap::getHeightFromFlat;
_gridIntHeightMultiplier = 0;
- m_V9 = NULL;
- m_V8 = NULL;
+ m_V9 = nullptr;
+ m_V8 = nullptr;
+ _maxHeight = nullptr;
+ _minHeight = nullptr;
// Liquid data
_liquidType = 0;
_liquidOffX = 0;
@@ -1214,9 +1216,9 @@ GridMap::GridMap()
_liquidWidth = 0;
_liquidHeight = 0;
_liquidLevel = INVALID_HEIGHT;
- _liquidEntry = NULL;
- _liquidFlags = NULL;
- _liquidMap = NULL;
+ _liquidEntry = nullptr;
+ _liquidFlags = nullptr;
+ _liquidMap = nullptr;
}
GridMap::~GridMap()
@@ -1277,15 +1279,19 @@ void GridMap::unloadData()
delete[] _areaMap;
delete[] m_V9;
delete[] m_V8;
+ delete[] _maxHeight;
+ delete[] _minHeight;
delete[] _liquidEntry;
delete[] _liquidFlags;
delete[] _liquidMap;
- _areaMap = NULL;
- m_V9 = NULL;
- m_V8 = NULL;
- _liquidEntry = NULL;
- _liquidFlags = NULL;
- _liquidMap = NULL;
+ _areaMap = nullptr;
+ m_V9 = nullptr;
+ m_V8 = nullptr;
+ _maxHeight = nullptr;
+ _minHeight = nullptr;
+ _liquidEntry = nullptr;
+ _liquidFlags = nullptr;
+ _liquidMap = nullptr;
_gridGetHeight = &GridMap::getHeightFromFlat;
}
@@ -1350,6 +1356,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)
}
else
_gridGetHeight = &GridMap::getHeightFromFlat;
+
+ if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
+ {
+ _maxHeight = new int16[3 * 3];
+ _minHeight = new int16[3 * 3];
+ if (fread(_maxHeight, sizeof(int16), 3 * 3, in) != 3 * 3 ||
+ fread(_minHeight, sizeof(int16), 3 * 3, in) != 3 * 3)
+ return false;
+ }
+
return true;
}
@@ -1620,6 +1636,66 @@ float GridMap::getHeightFromUint16(float x, float y) const
return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;
}
+float GridMap::getMinHeight(float x, float y) const
+{
+ if (!_minHeight)
+ return -500.0f;
+
+ static uint32 const indices[] =
+ {
+ 3, 0, 4,
+ 0, 1, 4,
+ 1, 2, 4,
+ 2, 5, 4,
+ 5, 8, 4,
+ 8, 7, 4,
+ 7, 6, 4,
+ 6, 3, 4
+ };
+
+ static float const boundGridCoords[] =
+ {
+ 0.0f, 0.0f,
+ 0.0f, -266.66666f,
+ 0.0f, -533.33331f,
+ -266.66666f, 0.0f,
+ -266.66666f, -266.66666f,
+ -266.66666f, -533.33331f,
+ -533.33331f, 0.0f,
+ -533.33331f, -266.66666f,
+ -533.33331f, -533.33331f
+ };
+
+ Cell cell(x, y);
+ float gx = x - (int32(cell.GridX()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
+ float gy = y - (int32(cell.GridY()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
+
+ uint32 quarterIndex = 0;
+ if (cell.CellY() < MAX_NUMBER_OF_CELLS / 2)
+ {
+ if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2)
+ {
+ quarterIndex = 4 + (gy > gx);
+ }
+ else
+ quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy);
+ }
+ else if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2)
+ {
+ quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy);
+ }
+ else
+ quarterIndex = gx > gy;
+
+ quarterIndex *= 3;
+
+ return G3D::Plane(
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], _minHeight[indices[quarterIndex + 0]]),
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], _minHeight[indices[quarterIndex + 1]]),
+ G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], _minHeight[indices[quarterIndex + 2]])
+ ).distance(G3D::Vector3(gx, gy, 0.0f));
+}
+
float GridMap::getLiquidLevel(float x, float y) const
{
if (!_liquidMap)
@@ -1679,12 +1755,12 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R
uint32 liqTypeIdx = liquidEntry->Type;
if (entry < 21)
{
- if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(getArea(x, y), MAPID_INVALID))
+ if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
{
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
if (!overrideLiquid && area->zone)
{
- area = GetAreaEntryByAreaID(area->zone);
+ area = sAreaTableStore.LookupEntry(area->zone);
if (area)
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
}
@@ -1835,7 +1911,7 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
// we are already under the surface or vmap height above map heigt
// or if the distance of the vmap height is less the land height distance
- if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z))
+ if (vmapHeight > mapHeight || fabs(mapHeight-z) > fabs(vmapHeight-z))
return vmapHeight;
else
return mapHeight; // better use .map surface height
@@ -1847,6 +1923,15 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
return mapHeight; // explicitly use map data
}
+float Map::GetMinHeight(float x, float y) const
+{
+ if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y))
+ return grid->getMinHeight(x, y);
+
+ return -500.0f;
+}
+
+
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
{
bool outdoor = true;
@@ -1887,7 +1972,7 @@ bool Map::IsOutdoors(float x, float y, float z) const
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outStaticDebug("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
#endif
- atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
+ atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
}
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
}
@@ -1911,7 +1996,7 @@ bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, in
return false;
}
-uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
+uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const
{
uint32 mogpFlags;
int32 adtId, rootId, groupId;
@@ -1924,20 +2009,20 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
haveAreaInfo = true;
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
if (wmoEntry)
- atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
+ atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
}
- uint16 areaflag;
+ uint16 areaId = 0;
if (atEntry)
- areaflag = atEntry->exploreFlag;
+ areaId = atEntry->ID;
else
{
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
- areaflag = gmap->getArea(x, y);
+ areaId = gmap->getArea(x, y);
// this used while not all *.map files generated (instances)
- else
- areaflag = GetAreaFlagByMapId(i_mapEntry->MapID);
+ if (!areaId)
+ areaId = i_mapEntry->linked_zone;
}
if (isOutdoors)
@@ -1947,8 +2032,31 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
else
*isOutdoors = true;
}
- return areaflag;
- }
+ return areaId;
+}
+
+uint32 Map::GetAreaId(float x, float y, float z) const
+{
+ return GetAreaId(x, y, z, nullptr);
+}
+
+uint32 Map::GetZoneId(float x, float y, float z) const
+{
+ uint32 areaId = GetAreaId(x, y, z);
+ if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
+ if (area->zone)
+ return area->zone;
+
+ return areaId;
+}
+
+void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
+{
+ areaid = zoneid = GetAreaId(x, y, z);
+ if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid))
+ if (area->zone)
+ zoneid = area->zone;
+}
uint8 Map::GetTerrainType(float x, float y) const
{
@@ -1986,12 +2094,12 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp
if (liquid_type && liquid_type < 21)
{
- if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(GetAreaFlag(x, y, z), GetId()))
+ if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z)))
{
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
if (!overrideLiquid && area->zone)
{
- area = GetAreaEntryByAreaID(area->zone);
+ area = sAreaTableStore.LookupEntry(area->zone);
if (area)
overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
}
@@ -2053,34 +2161,6 @@ float Map::GetWaterLevel(float x, float y) const
return 0;
}
-uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id)
-{
- AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
-
- if (entry)
- return entry->ID;
- else
- return 0;
-}
-
-uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id)
-{
- AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
-
- if (entry)
- return (entry->zone != 0) ? entry->zone : entry->ID;
- else
- return 0;
-}
-
-void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id)
-{
- AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
-
- areaid = entry ? entry->ID : 0;
- zoneid = entry ? ((entry->zone != 0) ? entry->zone : entry->ID) : 0;
-}
-
bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const
{
return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2)
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 93061f4a3f..aa8939638e 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -85,9 +85,10 @@ struct map_areaHeader
uint16 gridArea;
};
-#define MAP_HEIGHT_NO_HEIGHT 0x0001
-#define MAP_HEIGHT_AS_INT16 0x0002
-#define MAP_HEIGHT_AS_INT8 0x0004
+#define MAP_HEIGHT_NO_HEIGHT 0x0001
+#define MAP_HEIGHT_AS_INT16 0x0002
+#define MAP_HEIGHT_AS_INT8 0x0004
+#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
struct map_heightHeader
{
@@ -153,6 +154,8 @@ class GridMap
uint16* m_uint16_V8;
uint8* m_uint8_V8;
};
+ int16* _maxHeight;
+ int16* _minHeight;
// Height level data
float _gridHeight;
float _gridIntHeightMultiplier;
@@ -193,6 +196,7 @@ public:
uint16 getArea(float x, float y) const;
inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);}
+ float getMinHeight(float x, float y) const;
float getLiquidLevel(float x, float y) const;
uint8 getTerrainType(float x, float y) const;
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
@@ -327,12 +331,16 @@ class Map : public GridRefManager<NGridType>
// some calls like isInWater should not use vmaps due to processor power
// can return INVALID_HEIGHT if under z+2 z coord not found height
float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
+ float GetMinHeight(float x, float y) const;
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = NULL);
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0) const;
- uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const;
- bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const;
+ uint32 GetAreaId(float x, float y, float z, bool *isOutdoors) const;
+ bool GetAreaInfo(float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
+ uint32 GetAreaId(float x, float y, float z) const;
+ uint32 GetZoneId(float x, float y, float z) const;
+ void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const;
bool IsOutdoors(float x, float y, float z) const;
@@ -341,25 +349,6 @@ class Map : public GridRefManager<NGridType>
bool IsInWater(float x, float y, float z, LiquidData* data = 0) const;
bool IsUnderWater(float x, float y, float z) const;
- 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), GetId());
- }
-
- uint32 GetZoneId(float x, float y, float z) const
- {
- return GetZoneIdByAreaFlag(GetAreaFlag(x, y, z), GetId());
- }
-
- void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
- {
- GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(x, y, z), GetId());
- }
-
void MoveAllCreaturesInMoveList();
void MoveAllGameObjectsInMoveList();
void MoveAllDynamicObjectsInMoveList();
diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h
index fc7c158da8..d8ca015251 100644
--- a/src/server/game/Maps/MapManager.h
+++ b/src/server/game/Maps/MapManager.h
@@ -36,22 +36,20 @@ class MapManager
return (iter == i_maps.end() ? NULL : iter->second);
}
- uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const
- {
- Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
- 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);
+ Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
+ return m->GetAreaId(x, y, z);
}
uint32 GetZoneId(uint32 mapid, float x, float y, float z) const
{
- return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid);
+ Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
+ return m->GetZoneId(x, y, z);
}
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)
{
- Map::GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(mapid, x, y, z), mapid);
+ Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
+ m->GetZoneAndAreaId(zoneid, areaid, x, y, z);
}
void Initialize(void);
diff --git a/src/server/game/Misc/WhoListCache.cpp b/src/server/game/Misc/WhoListCache.cpp
index b945a61dfd..7b6873f1c7 100644
--- a/src/server/game/Misc/WhoListCache.cpp
+++ b/src/server/game/Misc/WhoListCache.cpp
@@ -35,7 +35,7 @@ void WhoListCacheMgr::Update()
wstrToLower(wgname);
std::string aname;
- if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
+ if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(itr->second->GetZoneId()))
aname = areaEntry->area_name[sWorld->GetDefaultDbcLocale()];
if (itr->second->IsSpectator())
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index ee6b5b4262..751024f46a 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -444,7 +444,7 @@ enum SpellAttr4
enum SpellAttr5
{
- SPELL_ATTR5_UNK0 = 0x00000001, // 0
+ SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING = 0x00000001, // 0
SPELL_ATTR5_NO_REAGENT_WHILE_PREP = 0x00000002, // 1 not need reagents if UNIT_FLAG_PREPARATION
SPELL_ATTR5_REMOVE_ON_ARENA_ENTER = 0x00000004, // 2 xinef: remove this aura on arena enter
SPELL_ATTR5_USABLE_WHILE_STUNNED = 0x00000008, // 3 usable while stunned
@@ -3531,7 +3531,7 @@ enum PartyResult
};
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
-#define MMAP_VERSION 3
+#define MMAP_VERSION 8
struct MmapTileHeader
{
@@ -3539,12 +3539,23 @@ struct MmapTileHeader
uint32 dtVersion;
uint32 mmapVersion;
uint32 size;
- bool usesLiquids : 1;
+ char usesLiquids;
+ char padding[3];
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
- mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
+ mmapVersion(MMAP_VERSION), size(0), usesLiquids(true), padding() { }
};
+// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files
+static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size");
+static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) +
+ sizeof(MmapTileHeader::dtVersion) +
+ sizeof(MmapTileHeader::mmapVersion) +
+ sizeof(MmapTileHeader::size) +
+ sizeof(MmapTileHeader::usesLiquids) +
+ sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");
+
+
enum NavTerrain
{
NAV_EMPTY = 0x00,
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index 0962c63aa5..0e74cdbdb8 100644
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -12,6 +12,7 @@
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "Player.h"
+#include "VMapFactory.h"
#define MIN_QUIET_DISTANCE 28.0f
#define MAX_QUIET_DISTANCE 43.0f
@@ -32,6 +33,19 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
if (!_getPoint(owner, x, y, z))
return;
+ // Add LOS check for target point
+ bool isInLOS = VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(owner->GetMapId(),
+ owner->GetPositionX(),
+ owner->GetPositionY(),
+ owner->GetPositionZ() + 2.0f,
+ x, y, z + 2.0f);
+
+ if (!isInLOS)
+ {
+ i_nextCheckTime.Reset(500);
+ return;
+ }
+
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
Movement::MoveSplineInit init(owner);
diff --git a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp
index c42ae417d2..0a55b66d23 100644
--- a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp
@@ -152,9 +152,10 @@ dtPolyRef PathGenerator::GetPolyByLocation(float* point, float* distance) const
// still nothing ..
// try with bigger search box
- extents[1] = 80.0f;
- result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint);
- if (DT_SUCCESS == result && polyRef != INVALID_POLYREF)
+ // Note that the extent should not overlap more than 128 polygons in the navmesh (see dtNavMeshQuery::findNearestPoly)
+ extents[1] = 50.0f;
+
+ if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
{
*distance = dtVdist(closestPoint, point);
return polyRef;
@@ -339,7 +340,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
if (startPoly != endPoly || !endInWaterFar)
{
float closestPoint[VERTEX_SIZE];
- if (DT_SUCCESS == _navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint))
+ if (dtStatusSucceed(_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint, NULL)))
{
dtVcopy(endPoint, closestPoint);
SetActualEndPosition(G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]));
@@ -416,7 +417,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
// we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
float suffixEndPoint[VERTEX_SIZE];
- if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
+ if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, NULL)))
{
// we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
// try to recover by using prev polyref
@@ -424,7 +425,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
if (prefixPolyLength)
{
suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
- if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
+ if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint,NULL)))
error = true;
}
else
@@ -445,7 +446,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
(int*)&suffixPolyLength,
MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path
- if (!suffixPolyLength || dtResult != DT_SUCCESS)
+ if (!_polyLength || dtStatusFailed(dtResult))
{
// this is probably an error state, but we'll leave it
// and hopefully recover on the next Update
@@ -470,7 +471,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
(int*)&_polyLength,
MAX_PATH_LENGTH); // max number of polygons in output path
- if (!_polyLength || dtResult != DT_SUCCESS)
+ if (!_polyLength || dtStatusFailed(dtResult))
{
// only happens if we passed bad data to findPath(), or navmesh is messed up
BuildShortcut();
@@ -499,7 +500,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
(int*)&_polyLength,
MAX_PATH_LENGTH); // max number of polygons in output path
- if (!_polyLength || dtResult != DT_SUCCESS)
+ if (!_polyLength || dtStatusFailed(dtResult))
{
// only happens if we passed bad data to findPath(), or navmesh is messed up
BuildShortcut();
@@ -658,7 +659,7 @@ void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoin
_pointPathLimit); // maximum number of points
}
- if (pointCount < 2 || dtResult != DT_SUCCESS)
+ if (pointCount < 2 || dtStatusFailed(dtResult))
{
// only happens if pass bad data to findStraightPath or navmesh is broken
// single point paths can be generated here
@@ -784,7 +785,7 @@ bool PathGenerator::HaveTile(const G3D::Vector3& p) const
if (tx < 0 || ty < 0)
return false;
- return (_navMesh->getTileAt(tx, ty) != NULL);
+ return (_navMesh->getTileAt(tx, ty, 0) != NULL);
}
uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited)
@@ -844,7 +845,7 @@ bool PathGenerator::GetSteerTarget(float const* startPos, float const* endPos,
uint32 nsteerPath = 0;
dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS);
- if (!nsteerPath || DT_SUCCESS != dtResult)
+ if (!nsteerPath || dtStatusFailed(dtResult))
return false;
// Find vertex far enough to steer to.
@@ -908,7 +909,7 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo
// Find movement delta.
float delta[VERTEX_SIZE];
dtVsub(delta, steerPos, iterPos);
- float len = dtSqrt(dtVdot(delta,delta));
+ float len = dtMathSqrtf(dtVdot(delta, delta));
// If the steer target is end of path or off-mesh link, do not move past the location.
if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
len = 1.0f;
diff --git a/src/server/game/Movement/MovementGenerators/PathGenerator.h b/src/server/game/Movement/MovementGenerators/PathGenerator.h
index 7632c47409..b6c6e72e0d 100644
--- a/src/server/game/Movement/MovementGenerators/PathGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/PathGenerator.h
@@ -38,7 +38,7 @@ class Unit;
#define ALLOWED_DIST_FROM_POLY 2.5f
#define ADDED_Z_FOR_POLY_LOOKUP 0.3f
#define DISALLOW_TIME_AFTER_FAIL 3 // secs
-#define MAX_FIXABLE_Z_ERROR 12.0f
+#define MAX_FIXABLE_Z_ERROR 7.0f
#define VERTEX_SIZE 3
#define INVALID_POLYREF 0
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
index dd5bf42511..97ffaa4437 100644
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
@@ -30,6 +30,9 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
return;
+ if (owner->HasUnitState(UNIT_STATE_CASTING) && !owner->CanMoveDuringChannel())
+ return;
+
float x, y, z;
bool isPlayerPet = owner->IsPet() && IS_PLAYER_GUID(owner->GetOwnerGUID());
bool sameTransport = owner->GetTransport() && owner->GetTransport() == i_target->GetTransport();
@@ -44,11 +47,17 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
(i_target->GetTypeId() == TYPEID_PLAYER && i_target->ToPlayer()->IsGameMaster()); // for .npc follow
bool forcePoint = ((!isPlayerPet || owner->GetMapId() == 618) && (forceDest || !useMMaps)) || sameTransport;
+ if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature()) && !sameTransport && !forceDest && !forcePoint)
+ return;
+
lastOwnerXYZ.Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ());
lastTargetXYZ.Relocate(i_target->GetPositionX(), i_target->GetPositionY(), i_target->GetPositionZ());
if (!i_offset)
{
+ if (i_target->IsWithinDistInMap(owner, CONTACT_DISTANCE))
+ return;
+
float allowedRange = MELEE_RANGE;
if ((!initial || (owner->movespline->Finalized() && this->GetMovementGeneratorType() == CHASE_MOTION_TYPE)) && i_target->IsWithinMeleeRange(owner, allowedRange) && i_target->IsWithinLOS(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ()))
return;
@@ -60,6 +69,9 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
owner->m_targetsNotAcceptable[i_target->GetGUID()] = MMapTargetData(sWorld->GetGameTime()+DISALLOW_TIME_AFTER_FAIL, owner, i_target.getTarget());
return;
}
+
+ // to nearest contact position
+ i_target->GetContactPoint(owner, x, y, z);
}
else
{
@@ -167,6 +179,7 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
else
{
owner->m_targetsNotAcceptable.erase(i_target->GetGUID());
+ owner->AddUnitState(UNIT_STATE_CHASE);
init.MovebyPath(i_path->GetPath());
if (i_angle == 0.f)
@@ -180,6 +193,8 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
// if failed to generate, just use normal MoveTo
}
+ owner->AddUnitState(UNIT_STATE_CHASE);
+
init.MoveTo(x,y,z);
// Using the same condition for facing target as the one that is used for SetInFront on movement end
// - applies to ChaseMovementGenerator mostly
@@ -206,7 +221,7 @@ bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff)
}
// prevent movement while casting spells with cast time or channel time
- if (owner->HasUnitState(UNIT_STATE_CASTING))
+ if (owner->HasUnitState(UNIT_STATE_CASTING) && !owner->CanMoveDuringChannel())
{
bool stop = true;
if (Spell* spell = owner->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 876c63e4c5..2c2bf165c6 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -1148,13 +1148,13 @@ void ScriptMgr::OnShutdown()
FOREACH_SCRIPT(WorldScript)->OnShutdown();
}
-bool ScriptMgr::OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target)
+bool ScriptMgr::OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target, uint32 criteria_id)
{
ASSERT(source);
// target can be NULL.
GET_SCRIPT_RET(AchievementCriteriaScript, scriptId, tmpscript, false);
- return tmpscript->OnCheck(source, target);
+ return tmpscript->OnCheck(source, target, criteria_id);
}
// Player
@@ -1303,6 +1303,21 @@ void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newAre
FOREACH_SCRIPT(PlayerScript)->OnUpdateZone(player, newZone, newArea);
}
+void ScriptMgr::OnPlayerUpdateArea(Player* player, uint32 oldArea, uint32 newArea)
+{
+ FOREACH_SCRIPT(PlayerScript)->OnUpdateArea(player, oldArea, newArea);
+}
+
+bool ScriptMgr::OnBeforePlayerTeleport(Player* player, uint32 mapid, float x, float y, float z, float orientation, uint32 options, Unit *target)
+{
+ bool ret=true;
+ FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts
+ if (!itr->second->OnBeforeTeleport(player, mapid, x, y, z, orientation, options, target))
+ ret=false; // we change ret value only when scripts return false
+
+ return ret;
+}
+
void ScriptMgr::OnPlayerUpdateFaction(Player* player)
{
FOREACH_SCRIPT(PlayerScript)->OnUpdateFaction(player);
@@ -1494,14 +1509,18 @@ void ScriptMgr::OnBeforeUpdateArenaPoints(ArenaTeam* at, std::map<uint32, uint32
FOREACH_SCRIPT(GlobalScript)->OnBeforeUpdateArenaPoints(at,ap);
}
-void ScriptMgr::OnAfterRefCount(LootStoreItem* LootStoreItem, uint32 &maxcount)
+void ScriptMgr::OnAfterRefCount(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, uint32 &maxcount, LootStore const& store)
{
- FOREACH_SCRIPT(GlobalScript)->OnAfterRefCount(LootStoreItem, maxcount);
+ FOREACH_SCRIPT(GlobalScript)->OnAfterRefCount(player, LootStoreItem, loot, canRate, lootMode, maxcount, store);
}
-void ScriptMgr::OnBeforeDropAddItem(Player const* player, Loot& loot, LootStoreItem* LootStoreItem)
+void ScriptMgr::OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store)
{
- FOREACH_SCRIPT(GlobalScript)->OnBeforeDropAddItem(player, loot, LootStoreItem);
+ FOREACH_SCRIPT(GlobalScript)->OnBeforeDropAddItem(player, loot, canRate, lootMode, LootStoreItem, store);
+}
+
+void ScriptMgr::OnItemRoll(Player const* player, LootStoreItem const* LootStoreItem, float &chance, Loot& loot, LootStore const& store) {
+ FOREACH_SCRIPT(GlobalScript)->OnItemRoll(player, LootStoreItem, chance, loot, store);
}
void ScriptMgr::OnInitializeLockedDungeons(Player* player, uint8& level, uint32& lockData)
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 260d8d666c..c71c45dbff 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -747,7 +747,11 @@ class AchievementCriteriaScript : public ScriptObject
bool IsDatabaseBound() const { return true; }
// Called when an additional criteria is checked.
- virtual bool OnCheck(Player* source, Unit* target) = 0;
+ virtual bool OnCheck(Player* source, Unit* target, uint32 /*criteria_id*/) {
+ return OnCheck(source, target);
+ }
+ // deprecated/legacy
+ virtual bool OnCheck(Player* /*source*/, Unit* /*target*/) { return true; };
};
class PlayerScript : public ScriptObject
@@ -838,9 +842,15 @@ class PlayerScript : public ScriptObject
// Called when a player switches to a new zone
virtual void OnUpdateZone(Player* /*player*/, uint32 /*newZone*/, uint32 /*newArea*/) { }
+ // Called when a player switches to a new area (more accurate than UpdateZone)
+ virtual void OnUpdateArea(Player* /*player*/, uint32 /*oldArea*/, uint32 /*newArea*/) { }
+
// Called when a player changes to a new map (after moving to new map)
virtual void OnMapChanged(Player* /*player*/) { }
+ // Called before a player is being teleported to new coords
+ virtual bool OnBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) { return true; }
+
// Called when team/faction is set on player
virtual void OnUpdateFaction(Player* /*player*/) { }
@@ -994,8 +1004,11 @@ class GlobalScript : public ScriptObject
// items
virtual void OnItemDelFromDB(SQLTransaction& /*trans*/, uint32 /*itemGuid*/) { }
virtual void OnMirrorImageDisplayItem(const Item* /*item*/, uint32& /*display*/) { }
- virtual void OnAfterRefCount(LootStoreItem* /*LootStoreItem*/, uint32& /*maxcount*/) { }
- virtual void OnBeforeDropAddItem(Player const* /*player*/, Loot& /*loot*/, LootStoreItem* /*LootStoreItem*/) { }
+
+ // loot
+ virtual void OnAfterRefCount(Player const* /*player*/, LootStoreItem* /*LootStoreItem*/, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, uint32& /*maxcount*/, LootStore const& /*store*/) { }
+ virtual void OnBeforeDropAddItem(Player const* /*player*/, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, LootStoreItem* /*LootStoreItem*/, LootStore const& /*store*/) { }
+ virtual void OnItemRoll(Player const* /*player*/, LootStoreItem const* /*LootStoreItem*/, float& /*chance*/, Loot& /*loot*/, LootStore const& /*store*/) { };
virtual void OnInitializeLockedDungeons(Player* /*player*/, uint8& /*level*/, uint32& /*lockData*/) { }
virtual void OnAfterInitializeLockedDungeons(Player* /*player*/) { }
@@ -1176,7 +1189,7 @@ class ScriptMgr
public: /* AchievementCriteriaScript */
- bool OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target);
+ bool OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target, uint32 criteria_id);
public: /* PlayerScript */
@@ -1210,6 +1223,8 @@ class ScriptMgr
void OnPlayerDelete(uint64 guid);
void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent);
void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea);
+ void OnPlayerUpdateArea(Player* player, uint32 oldArea, uint32 newArea);
+ bool OnBeforePlayerTeleport(Player* player, uint32 mapid, float x, float y, float z, float orientation, uint32 options, Unit *target);
void OnPlayerUpdateFaction(Player* player);
void OnPlayerAddToBattleground(Player* player, Battleground* bg);
void OnPlayerRemoveFromBattleground(Player* player, Battleground* bg);
@@ -1264,8 +1279,9 @@ class ScriptMgr
void OnGlobalItemDelFromDB(SQLTransaction& trans, uint32 itemGuid);
void OnGlobalMirrorImageDisplayItem(const Item *item, uint32 &display);
void OnBeforeUpdateArenaPoints(ArenaTeam* at, std::map<uint32, uint32> &ap);
- void OnAfterRefCount(LootStoreItem* LootStoreItem, uint32 &maxcount);
- void OnBeforeDropAddItem(Player const* player, Loot& loot, LootStoreItem* LootStoreItem);
+ void OnAfterRefCount(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, uint32 &maxcount, LootStore const& store);
+ void OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store);
+ void OnItemRoll(Player const* player, LootStoreItem const* LootStoreItem, float &chance, Loot& loot, LootStore const& store);
void OnInitializeLockedDungeons(Player* player, uint8& level, uint32& lockData);
void OnAfterInitializeLockedDungeons(Player* player);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index b0e436efb5..99759c7329 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -1711,20 +1711,16 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
Unit* target = aurApp->GetTarget();
// no-phase is also phase state so same code for apply and remove
- uint32 newPhase = 0;
- Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE);
- if (!phases.empty())
- for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
- newPhase |= (*itr)->GetMiscValue();
+ uint32 newPhase = target->GetPhaseByAuras();
if (Player* player = target->ToPlayer())
{
if (!newPhase)
newPhase = PHASEMASK_NORMAL;
- // GM-mode have mask 0xFFFFFFFF
+ // do not change phase to GM with all phases enabled
if (player->IsGameMaster())
- newPhase = 0xFFFFFFFF;
+ newPhase = PHASEMASK_ANYWHERE;
player->SetPhaseMask(newPhase, false);
player->GetSession()->SendSetPhaseShift(newPhase);
@@ -1769,7 +1765,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mode, bool apply) const
{
- if (!(mode & AURA_EFFECT_HANDLE_REAL))
+ if (!(mode & AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK))
return;
Unit* target = aurApp->GetTarget();
@@ -3582,6 +3578,9 @@ void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8
switch (GetId())
{
+ case 46924: // BladeStorm
+ target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
+ break;
case 34471: // The Beast Within
case 19574: // Bestial Wrath
mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index d1736893f3..c50ecc2bc0 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -395,7 +395,7 @@ Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owne
Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* castItem, uint64 casterGUID) :
m_spellInfo(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID()),
-m_castItemGuid(castItem ? castItem->GetGUID() : 0), m_applyTime(time(NULL)),
+m_castItemGuid(castItem ? castItem->GetGUID() : 0),m_castItemEntry(castItem ? castItem->GetEntry() : 0), m_applyTime(time(NULL)),
m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0),
m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1),
m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false)
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index 30f25dae9b..1587f9fadf 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -96,6 +96,7 @@ class Aura
uint32 GetId() const{ return GetSpellInfo()->Id; }
uint64 GetCastItemGUID() const { return m_castItemGuid; }
+ uint32 GetCastItemEntry() const { return m_castItemEntry; }
uint64 GetCasterGUID() const { return m_casterGuid; }
Unit* GetCaster() const;
WorldObject* GetOwner() const { return m_owner; }
@@ -235,6 +236,7 @@ class Aura
SpellInfo const* const m_spellInfo;
uint64 const m_casterGuid;
uint64 const m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
+ uint32 const m_castItemEntry; // when deleted, we could retrieve some information from template instead
time_t const m_applyTime;
WorldObject* const m_owner; //
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index f1aa91af71..8bf57153b9 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -287,6 +287,16 @@ Corpse* SpellCastTargets::GetCorpseTarget() const
return NULL;
}
+void SpellCastTargets::SetCorpseTarget(Corpse* target)
+{
+ if (!target)
+ return;
+
+ m_objectTarget = target;
+ m_objectTargetGUID = target->GetGUID();
+ m_targetMask |= TARGET_FLAG_CORPSE_MASK;
+}
+
WorldObject* SpellCastTargets::GetObjectTarget() const
{
return m_objectTarget;
@@ -1306,7 +1316,8 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis;
float x, y, z, angle;
angle = (float)rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
- m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle);
+ //m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle); this contains extra code that breaks fishing
+ m_caster->GetNearPoint(m_caster, x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, m_caster->GetOrientation() + angle);
float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseMask(), x, y, z, true, 120.0f);
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
@@ -2395,6 +2406,23 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
// Increase time interval for reflected spells by 1.5
m_caster->m_Events.AddEvent(new ReflectEvent(m_caster->GetGUID(), targetInfo.targetGUID, m_spellInfo), m_caster->m_Events.CalculateTime(targetInfo.timeDelay));
targetInfo.timeDelay += targetInfo.timeDelay >> 1;
+
+ // HACK: workaround check for succubus seduction case
+ // TODO: seduction should be casted only on humanoids (not demons)
+ if (m_caster->IsPet())
+ {
+ CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(m_caster->GetEntry());
+ switch (ci->family)
+ {
+ case CREATURE_FAMILY_SUCCUBUS:
+ {
+ if (m_spellInfo->SpellIconID != 694) // Soothing Kiss
+ cancel();
+ }
+ break;
+ return;
+ }
+ }
}
else
targetInfo.reflectResult = SPELL_MISS_NONE;
@@ -4545,14 +4573,14 @@ void Spell::WriteAmmoToPacket(WorldPacket* data)
{
if (uint32 item_id = m_caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i))
{
- if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
+ if (ItemTemplate const* itemEntry = sObjectMgr->GetItemTemplate(item_id))
{
if (itemEntry->Class == ITEM_CLASS_WEAPON)
{
switch (itemEntry->SubClass)
{
case ITEM_SUBCLASS_WEAPON_THROWN:
- ammoDisplayID = itemEntry->DisplayId;
+ ammoDisplayID = itemEntry->DisplayInfoID;
ammoInventoryType = itemEntry->InventoryType;
break;
case ITEM_SUBCLASS_WEAPON_BOW:
@@ -5788,7 +5816,7 @@ SpellCastResult Spell::CheckCast(bool strict)
m_pathFinder = new PathGenerator(m_caster);
m_pathFinder->CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ+0.15f, false);
G3D::Vector3 endPos = m_pathFinder->GetEndPosition(); // also check distance between target and the point calculated by mmaps
- if (m_pathFinder->GetPathType()&PATHFIND_NOPATH || target->GetExactDistSq(endPos.x, endPos.y, endPos.z) > maxdist*maxdist || m_pathFinder->getPathLength() > (40.0f + (m_caster->HasAura(58097) ? 5.0f : 0.0f)))
+ if (m_pathFinder->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE) || target->GetExactDistSq(endPos.x, endPos.y, endPos.z) > maxdist*maxdist || m_pathFinder->getPathLength() > (40.0f + (m_caster->HasAura(58097) ? 5.0f : 0.0f)))
return SPELL_FAILED_NOPATH;
}
break;
@@ -6200,7 +6228,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->IsAlive())
{
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId());
- if (AreaTableEntry const* pArea = GetAreaEntryByAreaID(m_originalCaster->GetAreaId()))
+ if (AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(m_originalCaster->GetAreaId()))
if ((pArea->flags & AREA_FLAG_NO_FLY_ZONE) || (Bf && !Bf->CanFlyIn()))
return SPELL_FAILED_NOT_HERE;
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index dd1241ea10..880bb1fdc8 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -107,6 +107,7 @@ class SpellCastTargets
uint64 GetCorpseTargetGUID() const;
Corpse* GetCorpseTarget() const;
+ void SetCorpseTarget(Corpse* target);
WorldObject* GetObjectTarget() const;
uint64 GetObjectTargetGUID() const;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 547a713c4d..4ec091f78a 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -3218,7 +3218,7 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/)
return;
// xinef: Hand of Reckoning, cast before checing canhavethreatlist. fixes damage against pets
- if (m_spellInfo->Id == 62124 && unitTarget->GetVictim() != m_caster && !unitTarget->IsTotem())
+ if (m_spellInfo->Id == 62124 && unitTarget->GetVictim() != m_caster)
m_caster->CastSpell(unitTarget, 67485, true);
// this effect use before aura Taunt apply for prevent taunt already attacking target
@@ -4241,14 +4241,14 @@ void Spell::EffectDuel(SpellEffIndex effIndex)
return;
// Players can only fight a duel in zones with this flag
- AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId());
+ AreaTableEntry const* casterAreaEntry = sAreaTableStore.LookupEntry(caster->GetAreaId());
if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
{
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
return;
}
- AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId());
+ AreaTableEntry const* targetAreaEntry = sAreaTableStore.LookupEntry(target->GetAreaId());
if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
{
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 098b5af9c6..d8dbd3aa8f 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -1069,7 +1069,7 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
if (!player)
return false;
- AreaTableEntry const* pArea = GetAreaEntryByAreaID(player->GetAreaId());
+ AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(player->GetAreaId());
if (!(pArea && pArea->flags & AREA_FLAG_NO_FLY_ZONE))
return false;
if (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY))
@@ -2513,7 +2513,7 @@ void SpellMgr::LoadSpellAreas()
}
}
- if (spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId))
+ if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId))
{
sLog->outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId);
continue;
@@ -6243,8 +6243,8 @@ void SpellMgr::LoadDbcDataCorrections()
}
// Xinef: The Veiled Sea area in outlands (Draenei zone), client blocks casting flying mounts
- for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i)
- if (AreaTableEntry* areaEntry = const_cast<AreaTableEntry*>(sAreaStore.LookupEntry(i)))
+ for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i)
+ if (AreaTableEntry* areaEntry = const_cast<AreaTableEntry*>(sAreaTableStore.LookupEntry(i)))
{
if (areaEntry->ID == 3479)
areaEntry->flags |= AREA_FLAG_NO_FLY_ZONE;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index e7cdd9aa35..3ec460da9e 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -75,6 +75,7 @@
#include "WhoListCache.h"
#include "AsyncAuctionListing.h"
#include "SavingSystem.h"
+#include <VMapManager2.h>
ACE_Atomic_Op<ACE_Thread_Mutex, bool> World::m_stopEvent = false;
uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
@@ -909,6 +910,12 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_UPTIME_UPDATE] = 1;
}
+ if (reload)
+ {
+ m_timers[WUPDATE_UPTIME].SetInterval(m_int_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
+ m_timers[WUPDATE_UPTIME].Reset();
+ }
+
// log db cleanup interval
m_int_configs[CONFIG_LOGDB_CLEARINTERVAL] = sConfigMgr->GetIntDefault("LogDB.Opt.ClearInterval", 10);
if (int32(m_int_configs[CONFIG_LOGDB_CLEARINTERVAL]) <= 0)
@@ -1218,9 +1225,6 @@ void World::LoadConfigSettings(bool reload)
// Dungeon finder
m_int_configs[CONFIG_LFG_OPTIONSMASK] = sConfigMgr->GetIntDefault("DungeonFinder.OptionsMask", 3);
- // DBC_ItemAttributes
- m_bool_configs[CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES] = sConfigMgr->GetBoolDefault("DBC.EnforceItemAttributes", true);
-
// Max instances per hour
m_int_configs[CONFIG_MAX_INSTANCES_PER_HOUR] = sConfigMgr->GetIntDefault("AccountInstancesPerHour", 5);
@@ -1276,6 +1280,12 @@ void World::SetInitialWorldSettings()
sLog->outString("Initializing Scripts...");
sScriptMgr->Initialize();
+ ///- Initialize VMapManager function pointers (to untangle game/collision circular deps)
+ if (VMAP::VMapManager2* vmmgr2 = dynamic_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager()))
+ {
+ vmmgr2->GetLiquidFlagsPtr = &GetLiquidFlags;
+ }
+
///- Initialize config settings
LoadConfigSettings();
@@ -1520,7 +1530,8 @@ void World::SetInitialWorldSettings()
sPoolMgr->LoadFromDB();
sLog->outString("Loading Game Event Data..."); // must be after loading pools fully
- sGameEventMgr->LoadFromDB();
+ sGameEventMgr->LoadHolidayDates(); // Must be after loading DBC
+ sGameEventMgr->LoadFromDB(); // Must be after loading holiday dates
sLog->outString("Loading UNIT_NPC_FLAG_SPELLCLICK Data..."); // must be after LoadQuests
sObjectMgr->LoadNPCSpellClickSpells();
@@ -1752,11 +1763,16 @@ void World::SetInitialWorldSettings()
m_gameTime = time(NULL);
m_startTime = m_gameTime;
+ LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES(%u, %u, 0, '%s')",
+ realmID, uint32(m_startTime), _FULLVERSION); // One-time query
+
m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS].SetCurrent(MINUTE*IN_MILLISECONDS);
+ m_timers[WUPDATE_UPTIME].SetInterval(m_int_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
+ //Update "uptime" table based on configuration entry in minutes.
m_timers[WUPDATE_CORPSES].SetInterval(20 * MINUTE * IN_MILLISECONDS);
//erase corpses every 20 minutes
@@ -2077,7 +2093,25 @@ void World::Update(uint32 diff)
// execute callbacks from sql queries that were queued recently
ProcessQueryCallbacks();
-
+
+ /// <li> Update uptime table
+ if (m_timers[WUPDATE_UPTIME].Passed())
+ {
+ uint32 tmpDiff = uint32(m_gameTime - m_startTime);
+ uint32 maxOnlinePlayers = GetMaxPlayerCount();
+
+ m_timers[WUPDATE_UPTIME].Reset();
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_UPTIME_PLAYERS);
+
+ stmt->setUInt32(0, tmpDiff);
+ stmt->setUInt16(1, uint16(maxOnlinePlayers));
+ stmt->setUInt32(2, realmID);
+ stmt->setUInt32(3, uint32(m_startTime));
+
+ LoginDatabase.Execute(stmt);
+ }
+
///- Erase corpses once every 20 minutes
if (m_timers[WUPDATE_CORPSES].Passed())
{
@@ -2765,6 +2799,7 @@ void World::UpdateRealmCharCount(uint32 accountId)
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT);
stmt->setUInt32(0, accountId);
+ stmt->setUInt32(1, accountId);
PreparedQueryResultFuture result = CharacterDatabase.AsyncQuery(stmt);
m_realmCharCallbacks.insert(result);
}
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 96eecf073d..6408e0d2dd 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -60,6 +60,7 @@ enum WorldTimers
{
WUPDATE_AUCTIONS,
WUPDATE_WEATHERS,
+ WUPDATE_UPTIME,
WUPDATE_CORPSES,
WUPDATE_EVENTS,
WUPDATE_CLEANDB,
@@ -147,7 +148,6 @@ enum WorldBoolConfigs
CONFIG_AUTOBROADCAST,
CONFIG_ALLOW_TICKETS,
CONFIG_DELETE_CHARACTER_TICKET_TRACE,
- CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
CONFIG_PRESERVE_CUSTOM_CHANNELS,
CONFIG_WINTERGRASP_ENABLE,
CONFIG_PDUMP_NO_PATHS,
diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt
index 6804d939fe..a3373a007d 100644
--- a/src/server/scripts/CMakeLists.txt
+++ b/src/server/scripts/CMakeLists.txt
@@ -78,8 +78,8 @@ message("")
include_directories(
${scripts_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}
- ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Detour
- ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Recast
+ ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Detour/Include
+ ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/deps/g3dlite/include
${CMAKE_SOURCE_DIR}/deps/SFMT
${CMAKE_SOURCE_DIR}/deps/zlib
diff --git a/src/server/scripts/Commands/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt
index 6b9bb2a892..f1e5aa4932 100644
--- a/src/server/scripts/Commands/CMakeLists.txt
+++ b/src/server/scripts/Commands/CMakeLists.txt
@@ -31,6 +31,7 @@ set(scripts_STAT_SRCS
Commands/cs_lookup.cpp
Commands/cs_message.cpp
Commands/cs_misc.cpp
+ Commands/cs_mmaps.cpp
Commands/cs_modify.cpp
Commands/cs_npc.cpp
Commands/cs_quest.cpp
diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp
index 9268272d2d..0967aa170d 100644
--- a/src/server/scripts/Commands/cs_gm.cpp
+++ b/src/server/scripts/Commands/cs_gm.cpp
@@ -191,14 +191,10 @@ public:
return false;
}
- const uint32 VISUAL_AURA = 37800;
std::string param = (char*)args;
if (param == "on")
{
- if (_player->HasAura(VISUAL_AURA, 0))
- _player->RemoveAurasDueToSpell(VISUAL_AURA);
-
_player->SetGMVisible(true);
//_player->UpdateObjectVisibility();
handler->GetSession()->SendNotification(LANG_INVISIBLE_VISIBLE);
@@ -208,7 +204,6 @@ public:
if (param == "off")
{
- _player->AddAura(VISUAL_AURA, _player);
_player->SetGMVisible(false);
//_player->UpdateObjectVisibility();
handler->GetSession()->SendNotification(LANG_INVISIBLE_INVISIBLE);
diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp
index 66a7d5f306..4a6235ddee 100644
--- a/src/server/scripts/Commands/cs_go.cpp
+++ b/src/server/scripts/Commands/cs_go.cpp
@@ -417,7 +417,7 @@ public:
uint32 areaId = id ? (uint32)atoi(id) : player->GetZoneId();
- AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId);
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
if (x < 0 || x > 100 || y < 0 || y > 100 || !areaEntry)
{
@@ -427,7 +427,7 @@ public:
}
// update to parent zone if exist (client map show only zones without parents)
- AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry;
+ AreaTableEntry const* zoneEntry = areaEntry->zone ? sAreaTableStore.LookupEntry(areaEntry->zone) : areaEntry;
Map const* map = sMapMgr->CreateBaseMap(zoneEntry->mapid);
diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp
index cdfc508d85..9d1c34c5a1 100644
--- a/src/server/scripts/Commands/cs_gobject.cpp
+++ b/src/server/scripts/Commands/cs_gobject.cpp
@@ -548,6 +548,7 @@ public:
stmt->setFloat(5, player->GetPositionY());
stmt->setFloat(6, player->GetPositionZ());
stmt->setFloat(7, distance * distance);
+ stmt->setFloat(8, player->GetPhaseMask());
PreparedQueryResult result = WorldDatabase.Query(stmt);
if (result)
diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp
index d81ce581da..60f5ce165c 100644
--- a/src/server/scripts/Commands/cs_lookup.cpp
+++ b/src/server/scripts/Commands/cs_lookup.cpp
@@ -86,9 +86,9 @@ public:
wstrToLower(wNamePart);
// Search in AreaTable.dbc
- for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows(); ++areaflag)
+ for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i)
{
- AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(areaflag);
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i);
if (areaEntry)
{
int locale = handler->GetSessionDbcLocale();
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 058290c9e3..268248f5bb 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -400,8 +400,8 @@ public:
object->GetZoneAndAreaId(zoneId, areaId);
MapEntry const* mapEntry = sMapStore.LookupEntry(object->GetMapId());
- AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zoneId);
- AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId);
+ AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId);
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
float zoneX = object->GetPositionX();
float zoneY = object->GetPositionY();
@@ -612,8 +612,8 @@ public:
else
_player->SaveRecallPosition();
- _player->TeleportTo(target->GetMapId(), target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()+0.25f, _player->GetOrientation(), TELE_TO_GM_MODE);
- _player->SetPhaseMask(target->GetPhaseMask() | 1, false);
+ if (_player->TeleportTo(target->GetMapId(), target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()+0.25f, _player->GetOrientation(), TELE_TO_GM_MODE, target))
+ _player->SetPhaseMask(target->GetPhaseMask() | 1, false);
}
else
{
@@ -734,8 +734,8 @@ public:
// before GM
float x, y, z;
handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, target->GetObjectSize());
- target->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, target->GetOrientation());
- target->SetPhaseMask(handler->GetSession()->GetPlayer()->GetPhaseMask(), false);
+ if (target->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, target->GetOrientation(), 0, handler->GetSession()->GetPlayer()))
+ target->SetPhaseMask(handler->GetSession()->GetPlayer()->GetPhaseMask(), false);
}
else
{
@@ -845,7 +845,7 @@ public:
// before GM
float x, y, z;
handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, player->GetObjectSize());
- player->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, player->GetOrientation());
+ player->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, player->GetOrientation(), 0, handler->GetSession()->GetPlayer());
}
return true;
@@ -1280,7 +1280,7 @@ public:
uint32 zoneId = player->GetZoneId();
- AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId);
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId);
if (!areaEntry || areaEntry->zone !=0)
{
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, graveyardId, zoneId);
@@ -1411,17 +1411,23 @@ public:
return false;
}
- int32 area = GetAreaFlagByAreaID(atoi((char*)args));
- int32 offset = area / 32;
- uint32 val = uint32((1 << (area % 32)));
+ AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args));
+ if (!area)
+ {
+ handler->SendSysMessage(LANG_BAD_VALUE);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
- if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE)
+ int32 offset = area->exploreFlag / 32;
+ if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
+ uint32 val = uint32((1 << (area->exploreFlag % 32)));
uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields | val)));
@@ -1442,17 +1448,23 @@ public:
return false;
}
- int32 area = GetAreaFlagByAreaID(atoi((char*)args));
- int32 offset = area / 32;
- uint32 val = uint32((1 << (area % 32)));
+ AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args));
+ if (!area)
+ {
+ handler->SendSysMessage(LANG_BAD_VALUE);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
- if (area < 0 || offset >= PLAYER_EXPLORED_ZONES_SIZE)
+ int32 offset = area->exploreFlag / 32;
+ if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
+ uint32 val = uint32((1 << (area->exploreFlag % 32)));
uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields ^ val)));
@@ -2025,12 +2037,12 @@ public:
MapEntry const* map = sMapStore.LookupEntry(mapId);
- AreaTableEntry const* area = GetAreaEntryByAreaID(areaId);
+ AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId);
if (area)
{
areaName = area->area_name[locale];
- AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone);
+ AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone);
if (zone)
zoneName = zone->area_name[locale];
}
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 075eae219c..928569fbc7 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -668,6 +668,7 @@ public:
stmt->setFloat(5, player->GetPositionY());
stmt->setFloat(6, player->GetPositionZ());
stmt->setFloat(7, distance * distance);
+ stmt->setFloat(8, player->GetPhaseMask());
PreparedQueryResult result = WorldDatabase.Query(stmt);
if (result)
diff --git a/src/server/scripts/Custom/README.md b/src/server/scripts/Custom/README.md
index 7b9e83d4e0..05944b8706 100644
--- a/src/server/scripts/Custom/README.md
+++ b/src/server/scripts/Custom/README.md
@@ -6,14 +6,20 @@ They will be git-ignored
Remember to use cmake macro inside your CMakeLists.txt to correctly
add scripts to project solution.
-BTW, **We strongly suggest you** to use our module system to create your custom
+
+
+/!\ BTW, **We strongly suggest you** to use our module system to create your custom
powerful module instead of simple scripts.
-----------------
-CMakeLists.txt example:
+How to:
+
+1) Create a CMakeLists.txt in this directory
+
+Example (everything below is needed, just replace with your scripts' names):
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
@@ -24,3 +30,8 @@ set(scripts_STAT_SRCS
AC_ADD_SCRIPT_LOADER("Custom" "ScriptLoader.h")
message(" -> Prepared: My custom scripts")
+
+
+2) Add them to ../ScriptLoader.cpp
+
+Open the file and go at the end of the file to know what to edit.
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h
index fd073b5a74..4073401b96 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h
@@ -110,4 +110,9 @@ enum GameObjectsIds
GO_UROK_PILE = 175621,
};
+enum npcspells
+{
+ SPELL_FINKLE_IS_EINHORN = 16710
+};
+
#endif
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp
index 751f58635b..98bd6fbec6 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp
@@ -67,6 +67,19 @@ public:
memset(go_emberseerrunes, 0, sizeof(go_emberseerrunes));
}
+ void CreatureLooted(Creature* creature, LootType loot)
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_THE_BEAST:
+ if (loot == LOOT_SKINNING)
+ {
+ creature->CastSpell(creature, SPELL_FINKLE_IS_EINHORN, true);
+ }
+ break;
+ }
+ }
+
void OnCreatureCreate(Creature* creature)
{
switch (creature->GetEntry())
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp
index 3c279ba2f7..5b44d39437 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp
@@ -61,6 +61,17 @@ class boss_golemagg : public CreatureScript
{
BossAI::EnterCombat(victim);
events.ScheduleEvent(EVENT_PYROBLAST, 7000);
+
+ // The two ragers should join the fight alongside me against my foes.
+ std::list<Creature *> ragers;
+ me->GetCreaturesWithEntryInRange(ragers, 100, NPC_CORE_RAGER);
+ for (Creature * i : ragers)
+ {
+ if (i && i->IsAlive() && !i->IsInCombat())
+ {
+ i->AI()->AttackStart(victim);
+ }
+ }
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask)
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp
index 1b515591c7..0908b5b107 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp
@@ -4,12 +4,12 @@
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
-/* ScriptData
-SDName: Boss_Magmadar
-SD%Complete: 75
-SDComment: Conflag on ground nyi
-SDCategory: Molten Core
-EndScriptData */
+ /* ScriptData
+ SDName: Boss_Magmadar
+ SD%Complete: 75
+ SDComment: Conflag on ground nyi
+ SDCategory: Molten Core
+ EndScriptData */
#include "ObjectMgr.h"
#include "ScriptMgr.h"
@@ -18,93 +18,229 @@ EndScriptData */
enum Texts
{
- EMOTE_FRENZY = 0
+ EMOTE_FRENZY = 0,
+ EMOTE_SMOLDERING = 0,
+ EMOTE_IGNITE = 1,
};
enum Spells
{
- SPELL_FRENZY = 19451,
- SPELL_MAGMA_SPIT = 19449,
- SPELL_PANIC = 19408,
- SPELL_LAVA_BOMB = 19428,
+ SPELL_FRENZY = 19451,
+ SPELL_MAGMA_SPIT = 19449,
+ SPELL_PANIC = 19408,
+ SPELL_LAVA_BOMB = 19428,
+ SPELL_SERRATED_BITE = 19771,
};
enum Events
{
- EVENT_FRENZY = 1,
- EVENT_PANIC = 2,
- EVENT_LAVA_BOMB = 3,
+ EVENT_FRENZY = 1,
+ EVENT_PANIC = 2,
+ EVENT_LAVA_BOMB = 3,
+ EVENT_SERRATED_BITE = 1,
+ EVENT_IGNITE = 2,
};
class boss_magmadar : public CreatureScript
{
- public:
- boss_magmadar() : CreatureScript("boss_magmadar") { }
+public:
+ boss_magmadar() : CreatureScript("boss_magmadar") { }
- struct boss_magmadarAI : public BossAI
+ struct boss_magmadarAI : public BossAI
+ {
+ boss_magmadarAI(Creature* creature) : BossAI(creature, BOSS_MAGMADAR)
{
- boss_magmadarAI(Creature* creature) : BossAI(creature, BOSS_MAGMADAR)
- {
- }
+ }
+
+ void Reset()
+ {
+ BossAI::Reset();
+ DoCast(me, SPELL_MAGMA_SPIT, true);
+ }
+
+ void EnterCombat(Unit* victim)
+ {
+ BossAI::EnterCombat(victim);
+ events.ScheduleEvent(EVENT_FRENZY, 30000);
+ events.ScheduleEvent(EVENT_PANIC, 20000);
+ events.ScheduleEvent(EVENT_LAVA_BOMB, 12000);
+ }
+
+ void UpdateAI(uint32 diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
- void Reset()
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
{
- BossAI::Reset();
- DoCast(me, SPELL_MAGMA_SPIT, true);
+ switch (eventId)
+ {
+ case EVENT_FRENZY:
+ Talk(EMOTE_FRENZY);
+ DoCast(me, SPELL_FRENZY);
+ events.ScheduleEvent(EVENT_FRENZY, 15000);
+ break;
+ case EVENT_PANIC:
+ DoCastVictim(SPELL_PANIC);
+ events.ScheduleEvent(EVENT_PANIC, 35000);
+ break;
+ case EVENT_LAVA_BOMB:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_LAVA_BOMB))
+ DoCast(target, SPELL_LAVA_BOMB);
+ events.ScheduleEvent(EVENT_LAVA_BOMB, 12000);
+ break;
+ default:
+ break;
+ }
}
- void EnterCombat(Unit* victim)
+ DoMeleeAttackIfReady();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new boss_magmadarAI(creature);
+ }
+};
+
+// Serrated Bites timer may be wrong
+class npc_magmadar_core_hound : public CreatureScript
+{
+public:
+ npc_magmadar_core_hound() : CreatureScript("npc_magmadar_core_hound") { }
+
+ struct npc_magmadar_core_houndAI : public CreatureAI
+ {
+ npc_magmadar_core_houndAI(Creature* creature) : CreatureAI(creature)
+ {
+ }
+
+ EventMap events;
+ std::list<Creature *> hounds;
+ bool smoldering = false;
+ Unit* killer;
+
+ void removeFeignDeath() {
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
+ me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
+ me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
+ me->RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT);
+ me->ClearUnitState(UNIT_STATE_DIED);
+ me->ClearUnitState(UNIT_STATE_CANNOT_AUTOATTACK);
+ me->DisableRotate(false);
+ }
+
+ void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/)
+ {
+ if (me->HealthBelowPctDamaged(0, damage))
{
- BossAI::EnterCombat(victim);
- events.ScheduleEvent(EVENT_FRENZY, 30000);
- events.ScheduleEvent(EVENT_PANIC, 20000);
- events.ScheduleEvent(EVENT_LAVA_BOMB, 12000);
+ if (!smoldering)
+ {
+ killer = attacker;
+ events.ScheduleEvent(EVENT_IGNITE, 10000);
+ me->SetHealth(1);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
+ me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
+ me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
+ me->AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
+ me->AddUnitState(UNIT_STATE_DIED);
+ me->AddUnitState(UNIT_STATE_CANNOT_AUTOATTACK);
+ me->DisableRotate(true);
+ Talk(EMOTE_SMOLDERING);
+ }
+ damage = 0;
+ smoldering = true;
}
+ }
- void UpdateAI(uint32 diff)
- {
- if (!UpdateVictim())
- return;
+ void Reset() {
+ removeFeignDeath();
+ }
+
+ void JustDied(Unit* /*killer*/) {
+ removeFeignDeath();
+ }
- events.Update(diff);
+ void EnterCombat(Unit* /*victim*/)
+ {
+ events.ScheduleEvent(EVENT_SERRATED_BITE, 10000); // timer may be wrong
+ }
+
+ void UpdateAI(uint32 diff)
+ {
+ if (!UpdateVictim() && !smoldering)
+ return;
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
+ events.Update(diff);
- while (uint32 eventId = events.ExecuteEvent())
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
{
- switch (eventId)
+ case EVENT_SERRATED_BITE:
+ if (UpdateVictim() && !smoldering) {
+ DoCast(me->GetVictim(), SPELL_SERRATED_BITE);
+ events.ScheduleEvent(EVENT_SERRATED_BITE, 10000); // again, timer may be wrong
+ }
+ break;
+ case EVENT_IGNITE:
+ smoldering = false;
+ me->GetCreaturesWithEntryInRange(hounds, 80, NPC_CORE_HOUND);
+ for (Creature * i : hounds)
{
- case EVENT_FRENZY:
- Talk(EMOTE_FRENZY);
- DoCast(me, SPELL_FRENZY);
- events.ScheduleEvent(EVENT_FRENZY, 15000);
- break;
- case EVENT_PANIC:
- DoCastVictim(SPELL_PANIC);
- events.ScheduleEvent(EVENT_PANIC, 35000);
- break;
- case EVENT_LAVA_BOMB:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_LAVA_BOMB))
- DoCast(target, SPELL_LAVA_BOMB);
- events.ScheduleEvent(EVENT_LAVA_BOMB, 12000);
- break;
- default:
- break;
+ if (i && i->IsAlive() && i->IsInCombat() && !i->HasUnitState(UNIT_STATE_DIED))
+ {
+ Talk(EMOTE_IGNITE);
+ me->SetFullHealth();
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
+ me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
+ me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
+ me->RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT);
+ me->ClearUnitState(UNIT_STATE_DIED);
+ me->ClearUnitState(UNIT_STATE_CANNOT_AUTOATTACK);
+ me->DisableRotate(false);
+ me->AI()->AttackStart(i->GetVictim());
+ return;
+ }
}
+ if (me->HasUnitState(UNIT_STATE_DIED))
+ {
+ if (killer)
+ {
+ me->Kill(killer, me);
+ }
+ else
+ {
+ me->Kill(me, me);
+ }
+ }
+ break;
+ default:
+ break;
}
-
- DoMeleeAttackIfReady();
}
- };
- CreatureAI* GetAI(Creature* creature) const
- {
- return new boss_magmadarAI(creature);
+ DoMeleeAttackIfReady();
}
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_magmadar_core_houndAI(creature);
+ }
};
void AddSC_boss_magmadar()
{
new boss_magmadar();
+ new npc_magmadar_core_hound();
}
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp
index 357ea5dd7d..ebf5aa3a2d 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp
@@ -80,6 +80,8 @@ class boss_majordomo : public CreatureScript
events.ScheduleEvent(EVENT_DAMAGE_REFLECTION, 15000);
events.ScheduleEvent(EVENT_BLAST_WAVE, 10000);
events.ScheduleEvent(EVENT_TELEPORT, 20000);
+ // Call every flamewaker around him
+ me->CallForHelp(30);
}
void UpdateAI(uint32 diff)
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp
index c4c415b9af..dceeab6c86 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp
@@ -61,6 +61,7 @@ enum Events
EVENT_INTRO_5 = 12
};
+
class boss_ragnaros : public CreatureScript
{
public:
@@ -83,6 +84,7 @@ class boss_ragnaros : public CreatureScript
_hasSubmergedOnce = false;
_isBanished = false;
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
+ me->SetOrientation(0.8f);
}
void EnterCombat(Unit* victim)
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp
index c97684c65a..8b0fba3cc9 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp
@@ -20,15 +20,15 @@ EndScriptData */
Position const SummonPositions[10] =
{
- {737.850f, -1145.35f, -120.288f, 4.71368f},
- {744.162f, -1151.63f, -119.726f, 4.58204f},
- {751.247f, -1152.82f, -119.744f, 4.49673f},
- {759.206f, -1155.09f, -120.051f, 4.30104f},
- {755.973f, -1152.33f, -120.029f, 4.25588f},
- {731.712f, -1147.56f, -120.195f, 4.95955f},
- {726.499f, -1149.80f, -120.156f, 5.24055f},
- {722.408f, -1152.41f, -120.029f, 5.33087f},
- {718.994f, -1156.36f, -119.805f, 5.75738f},
+ {759.542f, -1173.43f, -118.974f, 3.3048f},
+ {761.652f, -1164.30f, -119.533f, 3.3919f},
+ {747.323f, -1149.24f, -120.060f, 3.6629f},
+ {766.734f, -1183.16f, -119.292f, 2.9889f},
+ {757.364f, -1198.31f, -118.652f, 2.3095f},
+ {752.349f, -1159.19f, -119.261f, 3.6032f},
+ {738.015f, -1152.22f, -119.512f, 4.0792f},
+ {757.246f, -1189.79f, -118.633f, 2.5333f},
+ {745.916f, -1199.35f, -118.119f, 1.8932f},
{838.510f, -829.840f, -232.000f, 2.00000f},
};
@@ -45,29 +45,17 @@ class instance_molten_core : public InstanceMapScript
_golemaggTheIncineratorGUID = 0;
_majordomoExecutusGUID = 0;
_cacheOfTheFirelordGUID = 0;
- _executusSchedule = NULL;
_deadBossCount = 0;
_ragnarosAddDeaths = 0;
- _isLoading = false;
- _summonedExecutus = false;
}
- ~instance_molten_core_InstanceMapScript()
+ void OnPlayerEnter(Player* /*player*/) override
{
- delete _executusSchedule;
+ if (CheckMajordomoExecutus())
+ SummonMajordomoExecutus();
}
- void OnPlayerEnter(Player* /*player*/)
- {
- if (_executusSchedule)
- {
- SummonMajordomoExecutus(*_executusSchedule);
- delete _executusSchedule;
- _executusSchedule = NULL;
- }
- }
-
- void OnCreatureCreate(Creature* creature)
+ void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
@@ -82,19 +70,40 @@ class instance_molten_core : public InstanceMapScript
}
}
- void OnGameObjectCreate(GameObject* go)
+ void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_CACHE_OF_THE_FIRELORD:
_cacheOfTheFirelordGUID = go->GetGUID();
break;
+ case GO_CIRCLE_BARON:
+ _circlesGUIDs[5] = go->GetGUID();
+ break;
+ case GO_CIRCLE_GARR:
+ _circlesGUIDs[3] = go->GetGUID();
+ break;
+ case GO_CIRCLE_GEHENNAS:
+ _circlesGUIDs[2] = go->GetGUID();
+ break;
+ case GO_CIRCLE_GOLEMAGG:
+ _circlesGUIDs[7] = go->GetGUID();
+ break;
+ case GO_CIRCLE_MAGMADAR:
+ _circlesGUIDs[1] = go->GetGUID();
+ break;
+ case GO_CIRCLE_SHAZZRAH:
+ _circlesGUIDs[4] = go->GetGUID();
+ break;
+ case GO_CIRCLE_SULFURON:
+ _circlesGUIDs[6] = go->GetGUID();
+ break;
default:
break;
}
}
- void SetData(uint32 type, uint32 data)
+ void SetData(uint32 type, uint32 data) override
{
if (type == DATA_RAGNAROS_ADDS)
{
@@ -105,7 +114,7 @@ class instance_molten_core : public InstanceMapScript
}
}
- uint32 GetData(uint32 type) const
+ uint32 GetData(uint32 type) const override
{
switch (type)
{
@@ -116,7 +125,7 @@ class instance_molten_core : public InstanceMapScript
return 0;
}
- uint64 GetData64(uint32 type) const
+ uint64 GetData64(uint32 type) const override
{
switch (type)
{
@@ -129,33 +138,28 @@ class instance_molten_core : public InstanceMapScript
return 0;
}
- bool SetBossState(uint32 bossId, EncounterState state)
+ bool SetBossState(uint32 bossId, EncounterState state) override
{
if (!InstanceScript::SetBossState(bossId, state))
return false;
-
+
if (state == DONE && bossId < BOSS_MAJORDOMO_EXECUTUS)
- ++_deadBossCount;
-
- if (_isLoading)
- return true;
-
- if (_deadBossCount == 8)
- SummonMajordomoExecutus(false);
-
- if (bossId == BOSS_MAJORDOMO_EXECUTUS && state == DONE)
+ if (CheckMajordomoExecutus())
+ SummonMajordomoExecutus();
+
+ if (bossId == BOSS_MAJORDOMO_EXECUTUS && state == DONE) {
DoRespawnGameObject(_cacheOfTheFirelordGUID, 7 * DAY);
+ }
return true;
}
- void SummonMajordomoExecutus(bool done)
+ void SummonMajordomoExecutus()
{
- if (_summonedExecutus)
+ if (_majordomoExecutusGUID)
return;
- _summonedExecutus = true;
- if (!done)
+ if (GetBossState(BOSS_MAJORDOMO_EXECUTUS) != DONE)
{
instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, SummonPositions[0]);
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[1]);
@@ -168,10 +172,22 @@ class instance_molten_core : public InstanceMapScript
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[8]);
}
else if (TempSummon* summon = instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, RagnarosTelePos))
- summon->AI()->DoAction(ACTION_START_RAGNAROS_ALT);
+ summon->AI()->DoAction(ACTION_START_RAGNAROS_ALT);
}
- std::string GetSaveData()
+ bool CheckMajordomoExecutus() const
+ {
+ if (GetBossState(BOSS_RAGNAROS) == DONE)
+ return false;
+
+ for (uint8 i = 0; i < BOSS_MAJORDOMO_EXECUTUS; ++i)
+ if (GetBossState(i) != DONE)
+ return false;
+
+ return true;
+ }
+
+ std::string GetSaveData() override
{
OUT_SAVE_INST_DATA;
@@ -182,7 +198,7 @@ class instance_molten_core : public InstanceMapScript
return saveStream.str();
}
- void Load(char const* data)
+ void Load(char const* data) override
{
if (!data)
{
@@ -190,7 +206,6 @@ class instance_molten_core : public InstanceMapScript
return;
}
- _isLoading = true;
OUT_LOAD_INST_DATA(data);
char dataHead1, dataHead2;
@@ -200,44 +215,32 @@ class instance_molten_core : public InstanceMapScript
if (dataHead1 == 'M' && dataHead2 == 'C')
{
- EncounterState states[MAX_ENCOUNTER];
- uint8 executusCounter = 0;
-
- // need 2 loops to check spawning executus/ragnaros
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
{
uint32 tmpState;
loadStream >> tmpState;
if (tmpState == IN_PROGRESS || tmpState > TO_BE_DECIDED)
tmpState = NOT_STARTED;
- states[i] = EncounterState(tmpState);
-
- if (tmpState == DONE && i < BOSS_MAJORDOMO_EXECUTUS)
- ++executusCounter;
- }
- if (executusCounter >= 8 && states[BOSS_RAGNAROS] != DONE)
- _executusSchedule = new bool(states[BOSS_MAJORDOMO_EXECUTUS] == DONE);
+ SetBossState(i, EncounterState(tmpState));
+ }
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- SetBossState(i, states[i]);
+ if (CheckMajordomoExecutus())
+ SummonMajordomoExecutus();
}
else
OUT_LOAD_INST_DATA_FAIL;
OUT_LOAD_INST_DATA_COMPLETE;
- _isLoading = false;
}
private:
uint64 _golemaggTheIncineratorGUID;
uint64 _majordomoExecutusGUID;
uint64 _cacheOfTheFirelordGUID;
- bool* _executusSchedule;
uint8 _deadBossCount;
uint8 _ragnarosAddDeaths;
- bool _isLoading;
- bool _summonedExecutus;
+ std::unordered_map<uint8, uint64> _circlesGUIDs;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h
index 4c2f6ca393..ae4531435d 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h
@@ -47,11 +47,20 @@ enum Creatures
NPC_RAGNAROS = 11502,
NPC_FLAMEWAKER_HEALER = 11663,
NPC_FLAMEWAKER_ELITE = 11664,
+ NPC_CORE_RAGER = 11672,
+ NPC_CORE_HOUND = 11671,
};
enum GameObjects
{
GO_CACHE_OF_THE_FIRELORD = 179703,
+ GO_CIRCLE_SULFURON = 178187,
+ GO_CIRCLE_BARON = 178188,
+ GO_CIRCLE_SHAZZRAH = 178189,
+ GO_CIRCLE_GOLEMAGG = 178190,
+ GO_CIRCLE_GARR = 178191,
+ GO_CIRCLE_MAGMADAR = 178192,
+ GO_CIRCLE_GEHENNAS = 178193,
};
enum Data
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp
index 55c745a8a8..3278c123f4 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp
@@ -196,11 +196,13 @@ class boss_ayamiss : public CreatureScript
events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000);
break;
case EVENT_SUMMON_SWARMER:
+ {
Position Pos;
me->GetRandomPoint(SwarmerPos, 80.0f, Pos);
me->SummonCreature(NPC_SWARMER, Pos);
events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000);
break;
+ }
case EVENT_TRASH:
DoCastVictim(SPELL_TRASH);
events.ScheduleEvent(EVENT_TRASH, urand(5000, 7000));
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
index f16be1443d..5f48069dd1 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
@@ -880,7 +880,7 @@ public:
}
else
{
- NextWaveTimer = 65000;
+ NextWaveTimer = 150000;
uint8 num_to_activate = 5;
if (WaveNumber <= 2)
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
index e33efd3fa5..dd4f6b2e76 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
@@ -107,7 +107,7 @@ enum Spells
SPELL_RISEN_WITCH_DOCTOR_SPAWN = 69639,
SPELL_SUMMON_SHAMBLING_HORROR = 70372,
SPELL_SUMMON_DRUDGE_GHOULS = 70358,
- SPELL_INFEST = 70541,
+ SPELL_INFEST = 70541, //cast time 2 sec
SPELL_NECROTIC_PLAGUE = 70337,
SPELL_NECROTIC_PLAGUE_JUMP = 70338,
SPELL_PLAGUE_SIPHON = 74074,
@@ -116,12 +116,12 @@ enum Spells
SPELL_SHADOW_TRAP_KNOCKBACK = 73529,
// Phase 2
- SPELL_DEFILE = 72762,
+ SPELL_DEFILE = 72762, //cast time 2 sec
SPELL_DEFILE_AURA = 72743,
SPELL_DEFILE_GROW = 72756,
- SPELL_SOUL_REAPER = 69409,
+ SPELL_SOUL_REAPER = 69409, // instant
SPELL_SOUL_REAPER_BUFF = 69410,
- SPELL_SUMMON_VALKYR = 69037,
+ SPELL_SUMMON_VALKYR = 69037, // instant
SPELL_SUMMON_VALKYR_PERIODIC = 74361,
SPELL_WINGS_OF_THE_DAMNED = 74352,
SPELL_VALKYR_TARGET_SEARCH = 69030,
@@ -980,10 +980,10 @@ class boss_the_lich_king : public CreatureScript
case EVENT_QUAKE:
_phase = PHASE_TWO;
events.CancelEventGroup(EVENT_GROUP_ABILITIES);
- events.ScheduleEvent(EVENT_INFEST, 8000, EVENT_GROUP_ABILITIES);
- events.ScheduleEvent(EVENT_SUMMON_VALKYR, 15000, EVENT_GROUP_ABILITIES);
- events.ScheduleEvent(EVENT_SOUL_REAPER, 22000, EVENT_GROUP_ABILITIES);
- events.ScheduleEvent(EVENT_DEFILE, 32500, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_INFEST, 14000, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_SUMMON_VALKYR, 20000, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_SOUL_REAPER, 40000, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_DEFILE, 38000, EVENT_GROUP_ABILITIES);
me->InterruptNonMeleeSpells(false);
me->ClearUnitState(UNIT_STATE_CASTING);
@@ -995,10 +995,10 @@ class boss_the_lich_king : public CreatureScript
case EVENT_QUAKE_2:
_phase = PHASE_THREE;
events.CancelEventGroup(EVENT_GROUP_ABILITIES);
- events.ScheduleEvent(EVENT_SOUL_REAPER, 25000, EVENT_GROUP_ABILITIES);
- events.ScheduleEvent(EVENT_DEFILE, 32500, EVENT_GROUP_ABILITIES);
- events.ScheduleEvent(EVENT_VILE_SPIRITS, 18000, EVENT_GROUP_VILE_SPIRITS);
- events.ScheduleEvent(IsHeroic() ? EVENT_HARVEST_SOULS : EVENT_HARVEST_SOUL, 11000, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_SOUL_REAPER, 40000, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_DEFILE, 38000, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_VILE_SPIRITS, 20000, EVENT_GROUP_VILE_SPIRITS);
+ events.ScheduleEvent(IsHeroic() ? EVENT_HARVEST_SOULS : EVENT_HARVEST_SOUL, 14000, EVENT_GROUP_ABILITIES);
me->InterruptNonMeleeSpells(false);
me->ClearUnitState(UNIT_STATE_CASTING);
@@ -1020,7 +1020,7 @@ class boss_the_lich_king : public CreatureScript
break;
case EVENT_INFEST:
me->CastSpell(me, SPELL_INFEST, false);
- events.ScheduleEvent(EVENT_INFEST, urand(21000, 22000), EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_INFEST, 22500, EVENT_GROUP_ABILITIES);
break;
case EVENT_NECROTIC_PLAGUE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NecroticPlagueTargetCheck(me, NECROTIC_PLAGUE_LK, NECROTIC_PLAGUE_PLR)))
@@ -1040,7 +1040,7 @@ class boss_the_lich_king : public CreatureScript
case EVENT_PAIN_AND_SUFFERING:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
- events.DelayEventsToMax(500, EVENT_GROUP_ABILITIES);
+ //events.DelayEventsToMax(500, EVENT_GROUP_ABILITIES);
me->SetOrientation(me->GetAngle(target));
me->CastSpell(target, SPELL_PAIN_AND_SUFFERING, false);
}
@@ -1058,33 +1058,43 @@ class boss_the_lich_king : public CreatureScript
case EVENT_DEFILE:
{
uint32 evTime = events.GetNextEventTime(EVENT_SUMMON_VALKYR);
- if (evTime && (events.GetTimer() > evTime || evTime - events.GetTimer() < 5000)) // defile cast 2sec -> valkyr in less than 3 secs after defile appears
+ // if defile (cast time 2sec) is less than 3 before valkyr appears
+ // we've to decide
+ if (evTime && (events.GetTimer() > evTime || evTime - events.GetTimer() < 5000))
{
- if (events.GetTimer() > evTime || evTime - events.GetTimer() < 3500) // valkyr is less than 1.5 secs after defile - reschedule defile
+ // if valkyr is less than 1.5 secs after defile (cast time 2 sec) then we've a sync issue, so
+ // we need to cancel it (break) and schedule a defile to be casted 5 or 4 seconds after valkyr
+ if (events.GetTimer() > evTime || evTime - events.GetTimer() < 3500)
{
uint32 t = events.GetTimer() > evTime ? 0 : evTime - events.GetTimer();
events.ScheduleEvent(EVENT_DEFILE, t+(Is25ManRaid() ? 5000 : 4000), EVENT_GROUP_ABILITIES);
break;
- }
+ }
+
+ // if valkyr is coming between 1.5 and 3 seconds after defile then we've to
// delay valkyr just a bit
events.RescheduleEvent(EVENT_SUMMON_VALKYR, 5000, EVENT_GROUP_ABILITIES);
}
+
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, DefileTargetSelector(me)))
{
Talk(EMOTE_DEFILE_WARNING);
me->CastSpell(target, SPELL_DEFILE, false);
- events.ScheduleEvent(EVENT_DEFILE, urand(31000, 34000), EVENT_GROUP_ABILITIES);
+ // defile has a fixed CD (from dbm) that can be variable only
+ // if no target has been found at the moment (schedule after 1 second)
+ events.ScheduleEvent(EVENT_DEFILE, 32500, EVENT_GROUP_ABILITIES);
+ }
+ else {
+ // be sure it happen trying each seconds if no target
+ events.ScheduleEvent(EVENT_DEFILE, 1000, EVENT_GROUP_ABILITIES);
}
- else
- events.ScheduleEvent(EVENT_DEFILE, 2000, EVENT_GROUP_ABILITIES);
}
break;
case EVENT_SOUL_REAPER:
if (me->IsWithinMeleeRange(me->GetVictim()))
{
me->CastSpell(me->GetVictim(), SPELL_SOUL_REAPER, false);
- events.DelayEventsToMax(12000, EVENT_GROUP_ABILITIES);
- events.ScheduleEvent(EVENT_SOUL_REAPER, 30000, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_SOUL_REAPER, 30500, EVENT_GROUP_ABILITIES);
}
else
events.ScheduleEvent(EVENT_SOUL_REAPER, 1000, EVENT_GROUP_ABILITIES);
@@ -1094,12 +1104,15 @@ class boss_the_lich_king : public CreatureScript
me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL);
Talk(SAY_LK_SUMMON_VALKYR);
me->CastSpell((Unit*)NULL, SUMMON_VALKYR, false);
- events.ScheduleEvent(EVENT_SUMMON_VALKYR, urand(45000, 48000), EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_SUMMON_VALKYR, 45000, EVENT_GROUP_ABILITIES);
+ // schedule a defile (or reschedule it) if next defile event
+ // doesn't exist ( now > next defile ) or defile is coming too soon
uint32 minTime = (Is25ManRaid() ? 5000 : 4000);
if (uint32 evTime = events.GetNextEventTime(EVENT_DEFILE))
- if (events.GetTimer() > evTime || evTime - events.GetTimer() < minTime)
+ if (events.GetTimer() > evTime || evTime - events.GetTimer() < minTime) {
events.RescheduleEvent(EVENT_DEFILE, minTime, EVENT_GROUP_ABILITIES);
+ }
}
break;
case EVENT_VILE_SPIRITS:
@@ -1112,7 +1125,7 @@ class boss_the_lich_king : public CreatureScript
{
Talk(SAY_LK_HARVEST_SOUL);
me->CastSpell(target, SPELL_HARVEST_SOUL, false);
- events.ScheduleEvent(EVENT_HARVEST_SOUL, 70000, EVENT_GROUP_ABILITIES);
+ events.ScheduleEvent(EVENT_HARVEST_SOUL, 75000, EVENT_GROUP_ABILITIES);
}
else
events.ScheduleEvent(EVENT_HARVEST_SOUL, 10000, EVENT_GROUP_ABILITIES);
@@ -3789,4 +3802,4 @@ void AddSC_boss_the_lich_king()
new npc_lk_wicked_spirit();
new achievement_been_waiting_long_time();
new achievement_neck_deep_in_vile();
-} \ No newline at end of file
+}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index d1adf13cd9..b6d11e8967 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -1548,7 +1548,8 @@ class instance_icecrown_citadel : public InstanceMapScript
std::ostringstream saveStream;
saveStream << "I C " << GetBossSaveData() << HeroicAttempts << ' '
<< ColdflameJetsState << ' ' << BloodQuickeningState << ' ' << BloodQuickeningMinutes << ' ' << WeeklyQuestId10 << ' ' << PutricideEventProgress << ' '
- << uint32(LichKingHeroicAvailable ? 1 : 0) << ' ' << BloodPrinceTrashCount;
+ << uint32(LichKingHeroicAvailable ? 1 : 0) << ' ' << BloodPrinceTrashCount << ' ' << uint32(IsBuffAvailable ? 1 : 0);
+
OUT_SAVE_INST_DATA_COMPLETE;
return saveStream.str();
@@ -1600,6 +1601,8 @@ class instance_icecrown_citadel : public InstanceMapScript
loadStream >> temp;
LichKingHeroicAvailable = temp ? true : false;
loadStream >> BloodPrinceTrashCount;
+ loadStream >> temp;
+ SetData(DATA_BUFF_AVAILABLE, temp ? true : false);
}
else
OUT_LOAD_INST_DATA_FAIL;
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
index 1b8f6de3e7..461ce780a9 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
@@ -49,9 +49,9 @@ public:
return new boss_anubrekhanAI (pCreature);
}
- struct boss_anubrekhanAI : public ScriptedAI
+ struct boss_anubrekhanAI : public BossAI
{
- boss_anubrekhanAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_anubrekhanAI(Creature *c) : BossAI(c, BOSS_ANUB), summons(me)
{
pInstance = c->GetInstanceScript();
sayGreet = false;
@@ -71,15 +71,15 @@ public:
}
}
- void Reset()
+ void Reset()
{
+ BossAI::Reset();
events.Reset();
summons.DespawnAll();
SummonCryptGuards();
if (pInstance)
{
- pInstance->SetData(EVENT_ANUB, NOT_STARTED);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_ANUB_GATE)))
go->SetGoState(GO_STATE_ACTIVE);
}
@@ -107,13 +107,13 @@ public:
void SummonedCreatureDespawn(Creature* cr) { summons.Despawn(cr); }
- void JustDied(Unit* /*Killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
summons.DespawnAll();
if (pInstance)
{
pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
- pInstance->SetData(EVENT_ANUB, DONE);
}
}
@@ -132,13 +132,13 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
me->CallForHelp(30.0f); // catch helpers
Talk(SAY_AGGRO);
if (pInstance)
{
- pInstance->SetData(EVENT_ANUB, IN_PROGRESS);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_ANUB_GATE)))
go->SetGoState(GO_STATE_READY);
}
@@ -179,12 +179,14 @@ public:
events.RepeatEvent(20000);
break;
case EVENT_SPELL_LOCUST_SWARM:
+ {
me->CastSpell(me, RAID_MODE(SPELL_LOCUST_SWARM_10, SPELL_LOCUST_SWARM_25), false);
Position pos;
- me->GetNearPosition(pos, 10.0f, rand_norm()*2*M_PI);
+ me->GetNearPosition(pos, 10.0f, rand_norm() * 2 * M_PI);
me->SummonCreature(NPC_CRYPT_GUARD, pos);
events.RepeatEvent(90000);
break;
+ }
case EVENT_SPELL_BERSERK:
me->CastSpell(me, SPELL_BERSERK, true);
events.PopEvent();
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
index 65545bba68..96961d1ae2 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
@@ -49,9 +49,9 @@ public:
return new boss_faerlinaAI (pCreature);
}
- struct boss_faerlinaAI : public ScriptedAI
+ struct boss_faerlinaAI : public BossAI
{
- boss_faerlinaAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_faerlinaAI(Creature *c) : BossAI(c, BOSS_FAERLINA), summons(me)
{
pInstance = me->GetInstanceScript();
sayGreet = false;
@@ -81,24 +81,21 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
summons.DespawnAll();
SummonHelpers();
- if (pInstance)
- pInstance->SetData(EVENT_FAERLINA, NOT_STARTED);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
- me->SetInCombatWithZone();
+ BossAI::EnterCombat(who);
+ summons.DoZoneInCombat();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_POISON_BOLT, urand(12000,15000));
events.ScheduleEvent(EVENT_SPELL_RAIN_OF_FIRE, urand(6000,18000));
events.ScheduleEvent(EVENT_SPELL_FRENZY, urand(60000,80000), 1);
events.SetPhase(1);
-
- if (pInstance)
- pInstance->SetData(EVENT_FAERLINA, IN_PROGRESS);
}
void MoveInLineOfSight(Unit *who)
@@ -124,11 +121,10 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void JustDied(Unit* /*Killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
Talk(SAY_DEATH);
- if (pInstance)
- pInstance->SetData(EVENT_FAERLINA, DONE);
}
void UpdateAI(uint32 diff)
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp
index 36c8b29979..21cff6286e 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp
@@ -121,9 +121,9 @@ public:
return new boss_four_horsemenAI (pCreature);
}
- struct boss_four_horsemenAI : public ScriptedAI
+ struct boss_four_horsemenAI : public BossAI
{
- boss_four_horsemenAI(Creature *c) : ScriptedAI(c)
+ boss_four_horsemenAI(Creature *c) : BossAI(c, BOSS_HORSEMAN)
{
pInstance = me->GetInstanceScript();
switch (me->GetEntry())
@@ -174,15 +174,13 @@ public:
void Reset()
{
+ BossAI::Reset();
me->SetPosition(me->GetHomePosition());
movementPhase = MOVE_PHASE_NONE;
currentWaypoint = 0;
me->SetReactState(REACT_AGGRESSIVE);
events.Reset();
- if (pInstance)
- pInstance->SetData(EVENT_HORSEMAN, NOT_STARTED);
-
// Schedule Events
events.RescheduleEvent(EVENT_SPELL_MARK_CAST, 24000);
events.RescheduleEvent(EVENT_BERSERK, 100*15000);
@@ -248,25 +246,24 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void JustDied(Unit* /*killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
if (pInstance)
{
- pInstance->SetData(EVENT_HORSEMAN, DONE);
- if (pInstance->GetData(EVENT_HORSEMAN) == DONE)
+ if (pInstance->GetBossState(BOSS_HORSEMAN) == DONE) {
if (!me->GetMap()->GetPlayers().isEmpty())
if (Player* player = me->GetMap()->GetPlayers().getFirst()->GetSource())
player->SummonGameObject(RAID_MODE(GO_HORSEMEN_CHEST_10, GO_HORSEMEN_CHEST_25), 2514.8f, -2944.9f, 245.55f, 5.51f, 0, 0, 0, 0, 0);
+ }
}
Talk(SAY_DEATH);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
- if (pInstance)
- pInstance->SetData(EVENT_HORSEMAN, IN_PROGRESS);
-
+ BossAI::EnterCombat(who);
if (movementPhase == MOVE_PHASE_NONE)
{
Talk(SAY_AGGRO);
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
index 5a39e88fef..fdc4a5e6a8 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
@@ -52,9 +52,9 @@ public:
return new boss_gluthAI (pCreature);
}
- struct boss_gluthAI : public ScriptedAI
+ struct boss_gluthAI : public BossAI
{
- boss_gluthAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_gluthAI(Creature *c) : BossAI(c, BOSS_GLUTH), summons(me)
{
pInstance = me->GetInstanceScript();
}
@@ -66,14 +66,12 @@ public:
void Reset()
{
+ BossAI::Reset();
me->ApplySpellImmune(29306, IMMUNITY_ID, 29306, true);
events.Reset();
summons.DespawnAll();
gazeTarget = 0;
me->SetReactState(REACT_AGGRESSIVE);
-
- if (pInstance)
- pInstance->SetData(EVENT_GLUTH, NOT_STARTED);
}
void MoveInLineOfSight(Unit *who)
@@ -87,8 +85,9 @@ public:
ScriptedAI::MoveInLineOfSight(who);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
me->SetInCombatWithZone();
events.ScheduleEvent(EVENT_SPELL_MORTAL_WOUND, 10000);
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 30000);
@@ -96,9 +95,6 @@ public:
events.ScheduleEvent(EVENT_SPELL_BERSERK, 8*60000);
events.ScheduleEvent(EVENT_SUMMON_ZOMBIE, 10000);
events.ScheduleEvent(EVENT_CAN_EAT_ZOMBIE, 1000);
-
- if (pInstance)
- pInstance->SetData(EVENT_GLUTH, IN_PROGRESS);
}
void JustSummoned(Creature *summon)
@@ -120,11 +116,10 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void JustDied(Unit*)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
summons.DespawnAll();
- if (pInstance)
- pInstance->SetData(EVENT_GLUTH, DONE);
}
bool SelectPlayerInRoom()
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
index 10330f28ab..897103e475 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
@@ -135,9 +135,9 @@ public:
return new boss_gothikAI (pCreature);
}
- struct boss_gothikAI : public ScriptedAI
+ struct boss_gothikAI : public BossAI
{
- boss_gothikAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_gothikAI(Creature *c) : BossAI(c, BOSS_GOTHIK), summons(me)
{
pInstance = me->GetInstanceScript();
}
@@ -162,6 +162,7 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
summons.DespawnAll();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_DISABLE_MOVE);
@@ -172,7 +173,6 @@ public:
if (pInstance)
{
- pInstance->SetData(EVENT_GOTHIK, NOT_STARTED);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_GOTHIK_ENTER_GATE)))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_GOTHIK_INNER_GATE)))
@@ -182,8 +182,9 @@ public:
}
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
me->SetInCombatWithZone();
Talk(SAY_SPEECH);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_DISABLE_MOVE);
@@ -194,7 +195,6 @@ public:
if (pInstance)
{
- pInstance->SetData(EVENT_GOTHIK, IN_PROGRESS);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_GOTHIK_ENTER_GATE)))
go->SetGoState(GO_STATE_READY);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_GOTHIK_INNER_GATE)))
@@ -225,14 +225,14 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void JustDied(Unit* /*Killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
Talk(SAY_DEATH);
summons.DespawnAll();
if (pInstance)
{
- pInstance->SetData(EVENT_GOTHIK, DONE);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_GOTHIK_ENTER_GATE)))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_GOTHIK_INNER_GATE)))
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
index e0ab0e9a58..aa8b87531b 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
@@ -45,9 +45,9 @@ public:
return new boss_grobbulusAI (pCreature);
}
- struct boss_grobbulusAI : public ScriptedAI
+ struct boss_grobbulusAI : public BossAI
{
- boss_grobbulusAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_grobbulusAI(Creature *c) : BossAI(c, BOSS_GROBBULUS), summons(me)
{
pInstance = me->GetInstanceScript();
}
@@ -59,24 +59,20 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
summons.DespawnAll();
dropSludgeTimer = 0;
-
- if (pInstance)
- pInstance->SetData(EVENT_GROBBULUS, NOT_STARTED);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
me->SetInCombatWithZone();
events.ScheduleEvent(EVENT_SPELL_POISON_CLOUD, 15000);
events.ScheduleEvent(EVENT_SPELL_MUTATING_INJECTION, 20000);
events.ScheduleEvent(EVENT_SPELL_SLIME_SPRAY, 10000);
events.ScheduleEvent(EVENT_SPELL_BERSERK, RAID_MODE(12*MINUTE*IN_MILLISECONDS, 9*MINUTE*IN_MILLISECONDS));
-
- if (pInstance)
- pInstance->SetData(EVENT_GROBBULUS, IN_PROGRESS);
}
void SpellHitTarget(Unit *target, const SpellInfo* spellInfo)
@@ -95,11 +91,10 @@ public:
void SummonedCreatureDespawn(Creature* summon){ summons.Despawn(summon); }
- void JustDied(Unit*)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
summons.DespawnAll();
- if (pInstance)
- pInstance->SetData(EVENT_GROBBULUS, DONE);
}
void KilledUnit(Unit* who)
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
index 1c7461c92c..c6039bac60 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
@@ -48,9 +48,9 @@ public:
return new boss_heiganAI (pCreature);
}
- struct boss_heiganAI : public ScriptedAI
+ struct boss_heiganAI : public BossAI
{
- boss_heiganAI(Creature *c) : ScriptedAI(c)
+ boss_heiganAI(Creature *c) : BossAI(c, BOSS_HEIGAN)
{
pInstance = me->GetInstanceScript();
}
@@ -63,6 +63,7 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
currentPhase = 0;
currentSection = 3;
@@ -70,7 +71,6 @@ public:
if (pInstance)
{
- pInstance->SetData(EVENT_HEIGAN, NOT_STARTED);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_HEIGAN_ENTER_GATE)))
go->SetGoState(GO_STATE_ACTIVE);
}
@@ -88,20 +88,19 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void JustDied(Unit* /*Killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
Talk(SAY_DEATH);
- if (pInstance)
- pInstance->SetData(EVENT_HEIGAN, DONE);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
me->SetInCombatWithZone();
Talk(SAY_AGGRO);
if (pInstance)
{
- pInstance->SetData(EVENT_HEIGAN, IN_PROGRESS);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_HEIGAN_ENTER_GATE)))
go->SetGoState(GO_STATE_READY);
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
index 0e9f2148f8..5af8fbd6aa 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
@@ -115,9 +115,9 @@ public:
return new boss_kelthuzadAI (pCreature);
}
- struct boss_kelthuzadAI : public ScriptedAI
+ struct boss_kelthuzadAI : public BossAI
{
- boss_kelthuzadAI(Creature* c) : ScriptedAI(c), summons(me)
+ boss_kelthuzadAI(Creature* c) : BossAI(c, BOSS_KELTHUZAD), summons(me)
{
pInstance = me->GetInstanceScript();
}
@@ -162,6 +162,7 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
summons.DespawnAll();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE);
@@ -169,7 +170,6 @@ public:
if (pInstance)
{
- pInstance->SetData(EVENT_KELTHUZAD, NOT_STARTED);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_KELTHUZAD_FLOOR)))
{
go->SetPhaseMask(1, true);
@@ -198,12 +198,11 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void JustDied(Unit* /*Killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
summons.DespawnAll();
Talk(SAY_DEATH);
- if (pInstance)
- pInstance->SetData(EVENT_KELTHUZAD, DONE);
}
void MoveInLineOfSight(Unit* who)
@@ -212,8 +211,9 @@ public:
AttackStart(who);
}
- void EnterCombat(Unit* /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
Talk(SAY_SUMMON_MINIONS);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
me->RemoveAllAttackers();
@@ -229,7 +229,6 @@ public:
events.ScheduleEvent(EVENT_START_SECOND_PHASE, 228000);
if (pInstance)
{
- pInstance->SetData(EVENT_KELTHUZAD, IN_PROGRESS);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_KELTHUZAD_FLOOR)))
{
events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15000);
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
index dca14d834f..165ff01329 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
@@ -42,9 +42,9 @@ public:
return new boss_loathebAI (pCreature);
}
- struct boss_loathebAI : public ScriptedAI
+ struct boss_loathebAI : public BossAI
{
- boss_loathebAI(Creature *c) : ScriptedAI(c)
+ boss_loathebAI(Creature *c) : BossAI(c, BOSS_LOATHEB)
{
pInstance = me->GetInstanceScript();
}
@@ -54,10 +54,10 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
if (pInstance)
{
- pInstance->SetData(EVENT_LOATHEB, NOT_STARTED);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_LOATHEB_GATE)))
go->SetGoState(GO_STATE_ACTIVE);
}
@@ -77,11 +77,11 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
if (pInstance)
{
- pInstance->SetData(EVENT_LOATHEB, IN_PROGRESS);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_LOATHEB_GATE)))
go->SetGoState(GO_STATE_READY);
}
@@ -93,12 +93,6 @@ public:
events.ScheduleEvent(EVENT_SPELL_BERSERK, 720000);
}
- void JustDied(Unit* /*Killer*/)
- {
- if (pInstance)
- pInstance->SetData(EVENT_LOATHEB, DONE);
- }
-
void UpdateAI(uint32 diff)
{
if (!UpdateVictim())
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
index ad9515e9de..f93e5758cb 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
@@ -53,9 +53,9 @@ public:
return new boss_maexxnaAI (pCreature);
}
- struct boss_maexxnaAI : public ScriptedAI
+ struct boss_maexxnaAI : public BossAI
{
- boss_maexxnaAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_maexxnaAI(Creature *c) : BossAI(c, BOSS_MAEXXNA), summons(me)
{
pInstance = me->GetInstanceScript();
}
@@ -77,20 +77,21 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
summons.DespawnAll();
if (pInstance)
{
- pInstance->SetData(EVENT_MAEXXNA, NOT_STARTED);
- if (pInstance->GetData(EVENT_FAERLINA) == DONE)
+ if (pInstance->GetData(BOSS_FAERLINA) == DONE)
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_MAEXXNA_GATE)))
go->SetGoState(GO_STATE_ACTIVE);
}
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
me->SetInCombatWithZone();
events.ScheduleEvent(EVENT_WEB_WRAP, 20000);
events.ScheduleEvent(EVENT_SPELL_WEB_SPRAY, 40000);
@@ -101,18 +102,11 @@ public:
if (pInstance)
{
- pInstance->SetData(EVENT_MAEXXNA, IN_PROGRESS);
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_MAEXXNA_GATE)))
go->SetGoState(GO_STATE_READY);
}
}
- void JustDied(Unit* /*Killer*/)
- {
- if (pInstance)
- pInstance->SetData(EVENT_MAEXXNA, DONE);
- }
-
void JustSummoned(Creature* cr)
{
if (cr->GetEntry() == NPC_MAEXXNA_SPIDERLING)
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
index aa0cdeada6..95f81ca99b 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
@@ -66,9 +66,9 @@ public:
return new boss_nothAI (pCreature);
}
- struct boss_nothAI : public ScriptedAI
+ struct boss_nothAI : public BossAI
{
- boss_nothAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_nothAI(Creature *c) : BossAI(c, BOSS_NOTH), summons(me)
{
pInstance = me->GetInstanceScript();
}
@@ -123,14 +123,12 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
summons.DespawnAll();
me->SetControlled(false, UNIT_STATE_ROOT);
me->SetReactState(REACT_AGGRESSIVE);
events.SetPhase(0);
-
- if (pInstance)
- pInstance->SetData(EVENT_NOTH, NOT_STARTED);
}
void EnterEvadeMode()
@@ -139,12 +137,10 @@ public:
ScriptedAI::EnterEvadeMode();
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
- if (pInstance)
- pInstance->SetData(EVENT_NOTH, IN_PROGRESS);
-
StartGroundPhase();
}
@@ -154,11 +150,10 @@ public:
summon->SetInCombatWithZone();
}
- void JustDied(Unit* /*Killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
Talk(SAY_DEATH);
- if (pInstance)
- pInstance->SetData(EVENT_NOTH, DONE);
}
void KilledUnit(Unit* who)
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
index 05b5b4649a..18910bbcd3 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
@@ -47,9 +47,9 @@ public:
return new boss_patchwerkAI (pCreature);
}
- struct boss_patchwerkAI : public ScriptedAI
+ struct boss_patchwerkAI : public BossAI
{
- boss_patchwerkAI(Creature *c) : ScriptedAI(c)
+ boss_patchwerkAI(Creature *c) : BossAI(c, BOSS_PATCHWERK)
{
pInstance = me->GetInstanceScript();
}
@@ -59,9 +59,8 @@ public:
void Reset()
{
+ BossAI::Reset();
events.Reset();
- if (pInstance)
- pInstance->SetData(EVENT_PATCHWERK, NOT_STARTED);
}
void KilledUnit(Unit* who)
@@ -76,15 +75,15 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void JustDied(Unit* /*Killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
Talk(SAY_DEATH);
- if (pInstance)
- pInstance->SetData(EVENT_PATCHWERK, DONE);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
me->SetInCombatWithZone();
@@ -95,7 +94,6 @@ public:
if (pInstance)
{
pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
- pInstance->SetData(EVENT_PATCHWERK, IN_PROGRESS);
}
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
index 418fae7324..def339cf5e 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
@@ -60,9 +60,9 @@ public:
return new boss_razuviousAI (pCreature);
}
- struct boss_razuviousAI : public ScriptedAI
+ struct boss_razuviousAI : public BossAI
{
- boss_razuviousAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_razuviousAI(Creature *c) : BossAI(c, BOSS_RAZUVIOUS), summons(me)
{
pInstance = me->GetInstanceScript();
}
@@ -86,11 +86,10 @@ public:
void Reset()
{
+ BossAI::Reset();
summons.DespawnAll();
events.Reset();
SpawnHelpers();
- if (pInstance)
- pInstance->SetData(EVENT_RAZUVIOUS, NOT_STARTED);
}
void KilledUnit(Unit* who)
@@ -115,18 +114,18 @@ public:
me->LowerPlayerDamageReq(damage);
}
- void JustDied(Unit* /*killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
DoPlaySoundToSet(me, SOUND_DEATH);
me->MonsterYell("An honorable... death...", LANG_UNIVERSAL, 0);
me->CastSpell(me, SPELL_HOPELESS, true);
- if (pInstance)
- pInstance->SetData(EVENT_RAZUVIOUS, DONE);
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
switch (urand(0,2))
{
case 0:
@@ -147,8 +146,6 @@ public:
events.ScheduleEvent(EVENT_SPELL_DISRUPTING_SHOUT, 25000);
events.ScheduleEvent(EVENT_SPELL_JAGGED_KNIFE, 15000);
events.ScheduleEvent(EVENT_PLAY_COMMAND, 40000);
- if (pInstance)
- pInstance->SetData(EVENT_RAZUVIOUS, IN_PROGRESS);
summons.DoZoneInCombat();
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
index d0b8bb5d15..2514682c95 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
@@ -77,9 +77,9 @@ public:
return new boss_sapphironAI (pCreature);
}
- struct boss_sapphironAI : public ScriptedAI
+ struct boss_sapphironAI : public BossAI
{
- boss_sapphironAI(Creature* c) : ScriptedAI(c)
+ boss_sapphironAI(Creature* c) : BossAI(c, BOSS_SAPPHIRON)
{
pInstance = me->GetInstanceScript();
}
@@ -113,6 +113,7 @@ public:
void Reset()
{
+ BossAI::Reset();
if (me->IsVisible())
me->SetReactState(REACT_AGGRESSIVE);
@@ -121,9 +122,6 @@ public:
spawnTimer = 0;
currentTarget = 0;
blockList.clear();
-
- if (pInstance)
- pInstance->SetData(EVENT_SAPPHIRON, NOT_STARTED);
}
void EnterCombatSelfFunction()
@@ -147,8 +145,9 @@ public:
}
}
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
EnterCombatSelfFunction();
me->CastSpell(me, RAID_MODE(SPELL_FROST_AURA_10, SPELL_FROST_AURA_25), true);
@@ -159,16 +158,12 @@ public:
events.ScheduleEvent(EVENT_SPELL_BLIZZARD, 21000);
events.ScheduleEvent(EVENT_FLIGHT_START, 45000);
events.ScheduleEvent(EVENT_HUNDRED_CLUB, 5000);
-
- if (pInstance)
- pInstance->SetData(EVENT_SAPPHIRON, IN_PROGRESS);
}
- void JustDied(Unit* /*who*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
me->CastSpell(me, SPELL_SAPPHIRON_DIES, true);
- if (pInstance)
- pInstance->SetData(EVENT_SAPPHIRON, DONE);
}
void DoAction(int32 param)
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
index 0e5648f779..51e8f5b6ca 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
@@ -94,9 +94,9 @@ public:
return new boss_thaddiusAI (pCreature);
}
- struct boss_thaddiusAI : public ScriptedAI
+ struct boss_thaddiusAI : public BossAI
{
- boss_thaddiusAI(Creature *c) : ScriptedAI(c), summons(me)
+ boss_thaddiusAI(Creature *c) : BossAI(c, BOSS_THADDIUS), summons(me)
{
pInstance = me->GetInstanceScript();
}
@@ -139,8 +139,9 @@ public:
}
}
- void Reset()
+ void Reset()
{
+ BossAI::Reset();
events.Reset();
summons.DespawnAll();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
@@ -149,9 +150,6 @@ public:
resetTimer = 1;
me->SetPosition(me->GetHomePosition());
- if (pInstance)
- pInstance->SetData(EVENT_THADDIUS, NOT_STARTED);
-
me->SummonCreature(NPC_STALAGG, 3450.45f, -2931.42f, 312.091f, 5.49779f);
me->SummonCreature(NPC_FEUGEN, 3508.14f, -2988.65f, 312.092f, 2.37365f);
if (Creature* cr = me->SummonCreature(NPC_TESLA_COIL, 3527.34f, -2951.56f, 318.75f, 0.0f))
@@ -182,12 +180,12 @@ public:
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
- void JustDied(Unit* /*Killer*/)
+ void JustDied(Unit* killer)
{
+ BossAI::JustDied(killer);
Talk(SAY_DEATH);
if (pInstance)
{
- pInstance->SetData(EVENT_THADDIUS, DONE);
pInstance->DoRemoveAurasDueToSpellOnPlayers(28059);
pInstance->DoRemoveAurasDueToSpellOnPlayers(28084);
}
@@ -195,14 +193,12 @@ public:
void JustSummoned(Creature* cr) { summons.Summon(cr); }
- void EnterCombat(Unit * /*who*/)
+ void EnterCombat(Unit * who)
{
+ BossAI::EnterCombat(who);
me->SetInCombatWithZone();
summons.DoZoneInCombat(NPC_FEUGEN);
summons.DoZoneInCombat(NPC_STALAGG);
-
- if (pInstance)
- pInstance->SetData(EVENT_THADDIUS, IN_PROGRESS);
}
void UpdateAI(uint32 diff)
diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
index d9017164cd..93db29caea 100644
--- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
@@ -49,7 +49,7 @@ public:
{
instance_naxxramas_InstanceMapScript(Map* pMap) : InstanceScript(pMap)
{
- memset(&Encounters, 0, sizeof(Encounters));
+ SetBossNumber(MAX_ENCOUNTERS);
for (uint8 i = 0; i < 4; ++i)
HeiganEruption[i].clear();
@@ -101,7 +101,6 @@ public:
immortalAchievement = 1;
}
- uint32 Encounters[MAX_ENCOUNTERS];
std::set<GameObject*> HeiganEruption[4];
// GOs
@@ -169,17 +168,17 @@ public:
}
}
- bool IsEncounterInProgress() const
+ bool IsEncounterInProgress() const override
{
for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i)
{
- if (Encounters[i] == IN_PROGRESS)
+ if (GetBossState(i) == IN_PROGRESS)
return true;
}
return false;
}
- void OnCreatureCreate(Creature* creature)
+ void OnCreatureCreate(Creature* creature) override
{
switch(creature->GetEntry())
{
@@ -216,7 +215,7 @@ public:
}
}
- void OnGameObjectCreate(GameObject* pGo)
+ void OnGameObjectCreate(GameObject* pGo) override
{
if (pGo->GetGOInfo()->displayId == 6785 || pGo->GetGOInfo()->displayId == 1287)
{
@@ -228,57 +227,57 @@ public:
{
case GO_PATCHWERK_GATE:
_patchwerkGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_PATCHWERK] == DONE)
+ if (GetBossState(BOSS_PATCHWERK) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_GLUTH_GATE:
_gluthGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_GLUTH] == DONE)
+ if (GetBossState(BOSS_GLUTH) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_NOTH_GATE:
_nothGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_NOTH] == DONE)
+ if (GetBossState(BOSS_NOTH) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_HEIGAN_ENTERANCE_GATE:
_heiganGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_HEIGAN] == DONE || Encounters[EVENT_NOTH] == DONE)
+ if (GetBossState(BOSS_HEIGAN) == DONE || GetBossState(BOSS_NOTH) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_HEIGAN_EXIT_GATE:
_heiganGateExitGUID = pGo->GetGUID();
- if (Encounters[EVENT_HEIGAN] == DONE)
+ if (GetBossState(BOSS_HEIGAN) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_LOATHEB_GATE:
_loathebGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_LOATHEB] == DONE)
+ if (GetBossState(BOSS_LOATHEB) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_ANUB_GATE:
_anubGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_ANUB] == DONE)
+ if (GetBossState(BOSS_ANUB) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_ANUB_NEXT_GATE:
_anubNextGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_ANUB] == DONE)
+ if (GetBossState(BOSS_ANUB) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_FAERLINA_GATE:
_faerlinaGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_FAERLINA] == DONE)
+ if (GetBossState(BOSS_FAERLINA) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_MAEXXNA_GATE:
_maexxnaGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_FAERLINA] == DONE) // faerlina is correct
+ if (GetBossState(BOSS_FAERLINA) == DONE) // faerlina is correct
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_THADDIUS_GATE:
_thaddiusGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_GLUTH] == DONE) // gluth is correct
+ if (GetBossState(BOSS_GLUTH) == DONE) // gluth is correct
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_GOTHIK_ENTER_GATE:
@@ -289,12 +288,12 @@ public:
break;
case GO_GOTHIK_EXIT_GATE:
_gothikExitGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_GOTHIK] == DONE)
+ if (GetBossState(BOSS_GOTHIK) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_HORSEMAN_GATE:
_horsemanGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_GOTHIK] == DONE) // correct
+ if (GetBossState(BOSS_GOTHIK) == DONE) // correct
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_KELTHUZAD_FLOOR:
@@ -305,33 +304,33 @@ public:
break;
case GO_SAPPHIRON_GATE:
_sapphironGateGUID = pGo->GetGUID();
- if (Encounters[EVENT_SAPPHIRON] == DONE)
+ if (GetBossState(BOSS_SAPPHIRON) == DONE)
pGo->SetGoState(GO_STATE_ACTIVE);
break;
case GO_DEATHKNIGHT_WING:
_loathebPortalGUID = pGo->GetGUID();
- if (Encounters[EVENT_LOATHEB] == DONE)
+ if (GetBossState(BOSS_LOATHEB) == DONE)
pGo->SetPhaseMask(1, true);
break;
case GO_THADDIUS_PORTAL:
_thaddiusPortalGUID = pGo->GetGUID();
- if (Encounters[EVENT_THADDIUS] == DONE)
+ if (GetBossState(BOSS_THADDIUS) == DONE)
pGo->SetPhaseMask(1, true);
break;
case GO_MAEXXNA_PORTAL:
_maexxnaPortalGUID = pGo->GetGUID();
- if (Encounters[EVENT_MAEXXNA] == DONE)
+ if (GetBossState(BOSS_MAEXXNA) == DONE)
pGo->SetPhaseMask(1, true);
break;
case GO_HORSEMAN_PORTAL:
_horsemanPortalGUID = pGo->GetGUID();
- if (Encounters[EVENT_HORSEMAN] == DONE)
+ if (GetBossState(BOSS_HORSEMAN) == DONE)
pGo->SetPhaseMask(1, true);
break;
}
}
- void OnGameObjectRemove(GameObject* pGo)
+ void OnGameObjectRemove(GameObject* pGo) override
{
if (pGo->GetGOInfo()->displayId == 6785 || pGo->GetGOInfo()->displayId == 1287)
{
@@ -345,7 +344,7 @@ public:
cr->AI()->DoAction(ACTION_SAPPHIRON_BIRTH);
}
- bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/)
+ bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override
{
switch(criteria_id)
{
@@ -389,7 +388,7 @@ public:
{
uint8 count = 0;
for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i)
- if (Encounters[i] == NOT_STARTED)
+ if (GetBossState(i) == NOT_STARTED)
++count;
return !count && immortalAchievement;
@@ -398,57 +397,10 @@ public:
return false;
}
- void SetData(uint32 id, uint32 data)
+ void SetData(uint32 id, uint32 data) override
{
- // Bosses data
switch(id)
{
- case EVENT_PATCHWERK:
- case EVENT_GROBBULUS:
- case EVENT_GLUTH:
- case EVENT_NOTH:
- case EVENT_ANUB:
- case EVENT_MAEXXNA:
- case EVENT_RAZUVIOUS:
- case EVENT_GOTHIK:
- // EVENT_HORSEMAN HANDLED BELOW
- Encounters[id] = data;
- break;
- case EVENT_KELTHUZAD:
- if (data == NOT_STARTED)
- abominationsKilled = 0;
- Encounters[id] = data;
- break;
- case EVENT_FAERLINA:
- if (data == NOT_STARTED)
- faerlinaAchievement = true;
- Encounters[id] = data;
- break;
- case EVENT_THADDIUS:
- if (data == NOT_STARTED)
- thaddiusAchievement = true;
- Encounters[id] = data;
- break;
- case EVENT_LOATHEB:
- if (data == NOT_STARTED)
- loathebAchievement = true;
- Encounters[id] = data;
- break;
- case EVENT_HEIGAN:
- if (data == NOT_STARTED)
- heiganAchievement = true;
- Encounters[id] = data;
- break;
- case DATA_HEIGAN_ERUPTION:
- HeiganEruptSections(data);
- return;
- case EVENT_SAPPHIRON:
- Encounters[id] = data;
- if (data == DONE)
- _speakTimer = 1;
- else if (data == NOT_STARTED)
- sapphironAchievement = true;
- break;
case DATA_ABOMINATION_KILLED:
abominationsKilled++;
return;
@@ -471,17 +423,24 @@ public:
immortalAchievement = 0;
SaveToDB();
return;
+ case DATA_HEIGAN_ERUPTION:
+ HeiganEruptSections(data);
+ return;
}
-
+ }
+
+ bool SetBossState(uint32 bossId, EncounterState state) override
+ {
// Horseman handling
- if (id == EVENT_HORSEMAN)
+ if (bossId == BOSS_HORSEMAN)
{
- if (data == DONE)
+ if (state == DONE)
{
_horsemanTimer++;
_horsemanKilled++;
- if (_horsemanKilled < 4)
- return;
+ if (_horsemanKilled < 4) {
+ return false;
+ }
// All horsemans are killed
if (Creature* cr = instance->GetCreature(_blaumeuxGUID))
@@ -489,7 +448,7 @@ public:
}
// respawn
- else if (data == NOT_STARTED && _horsemanKilled > 0)
+ else if (state == NOT_STARTED && _horsemanKilled > 0)
{
Creature* cr;
_horsemanKilled = 0;
@@ -518,7 +477,7 @@ public:
cr->Respawn();
}
}
- else if (data == IN_PROGRESS)
+ else if (state == IN_PROGRESS)
{
Creature* cr;
if ((cr = instance->GetCreature(_blaumeuxGUID)))
@@ -531,66 +490,99 @@ public:
cr->SetInCombatWithZone();
}
- if (data == NOT_STARTED)
+ if (state == NOT_STARTED)
_horsemanTimer = 0;
-
- Encounters[id] = data;
}
-
+
+
+ if (!InstanceScript::SetBossState(bossId, state))
+ return false;
+
+ // Bosses data
+ switch(bossId)
+ {
+ case BOSS_KELTHUZAD:
+ if (state == NOT_STARTED)
+ abominationsKilled = 0;
+ break;
+ case BOSS_FAERLINA:
+ if (state == NOT_STARTED)
+ faerlinaAchievement = true;
+ break;
+ case BOSS_THADDIUS:
+ if (state == NOT_STARTED)
+ thaddiusAchievement = true;
+ break;
+ case BOSS_LOATHEB:
+ if (state == NOT_STARTED)
+ loathebAchievement = true;
+ break;
+ case BOSS_HEIGAN:
+ if (state == NOT_STARTED)
+ heiganAchievement = true;
+ break;
+ case BOSS_SAPPHIRON:
+ if (state == DONE)
+ _speakTimer = 1;
+ else if (state == NOT_STARTED)
+ sapphironAchievement = true;
+ break;
+ }
+
// Save instance and open gates
- if (data == DONE)
+ if (state == DONE)
{
SaveToDB();
- switch (id)
+ switch (bossId)
{
- case EVENT_PATCHWERK:
+ case BOSS_PATCHWERK:
if (GameObject* go = instance->GetGameObject(_patchwerkGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
break;
- case EVENT_GLUTH:
+ case BOSS_GLUTH:
if (GameObject* go = instance->GetGameObject(_gluthGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = instance->GetGameObject(_thaddiusGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
break;
- case EVENT_NOTH:
+ case BOSS_NOTH:
if (GameObject* go = instance->GetGameObject(_nothGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = instance->GetGameObject(_heiganGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
break;
- case EVENT_HEIGAN:
+ case BOSS_HEIGAN:
if (GameObject* go = instance->GetGameObject(_heiganGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = instance->GetGameObject(_heiganGateExitGUID))
go->SetGoState(GO_STATE_ACTIVE);
break;
- case EVENT_LOATHEB:
+ case BOSS_LOATHEB:
if (GameObject* go = instance->GetGameObject(_loathebGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = instance->GetGameObject(_loathebPortalGUID))
go->SetPhaseMask(1, true);
break;
- case EVENT_ANUB:
+ case BOSS_ANUB:
if (GameObject* go = instance->GetGameObject(_anubGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = instance->GetGameObject(_anubNextGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
break;
- case EVENT_FAERLINA:
+ case BOSS_FAERLINA:
if (GameObject* go = instance->GetGameObject(_faerlinaGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = instance->GetGameObject(_maexxnaGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
break;
- case EVENT_MAEXXNA:
+ case BOSS_MAEXXNA:
if (GameObject* go = instance->GetGameObject(_maexxnaGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = instance->GetGameObject(_maexxnaPortalGUID))
go->SetPhaseMask(1, true);
break;
- case EVENT_GOTHIK:
+ case BOSS_GOTHIK:
if (GameObject* go = instance->GetGameObject(_gothikEnterGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
if (GameObject* go = instance->GetGameObject(_gothikExitGateGUID))
@@ -598,33 +590,25 @@ public:
if (GameObject* go = instance->GetGameObject(_horsemanGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
break;
- case EVENT_SAPPHIRON:
+ case BOSS_SAPPHIRON:
if (GameObject* go = instance->GetGameObject(_sapphironGateGUID))
go->SetGoState(GO_STATE_ACTIVE);
break;
- case EVENT_THADDIUS:
+ case BOSS_THADDIUS:
if (GameObject* go = instance->GetGameObject(_thaddiusPortalGUID))
go->SetPhaseMask(1, true);
break;
- case EVENT_HORSEMAN:
+ case BOSS_HORSEMAN:
if (GameObject* go = instance->GetGameObject(_horsemanPortalGUID))
go->SetPhaseMask(1, true);
break;
}
}
+
+ return true;
}
- uint32 GetData(uint32 identifier) const
- {
- switch(identifier)
- {
- case EVENT_HORSEMAN:
- return Encounters[identifier];
- }
- return 0;
- }
-
- void Update(uint32 diff)
+ void Update(uint32 diff) override
{
if (_speakTimer)
{
@@ -666,7 +650,7 @@ public:
_horsemanTimer += diff;
}
- uint64 GetData64(uint32 id) const
+ uint64 GetData64(uint32 id) const override
{
switch (id)
{
@@ -703,21 +687,18 @@ public:
return 0;
}
- std::string GetSaveData()
+ std::string GetSaveData() override
{
OUT_SAVE_INST_DATA;
std::ostringstream saveStream;
- saveStream << "N X X " << Encounters[0] << ' ' << Encounters[1] << ' ' << Encounters[2] << ' ' << Encounters[3]
- << ' ' << Encounters[4] << ' ' << Encounters[5] << ' ' << Encounters[6] << ' ' << Encounters[7]
- << ' ' << Encounters[8] << ' ' << Encounters[9] << ' ' << Encounters[10] << ' ' << Encounters[11]
- << ' ' << Encounters[12] << ' ' << Encounters[13] << ' ' << Encounters[14] << ' ' << immortalAchievement;
+ saveStream << "N X X " << GetBossSaveData() << ' ' << immortalAchievement;
OUT_SAVE_INST_DATA_COMPLETE;
return saveStream.str();
}
- void Load(const char* in)
+ void Load(const char* in) override
{
if (!in)
{
@@ -735,9 +716,12 @@ public:
{
for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i)
{
- loadStream >> Encounters[i];
- if (Encounters[i] == IN_PROGRESS)
- Encounters[i] = NOT_STARTED;
+ uint32 tmpState;
+ loadStream >> tmpState;
+ if (tmpState == IN_PROGRESS)
+ tmpState = NOT_STARTED;
+
+ SetBossState(i, EncounterState(tmpState));
}
loadStream >> immortalAchievement;
diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
index 10bce8cbb1..25a1bed6d4 100644
--- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h
+++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
@@ -7,23 +7,23 @@
#include "ScriptPCH.h"
-enum NXEncounter
+enum Encouters
{
- EVENT_PATCHWERK = 0,
- EVENT_GROBBULUS = 1,
- EVENT_GLUTH = 2,
- EVENT_NOTH = 3,
- EVENT_HEIGAN = 4,
- EVENT_LOATHEB = 5,
- EVENT_ANUB = 6,
- EVENT_FAERLINA = 7,
- EVENT_MAEXXNA = 8,
- EVENT_THADDIUS = 9,
- EVENT_RAZUVIOUS = 10,
- EVENT_GOTHIK = 11,
- EVENT_HORSEMAN = 12,
- EVENT_SAPPHIRON = 13,
- EVENT_KELTHUZAD = 14,
+ BOSS_PATCHWERK = 0,
+ BOSS_GROBBULUS = 1,
+ BOSS_GLUTH = 2,
+ BOSS_NOTH = 3,
+ BOSS_HEIGAN = 4,
+ BOSS_LOATHEB = 5,
+ BOSS_ANUB = 6,
+ BOSS_FAERLINA = 7,
+ BOSS_MAEXXNA = 8,
+ BOSS_THADDIUS = 9,
+ BOSS_RAZUVIOUS = 10,
+ BOSS_GOTHIK = 11,
+ BOSS_HORSEMAN = 12,
+ BOSS_SAPPHIRON = 13,
+ BOSS_KELTHUZAD = 14,
MAX_ENCOUNTERS,
};
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index a88a56359b..50db4397db 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -1264,6 +1264,108 @@ public:
};
+enum BloodsporeRuination
+{
+ NPC_BLOODMAGE_LAURITH = 25381,
+ SAY_BLOODMAGE_LAURITH = 0,
+ EVENT_TALK = 1,
+ EVENT_RESET_ORIENTATION
+};
+
+class spell_q11719_bloodspore_ruination_45997 : public SpellScriptLoader
+{
+public:
+ spell_q11719_bloodspore_ruination_45997() : SpellScriptLoader("spell_q11719_bloodspore_ruination_45997") { }
+
+ class spell_q11719_bloodspore_ruination_45997_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_q11719_bloodspore_ruination_45997_SpellScript);
+
+ void HandleEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (Creature* laurith = caster->FindNearestCreature(NPC_BLOODMAGE_LAURITH, 100.0f))
+ laurith->AI()->SetGUID(caster->GetGUID());
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_q11719_bloodspore_ruination_45997_SpellScript::HandleEffect, EFFECT_1, SPELL_EFFECT_SEND_EVENT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_q11719_bloodspore_ruination_45997_SpellScript();
+ }
+};
+
+class npc_bloodmage_laurith : public CreatureScript
+{
+public:
+ npc_bloodmage_laurith() : CreatureScript("npc_bloodmage_laurith") { }
+
+ struct npc_bloodmage_laurithAI : public ScriptedAI
+ {
+ npc_bloodmage_laurithAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void Reset() override
+ {
+ _events.Reset();
+ _playerGUID = 0;
+ }
+
+ void SetGUID(uint64 guid, int32 /*action*/) override
+ {
+ if (_playerGUID)
+ return;
+
+ _playerGUID = guid;
+
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID))
+ me->SetFacingToObject(player);
+
+ _events.ScheduleEvent(EVENT_TALK, 1000);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (UpdateVictim())
+ {
+ DoMeleeAttackIfReady();
+ return;
+ }
+
+ _events.Update(diff);
+
+ if (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_TALK:
+ if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID))
+ Talk(SAY_BLOODMAGE_LAURITH, player);
+ _playerGUID = 0;
+ _events.ScheduleEvent(EVENT_RESET_ORIENTATION, 5000);
+ break;
+ case EVENT_RESET_ORIENTATION:
+ me->SetFacingTo(me->GetHomePosition().GetOrientation());
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap _events;
+ uint64 _playerGUID;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_bloodmage_laurithAI(creature);
+ }
+};
+
void AddSC_borean_tundra()
{
// Ours
@@ -1283,4 +1385,6 @@ void AddSC_borean_tundra()
new npc_valiance_keep_cannoneer();
new npc_warmage_coldarra();
new npc_hidden_cultist();
+ new spell_q11719_bloodspore_ruination_45997();
+ new npc_bloodmage_laurith();
}
diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp
index 367b5231f1..140029352a 100644
--- a/src/server/scripts/Northrend/zone_dalaran.cpp
+++ b/src/server/scripts/Northrend/zone_dalaran.cpp
@@ -576,13 +576,15 @@ class npc_minigob_manabonk : public CreatureScript
events.ScheduleEvent(EVENT_BLINK, 3*IN_MILLISECONDS);
break;
case EVENT_BLINK:
+ {
DoCast(me, SPELL_IMPROVED_BLINK);
Position pos;
me->GetRandomNearPosition(pos, (urand(15, 40)));
me->GetMotionMaster()->MovePoint(0, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
- events.ScheduleEvent(EVENT_DESPAWN, 3*IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_DESPAWN, 3 * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_DESPAWN_VISUAL, 2.5*IN_MILLISECONDS);
break;
+ }
case EVENT_DESPAWN_VISUAL:
DoCast(me, SPELL_TELEPORT_VISUAL);
break;
diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp
index 0a9b095316..5297bbc4ce 100644
--- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp
@@ -104,11 +104,13 @@ class boss_mechano_lord_capacitus : public CreatureScript
events.ScheduleEvent(EVENT_REFLECTIVE_DAMAGE_SHIELD, 20000);
break;
case EVENT_SUMMON_NETHER_CHARGE:
+ {
Position pos;
me->GetRandomNearPosition(pos, 8.0f);
me->SummonCreature(NPC_NETHER_CHARGE, pos, TEMPSUMMON_TIMED_DESPAWN, 18000);
events.ScheduleEvent(EVENT_SUMMON_NETHER_CHARGE, 5000);
break;
+ }
case EVENT_POSITIVE_SHIFT:
me->CastSpell(me, SPELL_POLARITY_SHIFT, true);
events.ScheduleEvent(EVENT_POSITIVE_SHIFT, 30000);
diff --git a/src/server/scripts/Pet/pet_mage.cpp b/src/server/scripts/Pet/pet_mage.cpp
index a8089857b9..4642e9a131 100644
--- a/src/server/scripts/Pet/pet_mage.cpp
+++ b/src/server/scripts/Pet/pet_mage.cpp
@@ -52,6 +52,7 @@ class npc_pet_mage_mirror_image : public CreatureScript
uint32 selectionTimer;
uint64 _ebonGargoyleGUID;
+ uint32 checktarget;
void InitializeAI()
{
@@ -135,7 +136,7 @@ class npc_pet_mage_mirror_image : public CreatureScript
}
}
- bool MySelectNextTarget()
+ void MySelectNextTarget()
{
if (_ebonGargoyleGUID)
{
@@ -153,21 +154,27 @@ class npc_pet_mage_mirror_image : public CreatureScript
// target has cc, search target without cc!
if (selection->HasBreakableByDamageCrowdControlAura() || !me->IsValidAttackTarget(selection))
{
- return false;
+ EnterEvadeMode();
+ return;
}
me->getThreatManager().resetAllAggro();
me->AddThreat(selection, 1000000.0f);
- AttackStart(selection);
- return true;
+
+ if (owner->IsInCombat())
+ AttackStart(selection);
+
}
}
- return false;
+
+ if (!me->GetVictim() || !me->GetVictim()->IsAlive())
+ return;
}
void Reset()
{
selectionTimer = 0;
+ checktarget = 0;
}
void UpdateAI(uint32 diff)
@@ -182,12 +189,15 @@ class npc_pet_mage_mirror_image : public CreatureScript
return;
}
- if (me->GetVictim()->HasBreakableByDamageCrowdControlAura() || !me->GetVictim()->IsAlive())
+ checktarget += diff;
+ if (checktarget >= 1000)
{
- me->InterruptNonMeleeSpells(false);
- if (!MySelectNextTarget())
- EnterEvadeMode();
- return;
+ if (me->GetVictim()->HasBreakableByDamageCrowdControlAura() || !me->GetVictim()->IsAlive())
+ {
+ MySelectNextTarget();
+ me->InterruptNonMeleeSpells(true); // Stop casting if target is C or not Alive.
+ return;
+ }
}
selectionTimer += diff;
diff --git a/src/server/scripts/ScriptLoader.cpp b/src/server/scripts/ScriptLoader.cpp
index d948a18c55..a5e9f710e9 100644
--- a/src/server/scripts/ScriptLoader.cpp
+++ b/src/server/scripts/ScriptLoader.cpp
@@ -46,6 +46,7 @@ void AddSC_list_commandscript();
void AddSC_lookup_commandscript();
void AddSC_message_commandscript();
void AddSC_misc_commandscript();
+void AddSC_mmaps_commandscript();
void AddSC_modify_commandscript();
void AddSC_npc_commandscript();
void AddSC_quest_commandscript();
@@ -616,6 +617,7 @@ void AddCommandScripts()
AddSC_lookup_commandscript();
AddSC_message_commandscript();
AddSC_misc_commandscript();
+ AddSC_mmaps_commandscript();
AddSC_modify_commandscript();
AddSC_npc_commandscript();
AddSC_quest_commandscript();
@@ -1169,3 +1171,15 @@ void AddOutdoorPvPScripts()
#endif
}
+
+//~ ********************** Put your custom scripts below, like the commented examples, uncomment and edit *************************************
+
+
+//~ void AddSC_MySuperScript();
+
+void AddCustomScripts()
+{
+#ifdef SCRIPTS
+ //~ AddSC_MySuperScript();
+#endif
+}
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index fbbbbbe15a..27263233f8 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -1545,12 +1545,16 @@ class spell_dk_death_grip : public SpellScriptLoader
{
PrepareSpellScript(spell_dk_death_grip_SpellScript);
- SpellCastResult CheckPvPRange()
+ SpellCastResult CheckCast()
{
Unit* caster = GetCaster();
- if (Unit* target = GetExplTargetUnit())
- if (target->GetTypeId() == TYPEID_PLAYER && caster->GetExactDist(target) < 8.0f) // xinef: should be 8.0f, but we have to add target size (1.5f)
- return SPELL_FAILED_TOO_CLOSE;
+ Unit* target = GetExplTargetUnit();
+
+ if (target->GetTypeId() == TYPEID_PLAYER && caster->GetExactDist(target) < 8.0f) // xinef: should be 8.0f, but we have to add target size (1.5f)
+ return SPELL_FAILED_TOO_CLOSE;
+
+ if (caster->HasUnitState(UNIT_STATE_JUMPING) || caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING))
+ return SPELL_FAILED_MOVING;
return SPELL_CAST_OK;
}
@@ -1560,9 +1564,22 @@ class spell_dk_death_grip : public SpellScriptLoader
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
Unit* baseTarget = GetExplTargetUnit();
+ Creature* targetCreature = GetHitCreature();
if (caster != target)
- caster->CastSpell(target, 49560, true);
+ {
+ if (targetCreature && (targetCreature->isWorldBoss() || targetCreature->IsDungeonBoss()))
+ {
+ return;
+ }
+ else
+ {
+ caster->CastSpell(target, 49560, true);
+ const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(1766); // Rogue kick
+ if (!target->IsImmunedToSpellEffect(spellInfo, EFFECT_0))
+ target->InterruptNonMeleeSpells(true);
+ }
+ }
else
baseTarget->CastSpell(caster, 49560, true);
}
@@ -1592,7 +1609,7 @@ class spell_dk_death_grip : public SpellScriptLoader
{
if (m_scriptSpellId == 49576) // xinef: base death grip, add pvp range restriction
{
- OnCheckCast += SpellCheckCastFn(spell_dk_death_grip_SpellScript::CheckPvPRange);
+ OnCheckCast += SpellCheckCastFn(spell_dk_death_grip_SpellScript::CheckCast);
OnEffectHitTarget += SpellEffectFn(spell_dk_death_grip_SpellScript::HandleBaseDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
else
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 4821e57555..f0ac73e39c 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -4431,10 +4431,7 @@ class spell_gen_mount : public SpellScriptLoader
if (map == 530 || (map == 571 && target->HasSpell(SPELL_COLD_WEATHER_FLYING)))
canFly = true;
- float x, y, z;
- target->GetPosition(x, y, z);
- uint32 areaFlag = target->GetBaseMap()->GetAreaFlag(x, y, z);
- AreaTableEntry const* area = sAreaStore.LookupEntry(areaFlag);
+ AreaTableEntry const* area = sAreaTableStore.LookupEntry(target->GetAreaId());
// Xinef: add battlefield check
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(target->GetZoneId());
if (!area || (canFly && ((area->flags & AREA_FLAG_NO_FLY_ZONE) || (Bf && !Bf->CanFlyIn()))))
diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp
index 2ea90c230c..45b3ac2640 100644
--- a/src/server/scripts/Spells/spell_warrior.cpp
+++ b/src/server/scripts/Spells/spell_warrior.cpp
@@ -592,7 +592,7 @@ class spell_warr_overpower : public SpellScriptLoader
if (Player* target = GetHitPlayer())
if (target->HasUnitState(UNIT_STATE_CASTING))
- target->CastSpell(target, spellId, true);
+ target->CastSpell(target, spellId, true, 0, 0, GetCaster()->GetGUID());
}
void Register()
diff --git a/src/server/scripts/World/achievement_scripts.cpp b/src/server/scripts/World/achievement_scripts.cpp
index a0a9f893b5..95c4db4801 100644
--- a/src/server/scripts/World/achievement_scripts.cpp
+++ b/src/server/scripts/World/achievement_scripts.cpp
@@ -112,10 +112,10 @@ class achievement_bg_sa_artillery : public AchievementCriteriaScript
}
};
-class achievement_arena_kills : public AchievementCriteriaScript
+class achievement_arena_by_type : public AchievementCriteriaScript
{
public:
- achievement_arena_kills(char const* name, uint8 arenaType) : AchievementCriteriaScript(name),
+ achievement_arena_by_type(char const* name, uint8 arenaType) : AchievementCriteriaScript(name),
_arenaType(arenaType)
{
}
@@ -129,7 +129,6 @@ class achievement_arena_kills : public AchievementCriteriaScript
uint8 const _arenaType;
};
-
class achievement_sickly_gazelle : public AchievementCriteriaScript
{
public:
@@ -254,9 +253,9 @@ void AddSC_achievement_scripts()
new achievement_sickly_gazelle();
new achievement_everything_counts();
new achievement_bg_av_perfection();
- new achievement_arena_kills("achievement_arena_2v2_kills", ARENA_TYPE_2v2);
- new achievement_arena_kills("achievement_arena_3v3_kills", ARENA_TYPE_3v3);
- new achievement_arena_kills("achievement_arena_5v5_kills", ARENA_TYPE_5v5);
+ new achievement_arena_by_type("achievement_arena_2v2_check", ARENA_TYPE_2v2);
+ new achievement_arena_by_type("achievement_arena_3v3_check", ARENA_TYPE_3v3);
+ new achievement_arena_by_type("achievement_arena_5v5_check", ARENA_TYPE_5v5);
new achievement_sa_defense_of_the_ancients();
new achievement_tilted();
new achievement_not_even_a_scratch();
diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt
index 58ec995c4e..fdc17078bc 100644
--- a/src/server/worldserver/CMakeLists.txt
+++ b/src/server/worldserver/CMakeLists.txt
@@ -44,7 +44,7 @@ endif()
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/deps/g3dlite/include
- ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/deps/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/deps/gsoap
${CMAKE_SOURCE_DIR}/deps/sockets/include
${CMAKE_SOURCE_DIR}/deps/SFMT
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 5ad7a5bc3b..66fa7fb615 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1434,16 +1434,6 @@ DeletedCharacterTicketTrace = 0
DungeonFinder.OptionsMask = 1
-
-#
-# DBC.EnforceItemAttributes
-# Description: Disallow overriding item attributes stored in DBC files with values from the
-# database.
-# Default: 1 - (Enabled, Enforce DBC values)
-# 0 - (Disabled, Use database values)
-
-DBC.EnforceItemAttributes = 1
-
#
# AccountInstancesPerHour
# Description: Controls the max amount of different instances player can enter within hour
diff --git a/src/tools/map_extractor/CMakeLists.txt b/src/tools/map_extractor/CMakeLists.txt
index 2c00a7e130..f127b496a1 100644
--- a/src/tools/map_extractor/CMakeLists.txt
+++ b/src/tools/map_extractor/CMakeLists.txt
@@ -12,8 +12,10 @@
file(GLOB_RECURSE sources *.cpp *.h)
set(include_Dirs
+ ${CMAKE_SOURCE_DIR}/src/common/Utilities
${CMAKE_SOURCE_DIR}/src/common
${CMAKE_SOURCE_DIR}/deps/libmpq
+ ${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/loadlib
)
diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp
index defab209d7..a22abb3ded 100644
--- a/src/tools/map_extractor/System.cpp
+++ b/src/tools/map_extractor/System.cpp
@@ -20,9 +20,12 @@
#include "dbcfile.h"
#include "mpq_libmpq04.h"
+#include "StringFormat.h"
#include "adt.h"
#include "wdt.h"
+
+#include "G3D/Plane.h"
#include <fcntl.h>
#if defined( __GNUC__ )
@@ -49,11 +52,10 @@ typedef struct
} map_id;
map_id *map_ids;
-uint16 *areas;
uint16 *LiqType;
-char output_path[128] = ".";
-char input_path[128] = ".";
-uint32 maxAreaId = 0;
+#define MAX_PATH_LENGTH 128
+char output_path[MAX_PATH_LENGTH] = ".";
+char input_path[MAX_PATH_LENGTH] = ".";
// **************************************************
// Extractor options
@@ -244,30 +246,6 @@ uint32 ReadMapDBC()
return map_count;
}
-void ReadAreaTableDBC()
-{
- printf("Read AreaTable.dbc file...");
- DBCFile dbc("DBFilesClient\\AreaTable.dbc");
-
- if(!dbc.open())
- {
- printf("Fatal error: Invalid AreaTable.dbc file format!\n");
- exit(1);
- }
-
- size_t area_count = dbc.getRecordCount();
- size_t maxid = dbc.getMaxId();
- areas = new uint16[maxid + 1];
- memset(areas, 0xff, (maxid + 1) * sizeof(uint16));
-
- for(uint32 x = 0; x < area_count; ++x)
- areas[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
-
- maxAreaId = dbc.getMaxId();
-
- printf("Done! (%u areas loaded)\n", (uint32)area_count);
-}
-
void ReadLiquidTypeTableDBC()
{
printf("Read LiquidType.dbc file...");
@@ -295,7 +273,7 @@ void ReadLiquidTypeTableDBC()
// Map file format data
static char const* MAP_MAGIC = "MAPS";
-static char const* MAP_VERSION_MAGIC = "v1.3";
+static char const* MAP_VERSION_MAGIC = "v1.8";
static char const* MAP_AREA_MAGIC = "AREA";
static char const* MAP_HEIGHT_MAGIC = "MHGT";
static char const* MAP_LIQUID_MAGIC = "MLIQ";
@@ -324,9 +302,10 @@ struct map_areaHeader
uint16 gridArea;
};
-#define MAP_HEIGHT_NO_HEIGHT 0x0001
-#define MAP_HEIGHT_AS_INT16 0x0002
-#define MAP_HEIGHT_AS_INT8 0x0004
+#define MAP_HEIGHT_NO_HEIGHT 0x0001
+#define MAP_HEIGHT_AS_INT16 0x0002
+#define MAP_HEIGHT_AS_INT8 0x0004
+#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
struct map_heightHeader
{
@@ -371,7 +350,7 @@ float selectUInt16StepStore(float maxDiff)
return 65535 / maxDiff;
}
// Temporary grid data store
-uint16 area_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
+uint16 area_ids[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
float V8[ADT_GRID_SIZE][ADT_GRID_SIZE];
float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
@@ -385,17 +364,20 @@ uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE];
float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
-bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, uint32 build)
+int16 flight_box_max[3][3];
+int16 flight_box_min[3][3];
+
+bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int /*cell_y*/, int /*cell_x*/, uint32 build)
{
ADT_file adt;
- if (!adt.loadFile(filename))
+ if (!adt.loadFile(inputPath))
return false;
adt_MCIN *cells = adt.a_grid->getMCIN();
if (!cells)
{
- printf("Can't find cells in '%s'\n", filename);
+ printf("Can't find cells in '%s'\n", inputPath.c_str());
return false;
}
@@ -405,39 +387,25 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
// Prepare map header
map_fileheader map;
- map.mapMagic = *(uint32 const*)MAP_MAGIC;
- map.versionMagic = *(uint32 const*)MAP_VERSION_MAGIC;
+ map.mapMagic = *reinterpret_cast<uint32 const*>(MAP_MAGIC);
+ map.versionMagic = *reinterpret_cast<uint32 const*>(MAP_VERSION_MAGIC);
map.buildMagic = build;
// Get area flags data
- for (int i=0;i<ADT_CELLS_PER_GRID;i++)
- {
- for(int j=0;j<ADT_CELLS_PER_GRID;j++)
- {
- adt_MCNK * cell = cells->getMCNK(i,j);
- uint32 areaid = cell->areaid;
- if(areaid && areaid <= maxAreaId)
- {
- if(areas[areaid] != 0xffff)
- {
- area_flags[i][j] = areas[areaid];
- continue;
- }
- printf("File: %s\nCan't find area flag for areaid %u [%d, %d].\n", filename, areaid, cell->ix, cell->iy);
- }
- area_flags[i][j] = 0xffff;
- }
- }
+ for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
+ for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
+ area_ids[i][j] = cells->getMCNK(i, j)->areaid;
+
//============================================
// Try pack area data
//============================================
bool fullAreaData = false;
- uint32 areaflag = area_flags[0][0];
- for (int y=0;y<ADT_CELLS_PER_GRID;y++)
+ uint32 areaId = area_ids[0][0];
+ for (int y = 0; y < ADT_CELLS_PER_GRID; ++y)
{
- for(int x=0;x<ADT_CELLS_PER_GRID;x++)
+ for (int x = 0; x < ADT_CELLS_PER_GRID; ++x)
{
- if(area_flags[y][x]!=areaflag)
+ if (area_ids[y][x] != areaId)
{
fullAreaData = true;
break;
@@ -449,27 +417,27 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
map.areaMapSize = sizeof(map_areaHeader);
map_areaHeader areaHeader;
- areaHeader.fourcc = *(uint32 const*)MAP_AREA_MAGIC;
+ areaHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_AREA_MAGIC);
areaHeader.flags = 0;
if (fullAreaData)
{
areaHeader.gridArea = 0;
- map.areaMapSize+=sizeof(area_flags);
+ map.areaMapSize += sizeof(area_ids);
}
else
{
areaHeader.flags |= MAP_AREA_NO_AREA;
- areaHeader.gridArea = (uint16)areaflag;
+ areaHeader.gridArea = static_cast<uint16>(areaId);
}
//
// Get Height map from grid
//
- for (int i=0;i<ADT_CELLS_PER_GRID;i++)
+ for (int i = 0; i<ADT_CELLS_PER_GRID; i++)
{
- for(int j=0;j<ADT_CELLS_PER_GRID;j++)
+ for (int j = 0; j<ADT_CELLS_PER_GRID; j++)
{
- adt_MCNK * cell = cells->getMCNK(i,j);
+ adt_MCNK * cell = cells->getMCNK(i, j);
if (!cell)
continue;
// Height values for triangles stored in order:
@@ -489,22 +457,22 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
// . . . . . . . .
// Set map height as grid height
- for (int y=0; y <= ADT_CELL_SIZE; y++)
+ for (int y = 0; y <= ADT_CELL_SIZE; y++)
{
int cy = i*ADT_CELL_SIZE + y;
- for (int x=0; x <= ADT_CELL_SIZE; x++)
+ for (int x = 0; x <= ADT_CELL_SIZE; x++)
{
int cx = j*ADT_CELL_SIZE + x;
- V9[cy][cx]=cell->ypos;
+ V9[cy][cx] = cell->ypos;
}
}
- for (int y=0; y < ADT_CELL_SIZE; y++)
+ for (int y = 0; y < ADT_CELL_SIZE; y++)
{
int cy = i*ADT_CELL_SIZE + y;
- for (int x=0; x < ADT_CELL_SIZE; x++)
+ for (int x = 0; x < ADT_CELL_SIZE; x++)
{
int cx = j*ADT_CELL_SIZE + x;
- V8[cy][cx]=cell->ypos;
+ V8[cy][cx] = cell->ypos;
}
}
// Get custom height
@@ -512,23 +480,23 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
if (!v)
continue;
// get V9 height map
- for (int y=0; y <= ADT_CELL_SIZE; y++)
+ for (int y = 0; y <= ADT_CELL_SIZE; y++)
{
int cy = i*ADT_CELL_SIZE + y;
- for (int x=0; x <= ADT_CELL_SIZE; x++)
+ for (int x = 0; x <= ADT_CELL_SIZE; x++)
{
int cx = j*ADT_CELL_SIZE + x;
- V9[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+x];
+ V9[cy][cx] += v->height_map[y*(ADT_CELL_SIZE * 2 + 1) + x];
}
}
// get V8 height map
- for (int y=0; y < ADT_CELL_SIZE; y++)
+ for (int y = 0; y < ADT_CELL_SIZE; y++)
{
int cy = i*ADT_CELL_SIZE + y;
- for (int x=0; x < ADT_CELL_SIZE; x++)
+ for (int x = 0; x < ADT_CELL_SIZE; x++)
{
int cx = j*ADT_CELL_SIZE + x;
- V8[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+ADT_CELL_SIZE+1+x];
+ V8[cy][cx] += v->height_map[y*(ADT_CELL_SIZE * 2 + 1) + ADT_CELL_SIZE + 1 + x];
}
}
}
@@ -538,18 +506,18 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
//============================================
float maxHeight = -20000;
float minHeight = 20000;
- for (int y=0; y<ADT_GRID_SIZE; y++)
+ for (int y = 0; y<ADT_GRID_SIZE; y++)
{
- for(int x=0;x<ADT_GRID_SIZE;x++)
+ for (int x = 0; x<ADT_GRID_SIZE; x++)
{
float h = V8[y][x];
if (maxHeight < h) maxHeight = h;
if (minHeight > h) minHeight = h;
}
}
- for (int y=0; y<=ADT_GRID_SIZE; y++)
+ for (int y = 0; y <= ADT_GRID_SIZE; y++)
{
- for(int x=0;x<=ADT_GRID_SIZE;x++)
+ for(int x = 0; x<= ADT_GRID_SIZE; x++)
{
float h = V9[y][x];
if (maxHeight < h) maxHeight = h;
@@ -560,12 +528,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
// Check for allow limit minimum height (not store height in deep ochean - allow save some memory)
if (CONF_allow_height_limit && minHeight < CONF_use_minHeight)
{
- for (int y=0; y<ADT_GRID_SIZE; y++)
- for(int x=0;x<ADT_GRID_SIZE;x++)
+ for (int y = 0; y<ADT_GRID_SIZE; y++)
+ for (int x = 0; x<ADT_GRID_SIZE; x++)
if (V8[y][x] < CONF_use_minHeight)
V8[y][x] = CONF_use_minHeight;
- for (int y=0; y<=ADT_GRID_SIZE; y++)
- for(int x=0;x<=ADT_GRID_SIZE;x++)
+ for (int y = 0; y <= ADT_GRID_SIZE; y++)
+ for (int x = 0; x <= ADT_GRID_SIZE; x++)
if (V9[y][x] < CONF_use_minHeight)
V9[y][x] = CONF_use_minHeight;
if (minHeight < CONF_use_minHeight)
@@ -574,11 +542,19 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
maxHeight = CONF_use_minHeight;
}
+ bool hasFlightBox = false;
+ if (adt_MFBO* mfbo = adt.a_grid->getMFBO())
+ {
+ memcpy(flight_box_max, &mfbo->max, sizeof(flight_box_max));
+ memcpy(flight_box_min, &mfbo->min, sizeof(flight_box_min));
+ hasFlightBox = true;
+ }
+
map.heightMapOffset = map.areaMapOffset + map.areaMapSize;
map.heightMapSize = sizeof(map_heightHeader);
map_heightHeader heightHeader;
- heightHeader.fourcc = *(uint32 const*)MAP_HEIGHT_MAGIC;
+ heightHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_HEIGHT_MAGIC);
heightHeader.flags = 0;
heightHeader.gridHeight = minHeight;
heightHeader.gridMaxHeight = maxHeight;
@@ -589,6 +565,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
// Not need store if flat surface
if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit)
heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
+
+ if (hasFlightBox)
+ {
+ heightHeader.flags |= MAP_HEIGHT_HAS_FLIGHT_BOUNDS;
+ map.heightMapSize += sizeof(flight_box_max) + sizeof(flight_box_min);
+ }
// Try store as packed in uint16 or uint8 values
if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
@@ -600,12 +582,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
float diff = maxHeight - minHeight;
if (diff < CONF_float_to_int8_limit) // As uint8 (max accuracy = CONF_float_to_int8_limit/256)
{
- heightHeader.flags|=MAP_HEIGHT_AS_INT8;
+ heightHeader.flags |= MAP_HEIGHT_AS_INT8;
step = selectUInt8StepStore(diff);
}
else if (diff<CONF_float_to_int16_limit) // As uint16 (max accuracy = CONF_float_to_int16_limit/65536)
{
- heightHeader.flags|=MAP_HEIGHT_AS_INT16;
+ heightHeader.flags |= MAP_HEIGHT_AS_INT16;
step = selectUInt16StepStore(diff);
}
}
@@ -613,32 +595,32 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
// Pack it to int values if need
if (heightHeader.flags&MAP_HEIGHT_AS_INT8)
{
- for (int y=0; y<ADT_GRID_SIZE; y++)
- for(int x=0;x<ADT_GRID_SIZE;x++)
+ for (int y = 0; y<ADT_GRID_SIZE; y++)
+ for (int x = 0; x<ADT_GRID_SIZE; x++)
uint8_V8[y][x] = uint8((V8[y][x] - minHeight) * step + 0.5f);
- for (int y=0; y<=ADT_GRID_SIZE; y++)
- for(int x=0;x<=ADT_GRID_SIZE;x++)
+ for (int y = 0; y <= ADT_GRID_SIZE; y++)
+ for (int x = 0; x <= ADT_GRID_SIZE; x++)
uint8_V9[y][x] = uint8((V9[y][x] - minHeight) * step + 0.5f);
- map.heightMapSize+= sizeof(uint8_V9) + sizeof(uint8_V8);
+ map.heightMapSize += sizeof(uint8_V9) + sizeof(uint8_V8);
}
else if (heightHeader.flags&MAP_HEIGHT_AS_INT16)
{
- for (int y=0; y<ADT_GRID_SIZE; y++)
- for(int x=0;x<ADT_GRID_SIZE;x++)
+ for (int y = 0; y<ADT_GRID_SIZE; y++)
+ for (int x = 0; x<ADT_GRID_SIZE; x++)
uint16_V8[y][x] = uint16((V8[y][x] - minHeight) * step + 0.5f);
- for (int y=0; y<=ADT_GRID_SIZE; y++)
- for(int x=0;x<=ADT_GRID_SIZE;x++)
+ for (int y = 0; y <= ADT_GRID_SIZE; y++)
+ for (int x = 0; x <= ADT_GRID_SIZE; x++)
uint16_V9[y][x] = uint16((V9[y][x] - minHeight) * step + 0.5f);
- map.heightMapSize+= sizeof(uint16_V9) + sizeof(uint16_V8);
+ map.heightMapSize += sizeof(uint16_V9) + sizeof(uint16_V8);
}
else
- map.heightMapSize+= sizeof(V9) + sizeof(V8);
+ map.heightMapSize += sizeof(V9) + sizeof(V8);
}
// Get from MCLQ chunk (old)
for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
{
- for(int j = 0; j < ADT_CELLS_PER_GRID; j++)
+ for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
{
adt_MCNK *cell = cells->getMCNK(i, j);
if (!cell)
@@ -658,7 +640,7 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
if (liquid->flags[y][x] != 0x0F)
{
liquid_show[cy][cx] = true;
- if (liquid->flags[y][x] & (1<<7))
+ if (liquid->flags[y][x] & (1 << 7))
liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER;
++count;
}
@@ -666,17 +648,17 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
}
uint32 c_flag = cell->flags;
- if (c_flag & (1<<2))
+ if (c_flag & (1 << 2))
{
liquid_entry[i][j] = 1;
liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; // water
}
- if (c_flag & (1<<3))
+ if (c_flag & (1 << 3))
{
liquid_entry[i][j] = 2;
liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; // ocean
}
- if (c_flag & (1<<4))
+ if (c_flag & (1 << 4))
{
liquid_entry[i][j] = 3;
liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; // magma/slime
@@ -734,7 +716,7 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
case LIQUID_TYPE_MAGMA: liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; break;
case LIQUID_TYPE_SLIME: liquid_flags[i][j] |= MAP_LIQUID_TYPE_SLIME; break;
default:
- printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->liquidType, filename, i, j);
+ printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->liquidType, inputPath.c_str(), i, j);
break;
}
// Dark water detect
@@ -877,17 +859,17 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
map.holesSize = 0;
// Ok all data prepared - store it
- FILE* output = fopen(filename2, "wb");
+ FILE* output = fopen(outputPath.c_str(), "wb");
if (!output)
{
- printf("Can't create the output file '%s'\n", filename2);
+ printf("Can't create the output file '%s'\n", outputPath.c_str());
return false;
}
fwrite(&map, sizeof(map), 1, output);
// Store area data
fwrite(&areaHeader, sizeof(areaHeader), 1, output);
if (!(areaHeader.flags&MAP_AREA_NO_AREA))
- fwrite(area_flags, sizeof(area_flags), 1, output);
+ fwrite(area_ids, sizeof(area_ids), 1, output);
// Store height data
fwrite(&heightHeader, sizeof(heightHeader), 1, output);
@@ -910,6 +892,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
}
}
+ if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
+ {
+ fwrite(flight_box_max, sizeof(flight_box_max), 1, output);
+ fwrite(flight_box_min, sizeof(flight_box_min), 1, output);
+ }
+
// Store liquid data if need
if (map.liquidMapOffset)
{
@@ -937,15 +925,14 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
void ExtractMapsFromMpq(uint32 build)
{
- char mpq_filename[1024];
- char output_filename[1024];
- char mpq_map_name[1024];
+ std::string mpqFileName;
+ std::string outputFileName;
+ std::string mpqMapName;
printf("Extracting maps...\n");
uint32 map_count = ReadMapDBC();
- ReadAreaTableDBC();
ReadLiquidTypeTableDBC();
std::string path = output_path;
@@ -957,9 +944,9 @@ void ExtractMapsFromMpq(uint32 build)
{
printf("Extract %s (%d/%u) \n", map_ids[z].name, z+1, map_count);
// Loadup map grid data
- sprintf(mpq_map_name, "World\\Maps\\%s\\%s.wdt", map_ids[z].name, map_ids[z].name);
+ mpqMapName = Trinity::StringFormat("World\\Maps\\%s\\%s.wdt", map_ids[z].name, map_ids[z].name);
WDT_file wdt;
- if (!wdt.loadFile(mpq_map_name, false))
+ if (!wdt.loadFile(mpqMapName, false))
{
// printf("Error loading %s map wdt data\n", map_ids[z].name);
continue;
@@ -971,17 +958,16 @@ void ExtractMapsFromMpq(uint32 build)
{
if (!wdt.main->adt_list[y][x].exist)
continue;
- sprintf(mpq_filename, "World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y);
- sprintf(output_filename, "%s/maps/%03u%02u%02u.map", output_path, map_ids[z].id, y, x);
- ConvertADT(mpq_filename, output_filename, y, x, build);
+ mpqFileName = Trinity::StringFormat("World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y);
+ outputFileName = Trinity::StringFormat("%s/maps/%03u%02u%02u.map", output_path, map_ids[z].id, y, x);
+ ConvertADT(mpqFileName, outputFileName, y, x, build);
}
// draw progress bar
printf("Processing........................%d%%\r", (100 * (y+1)) / WDT_MAP_SIZE);
}
}
printf("\n");
- delete [] areas;
- delete [] map_ids;
+ delete[] map_ids;
}
bool ExtractFile( char const* mpq_name, std::string const& filename )
diff --git a/src/tools/map_extractor/adt.cpp b/src/tools/map_extractor/adt.cpp
index 574167c216..257d0171aa 100644
--- a/src/tools/map_extractor/adt.cpp
+++ b/src/tools/map_extractor/adt.cpp
@@ -9,15 +9,16 @@
#include "adt.h"
// Helper
-int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888};
-int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000};
+int holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
+int holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
-u_map_fcc MHDRMagic = { {'R','D','H','M'} };
-u_map_fcc MCINMagic = { {'N','I','C','M'} };
-u_map_fcc MH2OMagic = { {'O','2','H','M'} };
-u_map_fcc MCNKMagic = { {'K','N','C','M'} };
-u_map_fcc MCVTMagic = { {'T','V','C','M'} };
-u_map_fcc MCLQMagic = { {'Q','L','C','M'} };
+u_map_fcc MHDRMagic = { { 'R','D','H','M' } };
+u_map_fcc MCINMagic = { { 'N','I','C','M' } };
+u_map_fcc MH2OMagic = { { 'O','2','H','M' } };
+u_map_fcc MCNKMagic = { { 'K','N','C','M' } };
+u_map_fcc MCVTMagic = { { 'T','V','C','M' } };
+u_map_fcc MCLQMagic = { { 'Q','L','C','M' } };
+u_map_fcc MFBOMagic = { { 'O','B','F','M' } };
bool isHole(int holes, int i, int j)
{
@@ -69,7 +70,7 @@ bool adt_MHDR::prepareLoadedData()
if (fcc != MHDRMagic.fcc)
return false;
- if (size!=sizeof(adt_MHDR)-8)
+ if (size != sizeof(adt_MHDR) - 8)
return false;
// Check and prepare MCIN
@@ -80,6 +81,9 @@ bool adt_MHDR::prepareLoadedData()
if (offsMH2O && !getMH2O()->prepareLoadedData())
return false;
+ if (offsMFBO && flags & 1 && !getMFBO()->prepareLoadedData())
+ return false;
+
return true;
}
@@ -142,3 +146,8 @@ bool adt_MCLQ::prepareLoadedData()
return true;
}
+
+bool adt_MFBO::prepareLoadedData()
+{
+ return fcc == MFBOMagic.fcc;
+}
diff --git a/src/tools/map_extractor/adt.h b/src/tools/map_extractor/adt.h
index 71e83cd999..94b830c4ef 100644
--- a/src/tools/map_extractor/adt.h
+++ b/src/tools/map_extractor/adt.h
@@ -248,6 +248,27 @@ public:
};
+// Adt file min/max height chunk
+//
+class adt_MFBO
+{
+ union
+ {
+ uint32 fcc;
+ char fcc_txt[4];
+ };
+public:
+ uint32 size;
+ struct plane
+ {
+ int16 coords[9];
+ };
+ plane max;
+ plane min;
+
+ bool prepareLoadedData();
+};
+
//
// Adt file header chunk
//
@@ -260,12 +281,12 @@ class adt_MHDR
public:
uint32 size;
- uint32 pad;
+ uint32 flags;
uint32 offsMCIN; // MCIN
- uint32 offsTex; // MTEX
- uint32 offsModels; // MMDX
- uint32 offsModelsIds; // MMID
- uint32 offsMapObejcts; // MWMO
+ uint32 offsTex; // MTEX
+ uint32 offsModels; // MMDX
+ uint32 offsModelsIds; // MMID
+ uint32 offsMapObejcts; // MWMO
uint32 offsMapObejctsIds; // MWID
uint32 offsDoodsDef; // MDDF
uint32 offsObjectsDef; // MODF
@@ -278,9 +299,22 @@ public:
uint32 data5;
public:
bool prepareLoadedData();
- adt_MCIN *getMCIN(){ return (adt_MCIN *)((uint8 *)&pad+offsMCIN);}
- adt_MH2O *getMH2O(){ return offsMH2O ? (adt_MH2O *)((uint8 *)&pad+offsMH2O) : 0;}
-
+ adt_MCIN* getMCIN()
+ {
+ return reinterpret_cast<adt_MCIN*>(reinterpret_cast<uint8*>(&flags) + offsMCIN);
+ }
+ adt_MH2O* getMH2O()
+ {
+ if (offsMH2O)
+ return reinterpret_cast<adt_MH2O*>(reinterpret_cast<uint8*>(&flags) + offsMH2O);
+ return nullptr;
+ }
+ adt_MFBO* getMFBO()
+ {
+ if (flags & 1 && offsMFBO)
+ return reinterpret_cast<adt_MFBO*>(reinterpret_cast<uint8*>(&flags) + offsMFBO);
+ return nullptr;
+ }
};
class ADT_file : public FileLoader{
diff --git a/src/tools/map_extractor/loadlib.cpp b/src/tools/map_extractor/loadlib.cpp
index 2a3b0482f5..1219ef78b5 100644
--- a/src/tools/map_extractor/loadlib.cpp
+++ b/src/tools/map_extractor/loadlib.cpp
@@ -26,14 +26,14 @@ FileLoader::~FileLoader()
free();
}
-bool FileLoader::loadFile(char *filename, bool log)
+bool FileLoader::loadFile(std::string const& fileName, bool log)
{
free();
- MPQFile mf(filename);
+ MPQFile mf(fileName.c_str());
if(mf.isEof())
{
if (log)
- printf("No such file %s\n", filename);
+ printf("No such file %s\n", fileName.c_str());
return false;
}
@@ -45,7 +45,7 @@ bool FileLoader::loadFile(char *filename, bool log)
if (prepareLoadedData())
return true;
- printf("Error loading %s", filename);
+ printf("Error loading %s", fileName.c_str());
mf.close();
free();
return false;
diff --git a/src/tools/map_extractor/loadlib/loadlib.h b/src/tools/map_extractor/loadlib/loadlib.h
index a2169b6b4b..e500f25e6e 100644
--- a/src/tools/map_extractor/loadlib/loadlib.h
+++ b/src/tools/map_extractor/loadlib/loadlib.h
@@ -7,6 +7,8 @@
#ifndef LOAD_LIB_H
#define LOAD_LIB_H
+#include <string>
+
#ifdef _WIN32
typedef __int64 int64;
typedef __int32 int32;
@@ -65,7 +67,7 @@ public:
file_MVER *version;
FileLoader();
~FileLoader();
- bool loadFile(char *filename, bool log = true);
+ bool loadFile(std::string const& filename, bool log = true);
virtual void free();
};
#endif
diff --git a/src/tools/mesh_extractor/Utils.h b/src/tools/mesh_extractor/Utils.h
index bf98e65f01..2daa23d854 100644
--- a/src/tools/mesh_extractor/Utils.h
+++ b/src/tools/mesh_extractor/Utils.h
@@ -341,7 +341,7 @@ public:
};
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
-#define MMAP_VERSION 3
+#define MMAP_VERSION 8
struct MmapTileHeader
{
diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp
index e5edd4a611..94780d7422 100644
--- a/src/tools/mmaps_generator/MapBuilder.cpp
+++ b/src/tools/mmaps_generator/MapBuilder.cpp
@@ -17,14 +17,13 @@
#include "DisableMgr.h"
#include <ace/OS_NS_unistd.h>
-uint32 GetLiquidFlags(uint32 /*liquidType*/) { return 0; }
namespace DisableMgr
{
bool IsDisabledFor(DisableType /*type*/, uint32 /*entry*/, Unit const* /*unit*/, uint8 /*flags*/ /*= 0*/) { return false; }
}
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
-#define MMAP_VERSION 3
+#define MMAP_VERSION 8
struct MmapTileHeader
{
@@ -32,12 +31,22 @@ struct MmapTileHeader
uint32 dtVersion;
uint32 mmapVersion;
uint32 size;
- bool usesLiquids : 1;
+ char usesLiquids;
+ char padding[3];
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
- mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
+ mmapVersion(MMAP_VERSION), size(0), usesLiquids(true), padding() {}
};
+// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files
+static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size");
+static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) +
+ sizeof(MmapTileHeader::dtVersion) +
+ sizeof(MmapTileHeader::mmapVersion) +
+ sizeof(MmapTileHeader::size) +
+ sizeof(MmapTileHeader::usesLiquids) +
+ sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");
+
namespace MMAP
{
MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid,
@@ -57,6 +66,10 @@ namespace MMAP
m_rcContext = new rcContext(false);
+ // percentageDone - Initializing
+ m_totalTiles = 0;
+ m_totalTilesBuilt = 0;
+
discoverTiles();
}
@@ -65,8 +78,8 @@ namespace MMAP
{
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
{
- (*it).second->clear();
- delete (*it).second;
+ (*it).m_tiles->clear();
+ delete (*it).m_tiles;
}
delete m_terrainBuilder;
@@ -85,9 +98,9 @@ namespace MMAP
for (uint32 i = 0; i < files.size(); ++i)
{
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
- if (m_tiles.find(mapID) == m_tiles.end())
+ if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end())
{
- m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>));
+ m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>));
count++;
}
}
@@ -97,8 +110,11 @@ namespace MMAP
for (uint32 i = 0; i < files.size(); ++i)
{
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
- m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>));
- count++;
+ if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end())
+ {
+ m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>));
+ count++;
+ }
}
printf("found %u.\n", count);
@@ -106,8 +122,8 @@ namespace MMAP
printf("Discovering tiles... ");
for (TileList::iterator itr = m_tiles.begin(); itr != m_tiles.end(); ++itr)
{
- std::set<uint32>* tiles = (*itr).second;
- mapID = (*itr).first;
+ std::set<uint32>* tiles = (*itr).m_tiles;
+ mapID = (*itr).m_mapId;
sprintf(filter, "%03u*.vmtile", mapID);
files.clear();
@@ -136,17 +152,20 @@ namespace MMAP
}
}
printf("found %u.\n\n", count);
+
+ // percentageDone - total tiles to process
+ m_totalTiles = count;
}
/**************************************************************************/
std::set<uint32>* MapBuilder::getTileList(uint32 mapID)
{
- TileList::iterator itr = m_tiles.find(mapID);
+ TileList::iterator itr = std::find(m_tiles.begin(), m_tiles.end(), mapID);
if (itr != m_tiles.end())
- return (*itr).second;
+ return (*itr).m_tiles;
std::set<uint32>* tiles = new std::set<uint32>();
- m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, tiles));
+ m_tiles.emplace_back(MapTiles(mapID, tiles));
return tiles;
}
@@ -157,9 +176,14 @@ namespace MMAP
BuilderThreadPool* pool = threads > 0 ? new BuilderThreadPool() : NULL;
+ m_tiles.sort([](MapTiles a, MapTiles b)
+ {
+ return a.m_tiles->size() > b.m_tiles->size();
+ });
+
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
{
- uint32 mapID = it->first;
+ uint32 mapID = it->m_mapId;
if (!shouldSkipMap(mapID))
{
if (threads > 0)
@@ -183,12 +207,14 @@ namespace MMAP
}
/**************************************************************************/
- void MapBuilder::getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY)
+ void MapBuilder::getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY) const
{
- maxX = INT_MAX;
- maxY = INT_MAX;
- minX = INT_MIN;
- minY = INT_MIN;
+ // min and max are initialized to invalid values so the caller iterating the [min, max] range
+ // will never enter the loop unless valid min/max values are found
+ maxX = 0;
+ maxY = 0;
+ minX = std::numeric_limits<uint32>::max();
+ minY = std::numeric_limits<uint32>::max();
float bmin[3] = { 0, 0, 0 };
float bmax[3] = { 0, 0, 0 };
@@ -329,7 +355,7 @@ namespace MMAP
void MapBuilder::buildMap(uint32 mapID)
{
#ifndef __APPLE__
- printf("[Thread %u] Building map %03u:\n", uint32(ACE_Thread::self()), mapID);
+ //printf("[Thread %u] Building map %03u:\n", uint32(ACE_Thread::self()), mapID);
#endif
std::set<uint32>* tiles = getTileList(mapID);
@@ -382,7 +408,8 @@ namespace MMAP
/**************************************************************************/
void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
{
- printf("[Map %03i] Building tile [%02u,%02u]\n", mapID, tileX, tileY);
+ // percentageDone - added, now it will show addional reference percentage done of the overall process
+ printf("%u%% [Map %03i] Building tile [%02u,%02u]\n", percentageDone(m_totalTiles, m_totalTilesBuilt), mapID, tileX, tileY);
MeshData meshData;
@@ -416,6 +443,9 @@ namespace MMAP
// build navmesh tile
buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
+
+ // percentageDone - increment tiles built
+ m_totalTilesBuilt++;
}
/**************************************************************************/
@@ -429,7 +459,7 @@ namespace MMAP
//if (tileBits < 1) tileBits = 1; // need at least one bit!
//int polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits;
- int polyBits = STATIC_POLY_BITS;
+ int polyBits = DT_POLY_BITS;
int maxTiles = tiles->size();
int maxPolysPerTile = 1 << polyBits;
@@ -541,7 +571,9 @@ namespace MMAP
config.borderSize = config.walkableRadius + 3;
config.maxEdgeLen = VERTEX_PER_TILE + 1; // anything bigger than tileSize
config.walkableHeight = m_bigBaseUnit ? 3 : 6;
- config.walkableClimb = m_bigBaseUnit ? 2 : 4; // keep less than walkableHeight
+ // a value >= 3|6 allows npcs to walk over some fences
+ // a value >= 4|8 allows npcs to walk over all fences
+ config.walkableClimb = m_bigBaseUnit ? 4 : 8;
config.minRegionArea = rcSqr(60);
config.mergeRegionArea = rcSqr(50);
config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons)
@@ -665,7 +697,7 @@ namespace MMAP
iv.polyMesh = rcAllocPolyMesh();
if (!iv.polyMesh)
{
- printf("%s alloc iv.polyMesh FIALED!\n", tileString);
+ printf("%s alloc iv.polyMesh FAILED!\n", tileString);
delete[] pmmerge;
delete[] dmmerge;
delete[] tiles;
@@ -676,7 +708,7 @@ namespace MMAP
iv.polyMeshDetail = rcAllocPolyMeshDetail();
if (!iv.polyMeshDetail)
{
- printf("%s alloc m_dmesh FIALED!\n", tileString);
+ printf("%s alloc m_dmesh FAILED!\n", tileString);
delete[] pmmerge;
delete[] dmmerge;
delete[] tiles;
@@ -741,12 +773,12 @@ namespace MMAP
if (params.nvp > DT_VERTS_PER_POLYGON)
{
printf("%s Invalid verts-per-polygon value! \n", tileString);
- continue;
+ break;
}
if (params.vertCount >= 0xffff)
{
printf("%s Too many vertices! \n", tileString);
- continue;
+ break;
}
if (!params.vertCount || !params.verts)
{
@@ -754,8 +786,8 @@ namespace MMAP
// loaded but those models don't span into this tile
// message is an annoyance
- //printf("%sNo vertices to build tile! \n", tileString);
- continue;
+ printf("%sNo vertices to build tile! \n", tileString);
+ break;
}
if (!params.polyCount || !params.polys ||
TILES_PER_MAP*TILES_PER_MAP == params.polyCount)
@@ -764,19 +796,19 @@ namespace MMAP
// keep in mind that we do output those into debug info
// drop tiles with only exact count - some tiles may have geometry while having less tiles
printf("%s No polygons to build on tile! \n", tileString);
- continue;
+ break;
}
if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
{
printf("%s No detail mesh to build tile! \n", tileString);
- continue;
+ break;
}
printf("%s Building navmesh tile...\n", tileString);
if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
{
printf("%s Failed building navmesh tile! \n", tileString);
- continue;
+ break;
}
dtTileRef tileRef = 0;
@@ -787,7 +819,7 @@ namespace MMAP
if (!tileRef || dtResult != DT_SUCCESS)
{
printf("%s Failed adding tile to navmesh! \n", tileString);
- continue;
+ break;
}
// file output
@@ -800,7 +832,7 @@ namespace MMAP
sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName);
perror(message);
navMesh->removeTile(tileRef, NULL, NULL);
- continue;
+ break;
}
printf("%s Writing to file...\n", tileString);
@@ -970,5 +1002,13 @@ namespace MMAP
return true;
}
+
+ /**************************************************************************/
+ uint32 MapBuilder::percentageDone(uint32 totalTiles, uint32 totalTilesBuilt)
+ {
+ if (totalTiles)
+ return totalTilesBuilt * 100 / totalTiles;
+ return 0;
+ }
}
diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h
index c99b8da0ea..877102af7e 100644
--- a/src/tools/mmaps_generator/MapBuilder.h
+++ b/src/tools/mmaps_generator/MapBuilder.h
@@ -9,7 +9,9 @@
#include <vector>
#include <set>
+#include <atomic>
#include <map>
+#include <list>
#include "TerrainBuilder.h"
#include "IntermediateValues.h"
@@ -27,7 +29,24 @@ using namespace VMAP;
namespace MMAP
{
- typedef std::map<uint32, std::set<uint32>*> TileList;
+ struct MapTiles
+ {
+ MapTiles() : m_mapId(uint32(-1)), m_tiles(NULL) {}
+
+ MapTiles(uint32 id, std::set<uint32>* tiles) : m_mapId(id), m_tiles(tiles) {}
+ ~MapTiles() {}
+
+ uint32 m_mapId;
+ std::set<uint32>* m_tiles;
+
+ bool operator==(uint32 id)
+ {
+ return m_mapId == id;
+ }
+ };
+
+ typedef std::list<MapTiles> TileList;
+
struct Tile
{
Tile() : chf(NULL), solid(NULL), cset(NULL), pmesh(NULL), dmesh(NULL) {}
@@ -49,7 +68,7 @@ namespace MMAP
class MapBuilder
{
public:
- MapBuilder(float maxWalkableAngle = 55.f,
+ MapBuilder(float maxWalkableAngle = 70.f,
bool skipLiquid = false,
bool skipContinents = false,
bool skipJunkMaps = true,
@@ -91,11 +110,13 @@ namespace MMAP
void getTileBounds(uint32 tileX, uint32 tileY,
float* verts, int vertCount,
float* bmin, float* bmax);
- void getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY);
+ void getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY) const;
bool shouldSkipMap(uint32 mapID);
bool isTransportMap(uint32 mapID);
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY);
+ // percentageDone - method to calculate percentage
+ uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone);
TerrainBuilder* m_terrainBuilder;
TileList m_tiles;
@@ -109,6 +130,9 @@ namespace MMAP
float m_maxWalkableAngle;
bool m_bigBaseUnit;
+ // percentageDone - variables to calculate percentage
+ uint32 m_totalTiles;
+ std::atomic<uint32> m_totalTilesBuilt;
// build performance - not really used for now
rcContext* m_rcContext;
diff --git a/src/tools/mmaps_generator/PathCommon.h b/src/tools/mmaps_generator/PathCommon.h
index 477f974021..e3f23b1a76 100644
--- a/src/tools/mmaps_generator/PathCommon.h
+++ b/src/tools/mmaps_generator/PathCommon.h
@@ -7,11 +7,9 @@
#ifndef _MMAP_COMMON_H
#define _MMAP_COMMON_H
+#include "Common.h"
#include <string>
#include <vector>
-#include <ace/OS_NS_sys_time.h>
-
-#include "Define.h"
#ifndef _WIN32
#include <stddef.h>
@@ -53,7 +51,7 @@ namespace MMAP
if (*++filter == '\0') // wildcard at end of filter means all remaing chars match
return true;
- while (true)
+ for (;;)
{
if (*filter == *str)
break;
@@ -125,26 +123,6 @@ namespace MMAP
return LISTFILE_OK;
}
-
- inline uint32 getMSTime()
- {
- static const ACE_Time_Value ApplicationStartTime = ACE_OS::gettimeofday();
- return (ACE_OS::gettimeofday() - ApplicationStartTime).msec();
- }
-
- inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
- {
- // getMSTime() have limited data range and this is case when it overflow in this tick
- if (oldMSTime > newMSTime)
- return (0xFFFFFFFF - oldMSTime) + newMSTime;
- else
- return newMSTime - oldMSTime;
- }
-
- inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
- {
- return getMSTimeDiff(oldMSTime, getMSTime());
- }
}
#endif
diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp
index 16201eba1a..1ce6137fc2 100644
--- a/src/tools/mmaps_generator/PathGenerator.cpp
+++ b/src/tools/mmaps_generator/PathGenerator.cpp
@@ -6,6 +6,7 @@
#include "PathCommon.h"
#include "MapBuilder.h"
+#include "Timer.h"
using namespace MMAP;
@@ -230,7 +231,7 @@ int finish(const char* message, int returnValue)
int main(int argc, char** argv)
{
int threads = 3, mapnum = -1;
- float maxAngle = 55.0f;
+ float maxAngle = 70.0f;
int tileX = -1, tileY = -1;
bool skipLiquid = false,
skipContinents = false,
@@ -263,7 +264,7 @@ int main(int argc, char** argv)
}
if (!checkDirectories(debugOutput))
- return silent ? -3 : finish("Press any key to close...", -3);
+ return silent ? -3 : finish("Press ENTER to close...", -3);
MapBuilder builder(maxAngle, skipLiquid, skipContinents, skipJunkMaps,
skipBattlegrounds, debugOutput, bigBaseUnit, offMeshInputPath);
diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp
index 260bb6da7e..3445013bd8 100644
--- a/src/tools/mmaps_generator/TerrainBuilder.cpp
+++ b/src/tools/mmaps_generator/TerrainBuilder.cpp
@@ -70,7 +70,7 @@ struct map_liquidHeader
namespace MMAP
{
- char const* MAP_VERSION_MAGIC = "v1.3";
+ char const* MAP_VERSION_MAGIC = "v1.8";
TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ }
TerrainBuilder::~TerrainBuilder() { }
@@ -700,7 +700,7 @@ namespace MMAP
uint8 type = NAV_EMPTY;
// convert liquid type to NavTerrain
- switch (liquid->GetType())
+ switch (liquid->GetType() & 3)
{
case 0:
case 1:
@@ -754,12 +754,12 @@ namespace MMAP
}
uint32 liqOffset = meshData.liquidVerts.size() / 3;
- for (uint32 i = 0; i < liqVerts.size(); ++i)
- meshData.liquidVerts.append(liqVerts[i].y, liqVerts[i].z, liqVerts[i].x);
+ for (uint32 j = 0; j < liqVerts.size(); ++j)
+ meshData.liquidVerts.append(liqVerts[j].y, liqVerts[j].z, liqVerts[j].x);
- for (uint32 i = 0; i < liqTris.size() / 3; ++i)
+ for (uint32 j = 0; j < liqTris.size() / 3; ++j)
{
- meshData.liquidTris.append(liqTris[i*3+1] + liqOffset, liqTris[i*3+2] + liqOffset, liqTris[i*3] + liqOffset);
+ meshData.liquidTris.append(liqTris[j*3+1] + liqOffset, liqTris[j*3+2] + liqOffset, liqTris[j*3] + liqOffset);
meshData.liquidType.append(type);
}
}
@@ -894,7 +894,7 @@ namespace MMAP
float p0[3], p1[3];
uint32 mid, tx, ty;
float size;
- if (sscanf(buf, "%d %d,%d (%f %f %f) (%f %f %f) %f", &mid, &tx, &ty,
+ if (sscanf(buf, "%u %u,%u (%f %f %f) (%f %f %f) %f", &mid, &tx, &ty,
&p0[0], &p0[1], &p0[2], &p1[0], &p1[1], &p1[2], &size) != 10)
continue;
diff --git a/src/tools/mmaps_generator/TerrainBuilder.h b/src/tools/mmaps_generator/TerrainBuilder.h
index 0bb29fef47..52773320fd 100644
--- a/src/tools/mmaps_generator/TerrainBuilder.h
+++ b/src/tools/mmaps_generator/TerrainBuilder.h
@@ -69,11 +69,13 @@ namespace MMAP
TerrainBuilder(bool skipLiquid);
~TerrainBuilder();
+ TerrainBuilder(const TerrainBuilder &tb) = delete;
+
void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
void loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, const char* offMeshFilePath);
- bool usesLiquids() { return !m_skipLiquid; }
+ bool usesLiquids() const { return !m_skipLiquid; }
// vert and triangle methods
static void transform(std::vector<G3D::Vector3> &original, std::vector<G3D::Vector3> &transformed,
@@ -109,10 +111,6 @@ namespace MMAP
/// Get the liquid type for a specific position
uint8 getLiquidType(int square, const uint8 liquid_type[16][16]);
-
- // hide parameterless and copy constructor
- TerrainBuilder();
- TerrainBuilder(const TerrainBuilder &tb);
};
}
diff --git a/src/tools/vmap4_extractor/loadlib/loadlib.h b/src/tools/vmap4_extractor/loadlib/loadlib.h
index e55b4a7c56..989f665934 100644
--- a/src/tools/vmap4_extractor/loadlib/loadlib.h
+++ b/src/tools/vmap4_extractor/loadlib/loadlib.h
@@ -7,6 +7,8 @@
#ifndef LOAD_LIB_H
#define LOAD_LIB_H
+#include <string>
+
#ifdef WIN32
typedef __int64 int64;
typedef __int32 int32;
@@ -59,7 +61,7 @@ public:
file_MVER *version;
FileLoader();
~FileLoader();
- bool loadFile(char *filename, bool log = true);
+ bool loadFile(std::string const& filename, bool log = true);
virtual void free();
};
#endif
diff --git a/src/tools/vmap4_extractor/model.cpp b/src/tools/vmap4_extractor/model.cpp
index 28c1bad31b..07f1f3ec16 100644
--- a/src/tools/vmap4_extractor/model.cpp
+++ b/src/tools/vmap4_extractor/model.cpp
@@ -84,17 +84,31 @@ bool Model::ConvertToVMAPModel(const char * outfilename)
wsize = sizeof(uint32) + sizeof(unsigned short) * nIndexes;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&nIndexes, sizeof(uint32), 1, output);
- if (nIndexes >0)
+ if (nIndexes > 0)
+ {
+ for (uint32 i = 0; i < nIndexes; ++i)
+ {
+ if ((i % 3) - 1 == 0 && i + 1 < nIndexes)
+ {
+ uint16 tmp = indices[i];
+ indices[i] = indices[i + 1];
+ indices[i + 1] = tmp;
+ }
+ }
fwrite(indices, sizeof(unsigned short), nIndexes, output);
-
+ }
fwrite("VERT", 4, 1, output);
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&nVertices, sizeof(int), 1, output);
if (nVertices >0)
{
- for(uint32 vpos=0; vpos <nVertices; ++vpos)
- std::swap(vertices[vpos].y, vertices[vpos].z);
+ for (uint32 vpos = 0; vpos < nVertices; ++vpos)
+ {
+ float tmp = vertices[vpos].y;
+ vertices[vpos].y = -vertices[vpos].z;
+ vertices[vpos].z = tmp;
+ }
fwrite(vertices, sizeof(float)*3, nVertices, output);
}
@@ -169,7 +183,6 @@ ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID
int realy1 = (int) ((float) pos.z / 533.333333f);
int realx2 = (int) ((float) pos.x / 533.333333f);
int realy2 = (int) ((float) pos.z / 533.333333f);
-
fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n",
MapName,
ModelInstName,