From 8cac2f42dbd281f1359b5d485c1284d915bde8e1 Mon Sep 17 00:00:00 2001 From: Charles A Edwards Date: Mon, 29 Aug 2016 15:51:13 +0100 Subject: [PATCH] Mant more cmangos Cata commits applied Commit: --- src/framework/Platform/Define.h | 15 +- src/game/BattleGround/BattleGround.cpp | 22 +- src/game/BattleGround/BattleGround.h | 2 + src/game/BattleGround/BattleGroundAB.cpp | 15 ++ src/game/BattleGround/BattleGroundAB.h | 2 + src/game/BattleGround/BattleGroundAV.cpp | 14 + src/game/BattleGround/BattleGroundAV.h | 2 + src/game/BattleGround/BattleGroundEY.cpp | 37 ++- src/game/BattleGround/BattleGroundEY.h | 2 + src/game/BattleGround/BattleGroundWS.cpp | 14 + src/game/BattleGround/BattleGroundWS.h | 2 + src/game/ChatCommands/Level2.cpp | 130 ++++++---- src/game/ChatCommands/Level3.cpp | 4 +- src/game/ChatCommands/debugcmds.cpp | 2 +- src/game/MotionGenerators/PathFinder.cpp | 2 +- src/game/Object/Creature.cpp | 27 +- src/game/Object/Creature.h | 3 +- src/game/Object/GameObject.cpp | 16 ++ src/game/Object/GameObject.h | 2 + src/game/Object/Object.cpp | 12 +- src/game/Object/Object.h | 1 + src/game/Object/Player.cpp | 28 +- src/game/Object/Unit.cpp | 60 +++-- src/game/Object/Unit.h | 1 + src/game/Server/DBCEnums.h | 11 +- src/game/Server/WorldSession.cpp | 2 +- src/game/Server/WorldSession.h | 3 +- src/game/Server/WorldSocket.cpp | 7 +- src/game/WorldHandlers/GridMap.cpp | 28 +- src/game/WorldHandlers/GridMap.h | 5 +- src/game/WorldHandlers/MiscHandler.cpp | 23 +- src/game/WorldHandlers/MoveMap.cpp | 55 +++- src/game/WorldHandlers/MoveMap.h | 6 +- src/game/WorldHandlers/MovementHandler.cpp | 6 +- src/game/WorldHandlers/ScriptMgr.cpp | 242 ++++++++++++++---- src/game/WorldHandlers/ScriptMgr.h | 49 +++- src/game/WorldHandlers/Spell.cpp | 29 ++- src/game/WorldHandlers/SpellAuras.cpp | 2 +- src/game/WorldHandlers/SpellEffects.cpp | 201 +++++++++++++-- src/game/WorldHandlers/SpellHandler.cpp | 5 +- src/game/WorldHandlers/WaypointManager.cpp | 2 +- src/game/WorldHandlers/WaypointManager.h | 2 +- src/game/WorldHandlers/World.cpp | 1 + src/game/WorldHandlers/World.h | 5 +- .../molten_core/boss_garr.cpp | 15 +- .../molten_core/boss_golemagg.cpp | 11 + .../northrend/naxxramas/boss_anubrekhan.cpp | 6 + .../northrend/naxxramas/boss_gluth.cpp | 8 +- .../northrend/naxxramas/boss_maexxna.cpp | 7 + .../northrend/ulduar/ulduar/boss_freya.cpp | 61 ++++- src/shared/DataStores/DB2FileLoader.cpp | 27 +- 51 files changed, 964 insertions(+), 270 deletions(-) diff --git a/src/framework/Platform/Define.h b/src/framework/Platform/Define.h index 141b62e33..2d1b3d9fb 100644 --- a/src/framework/Platform/Define.h +++ b/src/framework/Platform/Define.h @@ -64,9 +64,20 @@ typedef ACE_SHLIB_HANDLE MANGOS_LIBRARY_HANDLE; # define MANGOS_EXPORT __declspec(dllexport) # define MANGOS_IMPORT __cdecl #else // PLATFORM != PLATFORM_WINDOWS +# include + typedef void* MANGOS_LIBRARY_HANDLE; +# define MANGOS_LOAD_LIBRARY(libname) dlopen(libname, RTLD_LAZY) +# define MANGOS_CLOSE_LIBRARY(hlib) dlclose(hlib) +# define MANGOS_GET_PROC_ADDR(hlib, name) dlsym(hlib, name) # define MANGOS_EXPORT export -# if defined(__APPLE_CC__) && defined(BIG_ENDIAN) -# if (defined(__ppc__) || defined(__powerpc__)) +# if PLATFORM == PLATFORM_APPLE +# define MANGOS_SCRIPT_SUFFIX ".dylib" +# else +# define MANGOS_SCRIPT_SUFFIX ".so" +# endif +# define MANGOS_SCRIPT_PREFIX "lib" +# if defined(__APPLE_CC__) && defined(BIG_ENDIAN) // TODO:: more work to do with byte order. Have to be rechecked after boost integration. +# if (defined (__ppc__) || defined (__powerpc__)) # define MANGOS_IMPORT __attribute__ ((longcall)) # else # define MANGOS_IMPORT diff --git a/src/game/BattleGround/BattleGround.cpp b/src/game/BattleGround/BattleGround.cpp index af4915092..7ba25fa9d 100644 --- a/src/game/BattleGround/BattleGround.cpp +++ b/src/game/BattleGround/BattleGround.cpp @@ -326,14 +326,7 @@ void BattleGround::Update(uint32 diff) } else if (m_PrematureCountDownTimer < diff) { - // time's up! - Team winner = TEAM_NONE; - if (GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam()) - winner = ALLIANCE; - else if (GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam()) - winner = HORDE; - - EndBattleGround(winner); + EndBattleGround(GetPrematureWinner()); m_PrematureCountDown = false; } else if (!sBattleGroundMgr.isTesting()) @@ -1483,6 +1476,19 @@ void BattleGround::DoorOpen(ObjectGuid guid) sLog.outError("BattleGround: Door %s not found! - doors will be closed.", guid.GetString().c_str()); } +Team BattleGround::GetPrematureWinner() +{ + uint32 hordePlayers = GetPlayersCountByTeam(HORDE); + uint32 alliancePlayers = GetPlayersCountByTeam(ALLIANCE); + + if (hordePlayers > alliancePlayers) + return HORDE; + if (alliancePlayers > hordePlayers) + return ALLIANCE; + + return TEAM_NONE; +} + void BattleGround::OnObjectDBLoad(Creature* creature) { const BattleGroundEventIdx eventId = sBattleGroundMgr.GetCreatureEventIndex(creature->GetGUIDLow()); diff --git a/src/game/BattleGround/BattleGround.h b/src/game/BattleGround/BattleGround.h index 0bf2ffdb4..46b4b1e37 100644 --- a/src/game/BattleGround/BattleGround.h +++ b/src/game/BattleGround/BattleGround.h @@ -550,6 +550,8 @@ class BattleGround void DoorOpen(ObjectGuid guid); void DoorClose(ObjectGuid guid); + virtual Team GetPrematureWinner(); + virtual bool HandlePlayerUnderMap(Player* /*plr*/) { return false; } // since arenas can be AvA or Hvh, we have to get the "temporary" team of a player diff --git a/src/game/BattleGround/BattleGroundAB.cpp b/src/game/BattleGround/BattleGroundAB.cpp index da1142477..5014d1920 100644 --- a/src/game/BattleGround/BattleGroundAB.cpp +++ b/src/game/BattleGround/BattleGroundAB.cpp @@ -543,3 +543,18 @@ bool BattleGroundAB::IsAllNodesControlledByTeam(Team team) const return true; } + +Team BattleGroundAB::GetPrematureWinner() +{ + int32 hordeScore = m_TeamScores[TEAM_INDEX_HORDE]; + int32 allianceScore = m_TeamScores[TEAM_INDEX_ALLIANCE]; + + if (hordeScore > allianceScore) + return HORDE; + if (allianceScore > hordeScore) + return ALLIANCE; + + // If the values are equal, fall back to number of players on each team + return BattleGround::GetPrematureWinner(); +} + diff --git a/src/game/BattleGround/BattleGroundAB.h b/src/game/BattleGround/BattleGroundAB.h index de82130f5..d67574f7e 100644 --- a/src/game/BattleGround/BattleGroundAB.h +++ b/src/game/BattleGround/BattleGroundAB.h @@ -189,6 +189,8 @@ class BattleGroundAB : public BattleGround /* achievement req. */ bool IsAllNodesControlledByTeam(Team team) const override; bool IsTeamScores500Disadvantage(Team team) const { return m_TeamScores500Disadvantage[GetTeamIndexByTeamId(team)]; } + + virtual Team GetPrematureWinner() override; private: /* Gameobject spawning/despawning */ void _CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay); diff --git a/src/game/BattleGround/BattleGroundAV.cpp b/src/game/BattleGround/BattleGroundAV.cpp index cf177a193..30caa40eb 100644 --- a/src/game/BattleGround/BattleGroundAV.cpp +++ b/src/game/BattleGround/BattleGroundAV.cpp @@ -823,3 +823,17 @@ void BattleGroundAV::Reset() InitNode(BG_AV_NODES_SNOWFALL_GRAVE, BG_AV_TEAM_NEUTRAL, false); // give snowfall neutral owner } + +Team BattleGroundAV::GetPrematureWinner() +{ + int32 hordeScore = m_TeamScores[TEAM_INDEX_HORDE]; + int32 allianceScore = m_TeamScores[TEAM_INDEX_ALLIANCE]; + + if (hordeScore > allianceScore) + return HORDE; + if (allianceScore > hordeScore) + return ALLIANCE; + + // If the values are equal, fall back to number of players on each team + return BattleGround::GetPrematureWinner(); +} diff --git a/src/game/BattleGround/BattleGroundAV.h b/src/game/BattleGround/BattleGroundAV.h index ae3a0c2b8..b05570521 100644 --- a/src/game/BattleGround/BattleGroundAV.h +++ b/src/game/BattleGround/BattleGroundAV.h @@ -359,6 +359,8 @@ class BattleGroundAV : public BattleGround virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* plr) override; static BattleGroundAVTeamIndex GetAVTeamIndexByTeamId(Team team) { return BattleGroundAVTeamIndex(GetTeamIndexByTeamId(team)); } + + virtual Team GetPrematureWinner() override; private: /* Nodes occupying */ void EventPlayerAssaultsPoint(Player* player, BG_AV_Nodes node); diff --git a/src/game/BattleGround/BattleGroundEY.cpp b/src/game/BattleGround/BattleGroundEY.cpp index 6d0806a12..f1522a0fb 100644 --- a/src/game/BattleGround/BattleGroundEY.cpp +++ b/src/game/BattleGround/BattleGroundEY.cpp @@ -401,18 +401,6 @@ void BattleGroundEY::HandleKillPlayer(Player* player, Player* killer) void BattleGroundEY::EventPlayerDroppedFlag(Player* source) { - if (GetStatus() != STATUS_IN_PROGRESS) - { - // if not running, do not cast things at the dropper player, neither send unnecessary messages - // just take off the aura - if (IsFlagPickedUp() && GetFlagCarrierGuid() == source->GetObjectGuid()) - { - ClearFlagCarrier(); - source->RemoveAurasDueToSpell(EY_NETHERSTORM_FLAG_SPELL); - } - return; - } - if (!IsFlagPickedUp()) return; @@ -421,6 +409,13 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player* source) ClearFlagCarrier(); source->RemoveAurasDueToSpell(EY_NETHERSTORM_FLAG_SPELL); + + if (GetStatus() != STATUS_IN_PROGRESS) + { + // do not cast auras or send messages after match has ended + return; + } + m_flagState = EY_FLAG_STATE_ON_GROUND; m_flagRespawnTimer = EY_FLAG_RESPAWN_TIME; source->CastSpell(source, SPELL_RECENTLY_DROPPED_FLAG, true); @@ -429,12 +424,12 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player* source) if (source->GetTeam() == ALLIANCE) { UpdateWorldState(WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_ALLIANCE, 1); - SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL); + SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, nullptr); } else { UpdateWorldState(WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_HORDE, 1); - SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL); + SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, nullptr); } } @@ -625,3 +620,17 @@ bool BattleGroundEY::IsAllNodesControlledByTeam(Team team) const return true; } + +Team BattleGroundEY::GetPrematureWinner() +{ + int32 hordeScore = m_TeamScores[TEAM_INDEX_HORDE]; + int32 allianceScore = m_TeamScores[TEAM_INDEX_ALLIANCE]; + + if (hordeScore > allianceScore) + return HORDE; + if (allianceScore > hordeScore) + return ALLIANCE; + + // If the values are equal, fall back to number of players on each team + return BattleGround::GetPrematureWinner(); +} diff --git a/src/game/BattleGround/BattleGroundEY.h b/src/game/BattleGround/BattleGroundEY.h index 9a85830c5..8b1fe1f4f 100644 --- a/src/game/BattleGround/BattleGroundEY.h +++ b/src/game/BattleGround/BattleGroundEY.h @@ -284,6 +284,8 @@ class BattleGroundEY : public BattleGround /* achievement req. */ bool IsAllNodesControlledByTeam(Team team) const override; + virtual Team GetPrematureWinner() override; + private: // process capture events void ProcessCaptureEvent(GameObject* go, uint32 towerId, Team team, uint32 newWorldState, uint32 message); diff --git a/src/game/BattleGround/BattleGroundWS.cpp b/src/game/BattleGround/BattleGroundWS.cpp index 1aad78153..c6124e2ca 100644 --- a/src/game/BattleGround/BattleGroundWS.cpp +++ b/src/game/BattleGround/BattleGroundWS.cpp @@ -652,3 +652,17 @@ void BattleGroundWS::FillInitialWorldStates(WorldPacket& data, uint32& count) FillInitialWorldState(data, count, BG_WS_TIME_ENABLED, WORLD_STATE_ADD); FillInitialWorldState(data, count, BG_WS_TIME_REMAINING, GetRemainingTimeInMinutes()); } + +Team BattleGroundWS::GetPrematureWinner() +{ + int32 hordeScore = m_TeamScores[TEAM_INDEX_HORDE]; + int32 allianceScore = m_TeamScores[TEAM_INDEX_ALLIANCE]; + + if (hordeScore > allianceScore) + return HORDE; + if (allianceScore > hordeScore) + return ALLIANCE; + + // If the values are equal, fall back to number of players on each team + return BattleGround::GetPrematureWinner(); +} diff --git a/src/game/BattleGround/BattleGroundWS.h b/src/game/BattleGround/BattleGroundWS.h index 4ab1c7775..8fa832753 100644 --- a/src/game/BattleGround/BattleGroundWS.h +++ b/src/game/BattleGround/BattleGroundWS.h @@ -153,6 +153,8 @@ class BattleGroundWS : public BattleGround void ClearDroppedFlagGuid(Team team) { m_DroppedFlagGuid[GetTeamIndexByTeamId(team)].Clear();} ObjectGuid const& GetDroppedFlagGuid(Team team) const { return m_DroppedFlagGuid[GetTeamIndexByTeamId(team)];} virtual void FillInitialWorldStates(WorldPacket& data, uint32& count) override; + + virtual Team GetPrematureWinner() override; private: ObjectGuid m_flagCarrierAlliance; diff --git a/src/game/ChatCommands/Level2.cpp b/src/game/ChatCommands/Level2.cpp index c841031bf..68703f186 100644 --- a/src/game/ChatCommands/Level2.cpp +++ b/src/game/ChatCommands/Level2.cpp @@ -61,6 +61,7 @@ #include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand #include "MoveMap.h" // for mmap manager #include "PathFinder.h" // for mmap commands +#include "movement/MoveSplineInit.h" static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] = { @@ -2919,24 +2920,21 @@ inline void UnsummonVisualWaypoints(Player const* player, ObjectGuid ownerGuid) } } -/** - * Add a waypoint to a creature. +/** Add a waypoint to a creature + * .wp add [dbGuid] [pathId] [source] * - * The user can either select an npc or provide its GUID. + * The user can either select an npc or provide its dbGuid. + * Also the user can specify pathId and source if wanted. * * The user can even select a visual waypoint - then the new waypoint * is placed *after* the selected one - this makes insertion of new * waypoints possible. * - * eg: - * .wp add 12345 - * -> adds a waypoint to the npc with the GUID 12345 + * .wp add [pathId] [source] + * -> adds a waypoint to the currently selected creature, to path pathId in source-storage * - * .wp add - * -> adds a waypoint to the currently selected creature - * - * - * @param args if the user did not provide a GUID, it is NULL + * .wp add guid [pathId] [source] + * -> if no npc is selected, expect the creature provided with guid argument * * @return true - command did succeed, false - something went wrong */ @@ -3079,27 +3077,42 @@ bool ChatHandler::HandleWpAddCommand(char* args) PSendSysMessage(LANG_WAYPOINT_ADDED, wpPointId, wpOwner->GetGuidStr().c_str(), wpPathId, WaypointManager::GetOriginString(wpDestination).c_str()); return true; -} // HandleWpAddCommand +} // HandleWpAddCommand /** - * .wp modify emote | spell | text | del | move | add + * .wp modify waittime | scriptid | orientation | del | move [dbGuid, id] [value] * - * add -> add a WP after the selected visual waypoint - * User must select a visual waypoint and then issue ".wp modify add" - * - * emote + * waittime * User has selected a visual waypoint before. - * is added to this waypoint. Everytime the - * NPC comes to this waypoint, the emote is called. + * Delay is added to this waypoint. Everytime the + * NPC comes to this waypoint, it will wait Delay millieseconds. * - * emote + * waittime * User has not selected visual waypoint before. - * For the waypoint for the NPC with - * an emote is added. - * Everytime the NPC comes to this waypoint, the emote is called. + * For the waypoint for the NPC with + * an delay Delay is added to this waypoint + * Everytime the NPC comes to this waypoint, it will wait Delay millieseconds. * + * scriptid + * User has selected a visual waypoint before. + * is added to this waypoint. Everytime the + * NPC comes to this waypoint, the DBScript scriptId is executed. * - * info -> User did not select a visual waypoint and + * scriptid + * User has not selected visual waypoint before. + * For the waypoint for the NPC with + * an emote is added. + * Everytime the NPC comes to this waypoint, the DBScript scriptId is executed. + * + * orientation [DBGuid, WpNum] + * Set the orientation of the selected waypoint or waypoint given with DbGuid/ WpId + * to the value of . + * + * del [DBGuid, WpId] + * Remove the selected waypoint or waypoint given with DbGuid/ WpId. + * + * move [DBGuid, WpId] + * Move the selected waypoint or waypoint given with DbGuid/ WpId to player's current positiion. */ bool ChatHandler::HandleWpModifyCommand(char* args) { @@ -3303,29 +3316,19 @@ bool ChatHandler::HandleWpModifyCommand(char* args) } /** - * .wp show info | on | off + * .wp show info | on | off | first | last [dbGuid] [pathId [wpOrigin] ] * * info -> User has selected a visual waypoint before * - * info -> User did not select a visual waypoint and - * provided the GUID of the NPC and the number of - * the waypoint. - * * on -> User has selected an NPC; all visual waypoints for this * NPC are added to the world * - * on -> User did not select an NPC - instead the GUID of the + * on -> User did not select an NPC - instead the dbGuid of the * NPC is provided. All visual waypoints for this NPC * are added from the world. * * off -> User has selected an NPC; all visual waypoints for this * NPC are removed from the world. - * - * on -> User did not select an NPC - instead the GUID of the - * NPC is provided. All visual waypoints for this NPC - * are removed from the world. - * - * */ bool ChatHandler::HandleWpShowCommand(char* args) { @@ -5071,20 +5074,53 @@ bool ChatHandler::HandleMmapPathCommand(char* args) char* para = strtok(args, " "); bool useStraightPath = false; - if (para && strcmp(para, "true") == 0) - useStraightPath = true; + bool followPath = false; + bool unitToPlayer = false; + if (para) + { + if (strcmp(para, "go") == 0) + { + followPath = true; + para = strtok(nullptr, " "); + if (para && strcmp(para, "straight") == 0) + useStraightPath = true; + } + else if (strcmp(para, "straight") == 0) + useStraightPath = true; + else if (strcmp(para, "to_me") == 0) + unitToPlayer = true; + else + { + PSendSysMessage("Use '.mmap path go' to move on target."); + PSendSysMessage("Use '.mmap path straight' to generate straight path."); + PSendSysMessage("Use '.mmap path to_me' to generate path from the target to you."); + } + } + + Unit* destinationUnit; + Unit* originUnit; + if (unitToPlayer) + { + destinationUnit = player; + originUnit = target; + } + else + { + destinationUnit = target; + originUnit = player; + } // unit locations float x, y, z; - player->GetPosition(x, y, z); + destinationUnit->GetPosition(x, y, z); // path - PathFinder path(target); + PathFinder path(originUnit); path.setUseStrightPath(useStraightPath); path.calculate(x, y, z); PointsArray pointPath = path.getPath(); - PSendSysMessage("%s's path to %s:", target->GetName(), player->GetName()); + PSendSysMessage("%s's path to %s:", originUnit->GetName(), destinationUnit->GetName()); PSendSysMessage("Building %s", useStraightPath ? "StraightPath" : "SmoothPath"); PSendSysMessage("length " SIZEFMTD " type %u", pointPath.size(), path.getPathType()); @@ -5099,13 +5135,15 @@ bool ChatHandler::HandleMmapPathCommand(char* args) if (!player->isGameMaster()) PSendSysMessage("Enable GM mode to see the path points."); - // this entry visible only to GM's with "gm on" - static const uint32 WAYPOINT_NPC_ENTRY = 1; - Creature* wp = NULL; 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); + + if (followPath) { - wp = player->SummonCreature(WAYPOINT_NPC_ENTRY, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9000); - // TODO: make creature not sink/fall + Movement::MoveSplineInit init(*player); + init.MovebyPath(pointPath); + init.SetWalk(false); + init.Launch(); } return true; diff --git a/src/game/ChatCommands/Level3.cpp b/src/game/ChatCommands/Level3.cpp index 968d585b9..72c0fd12f 100644 --- a/src/game/ChatCommands/Level3.cpp +++ b/src/game/ChatCommands/Level3.cpp @@ -2302,7 +2302,7 @@ bool ChatHandler::HandleLearnAllCommand(char* /*args*/) int loop = 0; while (strcmp(allSpellList[loop], "0")) { - uint32 spell = atol((char*)allSpellList[loop++]); + uint32 spell = std::stoul((char*)allSpellList[loop++]); if (m_session->GetPlayer()->HasSpell(spell)) continue; @@ -2345,7 +2345,7 @@ bool ChatHandler::HandleLearnAllGMCommand(char* /*args*/) uint16 gmSpellIter = 0; while (strcmp(gmSpellList[gmSpellIter], "0")) { - uint32 spell = atol((char*)gmSpellList[gmSpellIter++]); + uint32 spell = std::stoul((char*)gmSpellList[gmSpellIter++]); SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, m_session->GetPlayer())) diff --git a/src/game/ChatCommands/debugcmds.cpp b/src/game/ChatCommands/debugcmds.cpp index 53fb5ad69..bfdcc6410 100644 --- a/src/game/ChatCommands/debugcmds.cpp +++ b/src/game/ChatCommands/debugcmds.cpp @@ -354,7 +354,7 @@ bool ChatHandler::HandleDebugGetLootRecipientCommand(char* /*args*/) bool ChatHandler::HandleDebugSendQuestInvalidMsgCommand(char* args) { - uint32 msg = atol(args); + uint32 msg = std::stoul(args); m_session->GetPlayer()->SendCanTakeQuestResponse(msg); return true; } diff --git a/src/game/MotionGenerators/PathFinder.cpp b/src/game/MotionGenerators/PathFinder.cpp index 90c3cf075..0a45ec253 100644 --- a/src/game/MotionGenerators/PathFinder.cpp +++ b/src/game/MotionGenerators/PathFinder.cpp @@ -39,7 +39,7 @@ PathFinder::PathFinder(const Unit* owner) : DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::PathInfo for %u \n", m_sourceUnit->GetGUIDLow()); uint32 mapId = m_sourceUnit->GetMapId(); - if (MMAP::MMapFactory::IsPathfindingEnabled(mapId)) + if (MMAP::MMapFactory::IsPathfindingEnabled(mapId, owner)) { MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager(); m_navMesh = mmap->GetNavMesh(mapId); diff --git a/src/game/Object/Creature.cpp b/src/game/Object/Creature.cpp index 15dafe4dc..b81ec7a0b 100644 --- a/src/game/Object/Creature.cpp +++ b/src/game/Object/Creature.cpp @@ -1810,17 +1810,26 @@ void Creature::SetLootStatus(CreatureLootStatus status) } } -// return true if this creature is tapped by the player or by a member of his group. -bool Creature::IsTappedBy(Player const* player) const +// simple tap system return true if player or his group tapped the creature +// TODO:: this is semi correct. For group situation need more work but its not a big issue +bool Creature::IsTappedBy(Player* plr) const { - if (player == GetOriginalLootRecipient()) - return true; + if (Player* recipient = GetLootRecipient()) + { + if (recipient == plr) + return true; - Group const* playerGroup = player->GetGroup(); - if (!playerGroup || playerGroup != GetGroupLootRecipient()) // if we dont have a group we arent the recipient - return false; // if creature doesnt have group bound it means it was solo killed by someone else - - return true; + if (Group* grp = recipient->GetGroup()) + { + if (Group* plrGroup = plr->GetGroup()) + { + if (plrGroup == grp) + return true; + } + } + return false; + } + return false; } SpellEntry const* Creature::ReachWithSpellAttack(Unit* pVictim) diff --git a/src/game/Object/Creature.h b/src/game/Object/Creature.h index 283a2b85e..507d86fd2 100644 --- a/src/game/Object/Creature.h +++ b/src/game/Object/Creature.h @@ -66,6 +66,7 @@ enum CreatureFlagsExtra CREATURE_EXTRA_FLAG_MMAP_FORCE_DISABLE = 0x00004000, // creature is forced to NOT use MMaps CREATURE_EXTRA_FLAG_WALK_IN_WATER = 0x00008000, // creature is forced to walk in water even it can swim CREATURE_EXTRA_FLAG_HAVE_NO_SWIM_ANIMATION = 0x00010000, // we have to not set "swim" animation or creature will have "no animation" + CREATURE_EXTRA_FLAG_NO_MELEE = 0x00020000, // creature can't melee }; // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform @@ -561,7 +562,7 @@ class Creature : public Unit bool IsImmuneToSpell(SpellEntry const* spellInfo, bool castOnSelf) override; bool IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectIndex index, bool castOnSelf) const override; void SetLootStatus(CreatureLootStatus status); - bool IsTappedBy(Player const* player) const; + bool IsTappedBy(Player* plr) const; bool IsElite() const { diff --git a/src/game/Object/GameObject.cpp b/src/game/Object/GameObject.cpp index cfaa0fbd2..c212bb9a7 100644 --- a/src/game/Object/GameObject.cpp +++ b/src/game/Object/GameObject.cpp @@ -79,6 +79,10 @@ GameObject::GameObject() : WorldObject(), m_groupLootTimer = 0; m_groupLootId = 0; m_lootGroupRecipientId = 0; + + m_isInUse = false; + m_reStockTimer = 0; + m_despawnTimer = 0; } GameObject::~GameObject() @@ -1951,6 +1955,7 @@ void GameObject::SetLootRecipient(Unit* pUnit) { m_lootRecipientGuid.Clear(); m_lootGroupRecipientId = 0; + ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); // needed to be sure tapping status is updated return; } @@ -1964,6 +1969,8 @@ void GameObject::SetLootRecipient(Unit* pUnit) // set group for group existed case including if player will leave group at loot time if (Group* group = player->GetGroup()) { m_lootGroupRecipientId = group->GetId(); } + + ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); // needed to be sure tapping status is updated } float GameObject::GetObjectBoundingRadius() const @@ -2402,6 +2409,15 @@ float GameObject::GetInteractionDistance() } } +void GameObject::SetInUse(bool use) +{ + m_isInUse = use; + if (use) + SetGoState(GO_STATE_ACTIVE); + else + SetGoState(GO_STATE_READY); +} + uint32 GameObject::GetScriptId() { return sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) ? sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) : sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, GetEntry()); diff --git a/src/game/Object/GameObject.h b/src/game/Object/GameObject.h index f5b9be0a3..5fcb14ad6 100644 --- a/src/game/Object/GameObject.h +++ b/src/game/Object/GameObject.h @@ -749,6 +749,8 @@ class GameObject : public WorldObject void AddUniqueUse(Player* player); void AddUse() { ++m_useTimes; } + bool IsInUse() const { return m_isInUse; } + void SetInUse(bool use); uint32 GetUseCount() const { return m_useTimes; } uint32 GetUniqueUseCount() const { return m_UniqueUsers.size(); } diff --git a/src/game/Object/Object.cpp b/src/game/Object/Object.cpp index dd9c20089..539214129 100644 --- a/src/game/Object/Object.cpp +++ b/src/game/Object/Object.cpp @@ -800,7 +800,7 @@ bool Object::LoadValues(const char* data) int index; for (iter = tokens.begin(), index = 0; index < m_valuesCount; ++iter, ++index) { - m_uint32Values[index] = atol((*iter).c_str()); + m_uint32Values[index] = std::stoul((*iter).c_str()); } return true; @@ -1119,6 +1119,16 @@ void Object::MarkForClientUpdate() } } +void Object::ForceValuesUpdateAtIndex(uint32 index) +{ + m_changedValues[index] = true; + if (m_inWorld && !m_objectUpdated) + { + AddToClientUpdateList(); + m_objectUpdated = true; + } +} + WorldObject::WorldObject() : #ifdef ENABLE_ELUNA elunaEvents(NULL), diff --git a/src/game/Object/Object.h b/src/game/Object/Object.h index c01568ddd..6320bc6e4 100644 --- a/src/game/Object/Object.h +++ b/src/game/Object/Object.h @@ -258,6 +258,7 @@ class Object void SetGuidValue(uint16 index, ObjectGuid const& value) { SetUInt64Value(index, value.GetRawValue()); } void SetStatFloatValue(uint16 index, float value); void SetStatInt32Value(uint16 index, int32 value); + void ForceValuesUpdateAtIndex(uint32 index); void ApplyModUInt32Value(uint16 index, int32 val, bool apply); void ApplyModInt32Value(uint16 index, int32 val, bool apply); diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index 89515f6f8..4e7bf76cd 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -191,7 +191,7 @@ void PlayerTaxi::LoadTaxiMask(const char* data) (index < TaxiMaskSize) && (iter != tokens.end()); ++iter, ++index) { // load and set bits only for existing taxi nodes - m_taximask[index] = sTaxiNodesMask[index] & uint8(atol((*iter).c_str())); + m_taximask[index] = sTaxiNodesMask[index] & uint8(std::stoul((*iter).c_str())); } } @@ -218,7 +218,7 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, Team for (Tokens::iterator iter = tokens.begin(); iter != tokens.end(); ++iter) { - uint32 node = uint32(atol(iter->c_str())); + uint32 node = std::stoul(iter->c_str()); AddTaxiDestination(node); } @@ -2358,23 +2358,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameo { if (uint32(go->GetGoType()) == gameobject_type || gameobject_type == MAX_GAMEOBJECT_TYPE) { - float maxdist; - switch (go->GetGoType()) - { - // TODO: find out how the client calculates the maximal usage distance to spellless working - // gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number - case GAMEOBJECT_TYPE_GUILD_BANK: - case GAMEOBJECT_TYPE_MAILBOX: - maxdist = 10.0f; - break; - case GAMEOBJECT_TYPE_FISHINGHOLE: - maxdist = 20.0f + CONTACT_DISTANCE; // max spell range - break; - default: - maxdist = INTERACTION_DISTANCE; - break; - } - + float maxdist = go->GetInteractionDistance(); if (go->IsWithinDistInMap(this, maxdist) && go->isSpawned()) return go; @@ -5543,6 +5527,10 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step) if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return false; + SkillStatusData& skillStatus = itr->second; + if (skillStatus.uState == SKILL_DELETED) + return false; + uint16 field = itr->second.pos / 2; uint8 offset = itr->second.pos & 1; // itr->second.pos % 2 @@ -15349,7 +15337,7 @@ void Player::_LoadIntoDataField(const char* data, uint32 startOffset, uint32 cou uint32 index; for (iter = tokens.begin(), index = 0; index < count; ++iter, ++index) { - m_uint32Values[startOffset + index] = atol((*iter).c_str()); + m_uint32Values[startOffset + index] = std::stoul((*iter).c_str()); } } diff --git a/src/game/Object/Unit.cpp b/src/game/Object/Unit.cpp index dbf321230..cbf01517b 100644 --- a/src/game/Object/Unit.cpp +++ b/src/game/Object/Unit.cpp @@ -2076,36 +2076,40 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) // This seems to reduce the victims time until next attack if your attack was parried if (damageInfo->TargetState == VICTIMSTATE_PARRY) { - // Get attack timers - float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); - float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); - // Reduce attack time - if (pVictim->haveOffhandWeapon() && offtime < basetime) + if (pVictim->GetTypeId() != TYPEID_UNIT || + !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY_HASTEN)) { - float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f; - float percent60 = 3.0f * percent20; - if (offtime > percent20 && offtime <= percent60) + // Get attack timers + float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); + float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); + // Reduce attack time + if (pVictim->haveOffhandWeapon() && offtime < basetime) { - pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); + float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f; + float percent60 = 3.0f * percent20; + if (offtime > percent20 && offtime <= percent60) + { + pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20)); + } + else if (offtime > percent60) + { + offtime -= 2.0f * percent20; + pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); + } } - else if (offtime > percent60) + else { - offtime -= 2.0f * percent20; - pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime)); - } - } - else - { - float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20f; - float percent60 = 3.0f * percent20; - if (basetime > percent20 && basetime <= percent60) - { - pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); - } - else if (basetime > percent60) - { - basetime -= 2.0f * percent20; - pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); + float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20f; + float percent60 = 3.0f * percent20; + if (basetime > percent20 && basetime <= percent60) + { + pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20)); + } + else if (basetime > percent60) + { + basetime -= 2.0f * percent20; + pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime)); + } } } } @@ -10736,9 +10740,9 @@ void CharmInfo::LoadPetActionBar(const std::string& data) for (iter = tokens.begin(), index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++iter, ++index) { // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion - uint8 type = (uint8)atol((*iter).c_str()); + uint8 type = (uint8)std::stoul((*iter).c_str()); ++iter; - uint32 action = atol((*iter).c_str()); + uint32 action = std::stoul((*iter).c_str()); PetActionBar[index].SetActionAndType(action, ActiveStates(type)); diff --git a/src/game/Object/Unit.h b/src/game/Object/Unit.h index 5cb45d069..c14030a7e 100644 --- a/src/game/Object/Unit.h +++ b/src/game/Object/Unit.h @@ -791,6 +791,7 @@ class MovementInfo void ChangeOrientation(float o) { pos.o = o; } void ChangePosition(float x, float y, float z, float o) { pos.x = x; pos.y = y; pos.z = z; pos.o = o; } void UpdateTime(uint32 _time) { time = _time; } + uint32 GetTime(){ return time; } struct JumpInfo { diff --git a/src/game/Server/DBCEnums.h b/src/game/Server/DBCEnums.h index 75b257b68..9cdf69669 100644 --- a/src/game/Server/DBCEnums.h +++ b/src/game/Server/DBCEnums.h @@ -465,11 +465,12 @@ enum TotemCategoryType // SummonProperties.dbc, col 1 == Group (m_control) enum SummonPropGroup { - SUMMON_PROP_GROUP_WILD = 0, - SUMMON_PROP_GROUP_FRIENDLY = 1, - SUMMON_PROP_GROUP_PETS = 2, - SUMMON_PROP_GROUP_CONTROLLABLE = 3, - SUMMON_PROP_GROUP_VEHICLE = 4 + SUMMON_PROP_GROUP_WILD = 0, + SUMMON_PROP_GROUP_FRIENDLY = 1, + SUMMON_PROP_GROUP_PETS = 2, + SUMMON_PROP_GROUP_CONTROLLABLE = 3, + SUMMON_PROP_GROUP_VEHICLE = 4, + SUMMON_PROP_GROUP_UNCONTROLLABLE_VEHICLE = 5 }; // SummonProperties.dbc, col 2 == FactionId (m_faction) diff --git a/src/game/Server/WorldSession.cpp b/src/game/Server/WorldSession.cpp index c311b5c73..b877c78b0 100644 --- a/src/game/Server/WorldSession.cpp +++ b/src/game/Server/WorldSession.cpp @@ -103,7 +103,7 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 m_muteTime(mute_time), _player(NULL), m_Socket(sock), _security(sec), _accountId(id), m_expansion(expansion), _logoutTime(0), m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_playerSave(false), m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(sObjectMgr.GetIndexForLocale(locale)), - m_latency(0), m_tutorialState(TUTORIALDATA_UNCHANGED) + m_latency(0), m_clientTimeDelay(0), m_tutorialState(TUTORIALDATA_UNCHANGED) { if (sock) { diff --git a/src/game/Server/WorldSession.h b/src/game/Server/WorldSession.h index a701b5162..9d6ff0183 100644 --- a/src/game/Server/WorldSession.h +++ b/src/game/Server/WorldSession.h @@ -462,6 +462,7 @@ class WorldSession m_latency = latency; } void SetClientTimeDelay(uint32 delay) { m_clientTimeDelay = delay; } + void ResetClientTimeDelay() { m_clientTimeDelay = 0; } uint32 getDialogStatus(Player* pPlayer, Object* questgiver, uint32 defstatus); public: // opcodes handlers @@ -1015,10 +1016,10 @@ class WorldSession LocaleConstant m_sessionDbcLocale; int m_sessionDbLocaleIndex; uint32 m_latency; + uint32 m_clientTimeDelay; AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; uint32 m_Tutorials[8]; TutorialDataState m_tutorialState; - uint32 m_clientTimeDelay; AddonsList m_addonsList; ACE_Based::LockedQueue _recvQueue; }; diff --git a/src/game/Server/WorldSocket.cpp b/src/game/Server/WorldSocket.cpp index 8356ea66e..857f816b0 100644 --- a/src/game/Server/WorldSocket.cpp +++ b/src/game/Server/WorldSocket.cpp @@ -1051,17 +1051,18 @@ int WorldSocket::HandlePing(WorldPacket& recvPacket) // critical section { - ACE_GUARD_RETURN(LockType, Guard, m_SessionLock, -1); - if (m_Session) + { m_Session->SetLatency(latency); + m_Session->ResetClientTimeDelay(); + } else { sLog.outError("WorldSocket::HandlePing: peer sent CMSG_PING, " "but is not authenticated or got recently kicked," " address = %s", GetRemoteAddress().c_str()); - return -1; + return false; } } diff --git a/src/game/WorldHandlers/GridMap.cpp b/src/game/WorldHandlers/GridMap.cpp index 87972d449..db31b3de5 100644 --- a/src/game/WorldHandlers/GridMap.cpp +++ b/src/game/WorldHandlers/GridMap.cpp @@ -58,6 +58,7 @@ GridMap::GridMap() m_gridGetHeight = &GridMap::getHeightFromFlat; m_V9 = NULL; m_V8 = NULL; + memset(m_holes, 0, sizeof(m_holes)); // Liquid data m_liquidType = 0; @@ -205,6 +206,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/) return true; } +bool GridMap::loadHolesData(FILE* in, uint32 offset, uint32 size) +{ + if (fseek(in, offset, SEEK_SET) != 0) + return false; + + if (fread(&m_holes, sizeof(m_holes), 1, in) != 1) + return false; + return true; +} + bool GridMap::loadGridMapLiquidData(FILE* in, uint32 offset, uint32 /*size*/) { GridMapLiquidHeader header; @@ -255,10 +266,22 @@ float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const return m_gridHeight; } +bool GridMap::isHole(int row, int col) const +{ + int cellRow = row / 8; // 8 squares per cell + int cellCol = col / 8; + int holeRow = row % 8 / 2; + int holeCol = (col - (cellCol * 8)) / 2; + + uint16 hole = m_holes[cellRow][cellCol]; + + return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0; +} + float GridMap::getHeightFromFloat(float x, float y) const { if (!m_V8 || !m_V9) - return m_gridHeight; + return INVALID_HEIGHT_VALUE; x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); @@ -270,6 +293,9 @@ float GridMap::getHeightFromFloat(float x, float y) const x_int &= (MAP_RESOLUTION - 1); y_int &= (MAP_RESOLUTION - 1); + if (isHole(x_int, y_int)) + return INVALID_HEIGHT_VALUE; + // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid // +--------------> X // | h1-------h2 Coordinates is: diff --git a/src/game/WorldHandlers/GridMap.h b/src/game/WorldHandlers/GridMap.h index 3bb9bc023..de477addd 100644 --- a/src/game/WorldHandlers/GridMap.h +++ b/src/game/WorldHandlers/GridMap.h @@ -126,7 +126,8 @@ struct GridMapLiquidData class GridMap { private: - + + uint16 m_holes[16][16]; uint32 m_flags; // Area data @@ -163,6 +164,8 @@ class GridMap bool loadAreaData(FILE* in, uint32 offset, uint32 size); bool loadHeightData(FILE* in, uint32 offset, uint32 size); bool loadGridMapLiquidData(FILE* in, uint32 offset, uint32 size); + bool loadHolesData(FILE* in, uint32 offset, uint32 size); + bool isHole(int row, int col) const; // Get height functions and pointers typedef float(GridMap::*pGetHeightPtr)(float x, float y) const; diff --git a/src/game/WorldHandlers/MiscHandler.cpp b/src/game/WorldHandlers/MiscHandler.cpp index 6af687720..8e72faf49 100644 --- a/src/game/WorldHandlers/MiscHandler.cpp +++ b/src/game/WorldHandlers/MiscHandler.cpp @@ -84,8 +84,6 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data) DEBUG_LOG("WORLD: Received opcode CMSG_WHO"); // recv_data.hexlike(); - uint32 clientcount = 0; - uint32 level_min, level_max, racemask, classmask, zones_count, str_count; uint32 zoneids[10]; // 10 is client limit std::string player_name, guild_name; @@ -149,9 +147,12 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data) bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST); AccountTypes gmLevelInWhoList = (AccountTypes)sWorld.getConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST); + uint32 matchcount = 0; + uint32 displaycount = 0; + WorldPacket data(SMSG_WHO, 50); // guess size - data << uint32(clientcount); // clientcount place holder, listed count - data << uint32(clientcount); // clientcount place holder, online count + data << uint32(matchcount); // clientcount place holder, listed count + data << uint32(displaycount); // clientcount place holder, online count // TODO: Guard Player map HashMapHolder::MapType& m = sObjectAccessor.GetPlayers(); @@ -250,6 +251,8 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data) if (!s_show) continue; + ++displaycount; + data << pname; // player name data << gname; // guild name data << uint32(lvl); // player level @@ -257,15 +260,13 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recv_data) data << uint32(race); // player race data << uint8(gender); // player gender data << uint32(pzoneid); // player zone id - - // 50 is maximum player count sent to client - if ((++clientcount) == 50) - break; } - uint32 count = m.size(); - data.put(0, clientcount); // insert right count, listed count - data.put(4, count > 50 ? count : clientcount); // insert right count, online count + if (sWorld.getConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS) && matchcount > sWorld.getConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS)) + matchcount = sWorld.getConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS); + + data.put(0, displaycount); // insert right count, count displayed + data.put(4, matchcount); // insert right count, count of matches SendPacket(&data); DEBUG_LOG("WORLD: Send SMSG_WHO Message"); diff --git a/src/game/WorldHandlers/MoveMap.cpp b/src/game/WorldHandlers/MoveMap.cpp index 6e0de02fb..22e60f6ca 100644 --- a/src/game/WorldHandlers/MoveMap.cpp +++ b/src/game/WorldHandlers/MoveMap.cpp @@ -25,6 +25,7 @@ #include "GridMap.h" #include "Log.h" #include "World.h" +#include "Creature.h" #include "MoveMap.h" #include "MoveMapSharedDefines.h" @@ -65,10 +66,30 @@ namespace MMAP delete[] mapList; } - bool MMapFactory::IsPathfindingEnabled(uint32 mapId) + bool MMapFactory::IsPathfindingEnabled(uint32 mapId, const Unit* unit = nullptr) { - return sWorld.getConfig(CONFIG_BOOL_MMAP_ENABLED) - && g_mmapDisabledIds->find(mapId) == g_mmapDisabledIds->end(); + if (!sWorld.getConfig(CONFIG_BOOL_MMAP_ENABLED)) + return false; + + if (unit) + { + // always use mmaps for players + if (unit->GetTypeId() == TYPEID_PLAYER) + return true; + + if (IsPathfindingForceDisabled(unit)) + return false; + + if (IsPathfindingForceEnabled(unit)) + return true; + + // always use mmaps for pets of players (can still be disabled by extra-flag for pet creature) + if (unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->IsPet() && unit->GetOwner() && + unit->GetOwner()->GetTypeId() == TYPEID_PLAYER) + return true; + } + + return g_mmapDisabledIds->find(mapId) == g_mmapDisabledIds->end(); } void MMapFactory::clear() @@ -80,6 +101,34 @@ namespace MMAP g_MMapManager = NULL; } + bool MMapFactory::IsPathfindingForceEnabled(const Unit* unit) + { + if (const Creature* pCreature = dynamic_cast(unit)) + { + if (const CreatureInfo* pInfo = pCreature->GetCreatureInfo()) + { + if (pInfo->ExtraFlags & CREATURE_EXTRA_FLAG_MMAP_FORCE_ENABLE) + return true; + } + } + + return false; + } + + bool MMapFactory::IsPathfindingForceDisabled(const Unit* unit) + { + if (const Creature* pCreature = dynamic_cast(unit)) + { + if (const CreatureInfo* pInfo = pCreature->GetCreatureInfo()) + { + if (pInfo->ExtraFlags & CREATURE_EXTRA_FLAG_MMAP_FORCE_DISABLE) + return true; + } + } + + return false; + } + // ######################## MMapManager ######################## MMapManager::~MMapManager() { diff --git a/src/game/WorldHandlers/MoveMap.h b/src/game/WorldHandlers/MoveMap.h index ce8fd75e5..5c2b04a7a 100644 --- a/src/game/WorldHandlers/MoveMap.h +++ b/src/game/WorldHandlers/MoveMap.h @@ -31,6 +31,8 @@ #include "../../dep/recastnavigation/Detour/Include/DetourNavMesh.h" #include "../../dep/recastnavigation/Detour/Include/DetourNavMeshQuery.h" +class Unit; + // memory management inline void* dtCustomAlloc(int size, dtAllocHint /*hint*/) { @@ -107,7 +109,9 @@ namespace MMAP static MMapManager* createOrGetMMapManager(); static void clear(); static void preventPathfindingOnMaps(const char* ignoreMapIds); - static bool IsPathfindingEnabled(uint32 mapId); + static bool IsPathfindingEnabled(uint32 mapId, const Unit* unit); + static bool IsPathfindingForceEnabled(const Unit* unit); + static bool IsPathfindingForceDisabled(const Unit* unit); }; } diff --git a/src/game/WorldHandlers/MovementHandler.cpp b/src/game/WorldHandlers/MovementHandler.cpp index fa2172434..5dd7f0a84 100644 --- a/src/game/WorldHandlers/MovementHandler.cpp +++ b/src/game/WorldHandlers/MovementHandler.cpp @@ -38,6 +38,8 @@ #include "MapPersistentStateMgr.h" #include "ObjectMgr.h" +#define MOVEMENT_PACKET_TIME_DELAY 0 + void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recv_data*/) { DEBUG_LOG("WORLD: got MSG_MOVE_WORLDPORT_ACK."); @@ -595,7 +597,9 @@ bool WorldSession::VerifyMovementInfo(MovementInfo const& movementInfo, ObjectGu void WorldSession::HandleMoverRelocation(MovementInfo& movementInfo) { - movementInfo.UpdateTime(WorldTimer::getMSTime()); + if (m_clientTimeDelay == 0) + m_clientTimeDelay = WorldTimer::getMSTime() - movementInfo.GetTime(); + movementInfo.UpdateTime(movementInfo.GetTime() + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY); Unit* mover = _player->GetMover(); diff --git a/src/game/WorldHandlers/ScriptMgr.cpp b/src/game/WorldHandlers/ScriptMgr.cpp index 8c6047ad7..2c62dc036 100644 --- a/src/game/WorldHandlers/ScriptMgr.cpp +++ b/src/game/WorldHandlers/ScriptMgr.cpp @@ -702,7 +702,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename) } break; } - case SCRIPT_COMMAND_SEND_AI_EVENT_AROUND: // 35 + case SCRIPT_COMMAND_SEND_AI_EVENT: // 35 { if (tmp.sendAIEvent.eventType >= MAXIMAL_AI_EVENT_EVENTAI) { @@ -717,7 +717,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename) { if (tmp.moveDynamic.maxDist < tmp.moveDynamic.minDist) { - sLog.outErrorDb("Table `%s` has invalid min-dist (datalong2 = %u) less than max-dist (datalon = %u) in SCRIPT_COMMAND_MOVE_DYNAMIC for script id %u", tablename, tmp.moveDynamic.minDist, tmp.moveDynamic.maxDist, tmp.id); + sLog.outErrorDb("Table `%s` has invalid min-dist (datalong2 = %u) less than max-dist (datalong = %u) in SCRIPT_COMMAND_MOVE_DYNAMIC for script id %u", tablename, tmp.moveDynamic.minDist, tmp.moveDynamic.maxDist, tmp.id); continue; } break; @@ -736,7 +736,36 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename) } break; } - case SCRIPT_COMMAND_CHANGE_ENTRY: // 39 + case SCRIPT_COMMAND_SET_FLY: // 39 + case SCRIPT_COMMAND_DESPAWN_GO: // 40 + case SCRIPT_COMMAND_RESPAWN: // 41 + break; + case SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS: // 42 + { + if (tmp.textId[0] < 0 || tmp.textId[1] < 0 || tmp.textId[2] < 0) + { + sLog.outErrorDb("Table `%s` has invalid equipment slot (dataint = %u, dataint2 = %u, dataint3 = %u) in SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS for script id %u", tablename, tmp.textId[0], tmp.textId[1], tmp.textId[2], tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_RESET_GO: // 43 + break; + case SCRIPT_COMMAND_UPDATE_TEMPLATE: // 44 + { + if (!sCreatureStorage.LookupEntry(tmp.updateTemplate.newTemplate)) + { + sLog.outErrorDb("Table `%s` uses nonexistent creature entry %u in SCRIPT_COMMAND_UPDATE_TEMPLATE for script id %u.", tablename, tmp.updateTemplate.newTemplate, tmp.id); + continue; + } + if (tmp.updateTemplate.newFactionTeam != 0 && tmp.updateTemplate.newFactionTeam != 1) + { + sLog.outErrorDb("Table `%s` uses nonexistent faction team %u in SCRIPT_COMMAND_UPDATE_TEMPLATE for script id %u.", tablename, tmp.updateTemplate.newFactionTeam, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_CHANGE_ENTRY: // 45 { if (tmp.changeEntry.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.changeEntry.creatureEntry)) { @@ -1048,15 +1077,24 @@ bool ScriptAction::GetScriptProcessTargets(WorldObject* pOrigSource, WorldObject if (m_script->IsCreatureBuddy()) { - Creature* pCreatureBuddy = NULL; + Creature* pCreatureBuddy = nullptr; - MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->buddyEntry, true, false, m_script->searchRadiusOrGuid, true); - MaNGOS::CreatureLastSearcher searcher(pCreatureBuddy, u_check); + if (m_script->data_flags & SCRIPT_FLAG_BUDDY_IS_DESPAWNED) + { + MaNGOS::AllCreaturesOfEntryInRangeCheck u_check(pSearcher, m_script->buddyEntry, m_script->searchRadiusOrGuid); + MaNGOS::CreatureLastSearcher searcher(pCreatureBuddy, u_check); + Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadiusOrGuid); + } + else + { + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->buddyEntry, true, false, m_script->searchRadiusOrGuid, true); + MaNGOS::CreatureLastSearcher searcher(pCreatureBuddy, u_check); - if (m_script->data_flags & SCRIPT_FLAG_BUDDY_IS_PET) - { Cell::VisitWorldObjects(pSearcher, searcher, m_script->searchRadiusOrGuid); } - else // Normal Creature - { Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadiusOrGuid); } + if (m_script->data_flags & SCRIPT_FLAG_BUDDY_IS_PET) + Cell::VisitWorldObjects(pSearcher, searcher, m_script->searchRadiusOrGuid); + else // Normal Creature + Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadiusOrGuid); + } pBuddy = pCreatureBuddy; @@ -1894,55 +1932,80 @@ bool ScriptAction::HandleScriptStep() } return terminateResult; } - case SCRIPT_COMMAND_SEND_AI_EVENT_AROUND: // 35 + case SCRIPT_COMMAND_SEND_AI_EVENT: // 35 { if (LogIfNotCreature(pSource)) return false; if (LogIfNotUnit(pTarget)) break; - ((Creature*)pSource)->AI()->SendAIEventAround(AIEventType(m_script->sendAIEvent.eventType), (Unit*)pTarget, 0, float(m_script->sendAIEvent.radius)); + // if radius is provided send AI event around + if (m_script->sendAIEvent.radius) + ((Creature*)pSource)->AI()->SendAIEventAround(AIEventType(m_script->sendAIEvent.eventType), (Unit*)pTarget, 0, float(m_script->sendAIEvent.radius)); + // else if no radius and target is creature send AI event to target + else if (pTarget->GetTypeId() == TYPEID_UNIT) + ((Creature*)pSource)->AI()->SendAIEvent(AIEventType(m_script->sendAIEvent.eventType), nullptr, (Creature*)pTarget); break; } - case SCRIPT_COMMAND_TURN_TO: // 36 + case SCRIPT_COMMAND_TURN_TO: // 36 { - if (LogIfNotUnit(pSource)) - { break; } + if (LogIfNotCreature(pSource)) + return false; + Creature* pCSource = static_cast(pSource); + if (!pTarget) + { + sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command _SET_FACING (%u): No target found.", m_table, m_script->id, m_script->command); + return false; + } + if (m_script->turnTo.targetId) + { + float x, y, z, o; + if (pCSource->GetMotionMaster()->empty() || !pCSource->GetMotionMaster()->top()->GetResetPosition(*pCSource, x, y, z, o)) + pCSource->GetRespawnCoord(x, y, z, &o); + pCSource->SetFacingTo(o); - ((Unit*)pSource)->SetFacingTo(pSource->GetAngle(pTarget)); + if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL && !pCSource->IsInCombat()) + pCSource->SetTargetGuid(ObjectGuid()); + } + else + { + pCSource->SetFacingToObject(pTarget); + if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL && !LogIfNotUnit(pTarget) && !pCSource->IsInCombat()) + pCSource->SetTargetGuid(pTarget->GetObjectGuid()); + } break; } case SCRIPT_COMMAND_MOVE_DYNAMIC: // 37 { - //if (LogIfNotCreature(pSource)) - // return false; - //if (LogIfNotUnit(pTarget)) - // return false; + if (LogIfNotCreature(pSource)) + return false; + if (LogIfNotUnit(pTarget)) + return false; - //float x, y, z; - //if (m_script->moveDynamic.maxDist == 0) // Move to pTarget - //{ - // if (pTarget == pSource) - // { - // sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, _MOVE_DYNAMIC called with maxDist == 0, but resultingSource == resultingTarget (== %s)", m_table, m_script->id, pSource->GetGuidStr().c_str()); - // break; - // } - // pTarget->GetContactPoint(pSource, x, y, z); - //} - //else // Calculate position - //{ - // float orientation; - // if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) - // orientation = pSource->GetOrientation() + m_script->o + 2 * M_PI_F; - // else - // orientation = m_script->o; + float x, y, z; + if (m_script->moveDynamic.maxDist == 0) // Move to pTarget + { + if (pTarget == pSource) + { + sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, _MOVE_DYNAMIC called with maxDist == 0, but resultingSource == resultingTarget (== %s)", m_table, m_script->id, pSource->GetGuidStr().c_str()); + break; + } + pTarget->GetContactPoint(pSource, x, y, z); + } + else // Calculate position + { + float orientation; + if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) + orientation = pSource->GetOrientation() + m_script->o + 2 * M_PI_F; + else + orientation = m_script->o; - // pSource->GetRandomPoint(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), m_script->moveDynamic.maxDist, x, y, z, - // m_script->moveDynamic.minDist, (orientation == 0.0f ? NULL : &orientation)); - // z = std::max(z, pTarget->GetPositionZ()); - // pSource->UpdateAllowedPositionZ(x, y, z); - //} - //((Creature*)pSource)->GetMotionMaster()->MovePoint(1, x, y, z); + pSource->GetRandomPoint(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), m_script->moveDynamic.maxDist, x, y, z, + m_script->moveDynamic.minDist, (orientation == 0.0f ? nullptr : &orientation)); + z = std::max(z, pTarget->GetPositionZ()); + pSource->UpdateAllowedPositionZ(x, y, z); + } + ((Creature*)pSource)->GetMotionMaster()->MovePoint(1, x, y, z); break; } case SCRIPT_COMMAND_SEND_MAIL: // 38 @@ -1962,7 +2025,98 @@ bool ScriptAction::HandleScriptStep() MailDraft(m_script->sendMail.mailTemplateId).SendMailTo(static_cast(pTarget), sender, MAIL_CHECK_MASK_HAS_BODY, deliverDelay); break; } - case SCRIPT_COMMAND_CHANGE_ENTRY: // 39 + case SCRIPT_COMMAND_SET_FLY: // 39 + { + if (LogIfNotCreature(pSource)) + break; + + // enable / disable the fly anim flag + if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) + { + if (m_script->fly.fly) + pSource->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + else + pSource->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + } + + ((Creature*)pSource)->SetLevitate(!!m_script->fly.fly); + break; + } + case SCRIPT_COMMAND_DESPAWN_GO: // 40 + { + if (LogIfNotGameObject(pTarget)) + break; + + // ToDo: Change this to pGo->ForcedDespawn() when function is implemented! + ((GameObject*)pTarget)->SetLootState(GO_JUST_DEACTIVATED); + break; + } + case SCRIPT_COMMAND_RESPAWN: // 41 + { + if (LogIfNotCreature(pTarget)) + break; + + ((Creature*)pTarget)->Respawn(); + break; + } + case SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS: // 42 + { + if (LogIfNotCreature(pSource)) + return false; + + Creature* pCSource = static_cast(pSource); + // reset default + if (m_script->setEquipment.resetDefault) + { + pCSource->LoadEquipment(pCSource->GetCreatureInfo()->EquipmentTemplateId, true); + break; + } + + // main hand + if (m_script->textId[0] >= 0) + pCSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, m_script->textId[0]); + + // off hand + if (m_script->textId[1] >= 0) + pCSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, m_script->textId[1]); + + // ranged + if (m_script->textId[2] >= 0) + pCSource->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, m_script->textId[2]); + break; + } + case SCRIPT_COMMAND_RESET_GO: // 43 + { + if (LogIfNotGameObject(pTarget)) + break; + + GameObject* pGoTarget = static_cast(pTarget); + switch (pGoTarget->GetGoType()) + { + case GAMEOBJECT_TYPE_DOOR: + case GAMEOBJECT_TYPE_BUTTON: + pGoTarget->ResetDoorOrButton(); + break; + default: + sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for gameobject(buddyEntry: %u). Gameobject is not a door or button", m_table, m_script->id, m_script->command, m_script->buddyEntry); + break; + } + break; + } + case SCRIPT_COMMAND_UPDATE_TEMPLATE: // 44 + { + if (LogIfNotCreature(pSource)) + return false; + + Creature* pCSource = static_cast(pSource); + + if (pCSource->GetEntry() != m_script->updateTemplate.newTemplate) + pCSource->UpdateEntry(m_script->updateTemplate.newTemplate, m_script->updateTemplate.newFactionTeam ? HORDE : ALLIANCE); + else + sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u failed. Source already has specified creature entry.", m_table, m_script->id, m_script->command); + break; + } + case SCRIPT_COMMAND_CHANGE_ENTRY: // 45 { if (LogIfNotCreature(pSource)) { break; } diff --git a/src/game/WorldHandlers/ScriptMgr.h b/src/game/WorldHandlers/ScriptMgr.h index 43bf75883..7709b67be 100644 --- a/src/game/WorldHandlers/ScriptMgr.h +++ b/src/game/WorldHandlers/ScriptMgr.h @@ -132,7 +132,7 @@ enum DBScriptCommand // resSource, resTar SCRIPT_COMMAND_XP_USER = 33, // source or target with Player, datalong = bool (0=off, 1=on) SCRIPT_COMMAND_TERMINATE_COND = 34, // datalong = condition_id, datalong2 = if != 0 then quest_id of quest that will be failed for player's group if the script is terminated // data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL terminate when condition is false ELSE terminate when condition is true - SCRIPT_COMMAND_SEND_AI_EVENT_AROUND = 35, // resSource = Creature, resTarget = Unit + SCRIPT_COMMAND_SEND_AI_EVENT = 35, // resSource = Creature, resTarget = Unit // datalong = AIEventType // datalong2 = radius SCRIPT_COMMAND_TURN_TO = 36, // resSource = Unit, resTarget = Unit/none @@ -145,8 +145,20 @@ enum DBScriptCommand // resSource, resTar SCRIPT_COMMAND_SEND_MAIL = 38, // resSource WorldObject, can be NULL, resTarget Player // datalong: Send mailTemplateId from resSource (if provided) to player resTarget // datalong2: AlternativeSenderEntry. Use as sender-Entry + SCRIPT_COMMAND_SET_FLY = 39, // resSource = Creature + // datalong = bool 0=off, 1=on + // data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL set/unset byte flag UNIT_BYTE1_FLAG_FLY_ANIM // dataint1: Delay (>= 0) in Seconds - SCRIPT_COMMAND_CHANGE_ENTRY = 39, // resSource = Creature, datalong=creature entry + SCRIPT_COMMAND_DESPAWN_GO = 40, // resTarget = GameObject + SCRIPT_COMMAND_RESPAWN = 41, // resSource = Creature. Requires SCRIPT_FLAG_BUDDY_IS_DESPAWNED to find dead or despawned targets + SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS = 42, // resSource = Creature + // datalong = resetDefault: bool 0=false, 1=true + // dataint = main hand slot; dataint2 = off hand slot; dataint3 = ranged slot + SCRIPT_COMMAND_RESET_GO = 43, // resTarget = GameObject + SCRIPT_COMMAND_UPDATE_TEMPLATE = 44, // resSource = Creature + // datalong = new Creature entry + // datalong2 = Alliance(0) Horde(1), other values throw error + SCRIPT_COMMAND_CHANGE_ENTRY = 45, // resSource = Creature, datalong=creature entry // dataint1 = entry }; @@ -161,8 +173,9 @@ enum ScriptInfoDataFlags SCRIPT_FLAG_COMMAND_ADDITIONAL = 0x08, // command dependend SCRIPT_FLAG_BUDDY_BY_GUID = 0x10, // take the buddy by guid SCRIPT_FLAG_BUDDY_IS_PET = 0x20, // buddy is a pet + SCRIPT_FLAG_BUDDY_IS_DESPAWNED = 0X40, // buddy is dead or despawned }; -#define MAX_SCRIPT_FLAG_VALID (2 * SCRIPT_FLAG_BUDDY_IS_PET - 1) +#define MAX_SCRIPT_FLAG_VALID (2 * SCRIPT_FLAG_BUDDY_IS_DESPAWNED - 1) struct ScriptInfo { @@ -371,7 +384,7 @@ struct ScriptInfo uint32 failQuest; // datalong2 } terminateCond; - struct // SCRIPT_COMMAND_SEND_AI_EVENT_AROUND (35) + struct // SCRIPT_COMMAND_SEND_AI_EVENT (35) { uint32 eventType; // datalong uint32 radius; // datalong2 @@ -395,7 +408,30 @@ struct ScriptInfo uint32 altSender; // datalong2; } sendMail; - struct // SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL (23) + struct // SCRIPT_COMMAND_SET_FLY (39) + { + uint32 fly; // datalong + uint32 empty; // datalong2 + } fly; + + // datalong unsed // SCRIPT_COMMAND_DESPAWN_GO (40) + // datalong unsed // SCRIPT_COMMAND_RESPAWN (41) + + struct // SCRIPT_COMMAND_SET_EQUIPMENT_SLOTS (42) + { + uint32 resetDefault; // datalong + uint32 empty; // datalong2 + } setEquipment; + + // datalong unsed // SCRIPT_COMMAND_RESET_GO (43) + + struct // SCRIPT_COMMAND_UPDATE_TEMPLATE (44) + { + uint32 newTemplate; // datalong + uint32 newFactionTeam; // datalong2 + } updateTemplate; + + struct // SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL (45) { uint32 creatureEntry; // datalong uint32 empty1; // datalong2 @@ -443,6 +479,8 @@ struct ScriptInfo case SCRIPT_COMMAND_CLOSE_DOOR: case SCRIPT_COMMAND_ACTIVATE_OBJECT: case SCRIPT_COMMAND_GO_LOCK_STATE: + case SCRIPT_COMMAND_DESPAWN_GO: + case SCRIPT_COMMAND_RESET_GO: return false; default: return true; @@ -464,6 +502,7 @@ struct ScriptInfo case SCRIPT_COMMAND_TERMINATE_COND: case SCRIPT_COMMAND_TURN_TO: case SCRIPT_COMMAND_MOVE_DYNAMIC: + case SCRIPT_COMMAND_SET_FLY: return true; default: return false; diff --git a/src/game/WorldHandlers/Spell.cpp b/src/game/WorldHandlers/Spell.cpp index bc78525bc..82bf4e8ab 100644 --- a/src/game/WorldHandlers/Spell.cpp +++ b/src/game/WorldHandlers/Spell.cpp @@ -6154,24 +6154,29 @@ SpellCastResult Spell::CheckCast(bool strict) case SPELL_EFFECT_LEAP: case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER: { - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEffect->GetRadiusIndex())); - float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation()); - float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation()); - // teleport a bit above terrain level to avoid falling below it - float fz = m_caster->GetMap()->GetHeight(m_caster->GetPhaseMask(), fx, fy, m_caster->GetPositionZ()); - if (fz <= INVALID_HEIGHT) // note: this also will prevent use effect in instances without vmaps height enabled - return SPELL_FAILED_TRY_AGAIN; + if (!m_caster || m_caster->IsTaxiFlying()) + return SPELL_FAILED_NOT_ON_TAXI; - float caster_pos_z = m_caster->GetPositionZ(); - // Control the caster to not climb or drop when +-fz > 8 - if (!(fz <= caster_pos_z + 8 && fz >= caster_pos_z - 8)) - return SPELL_FAILED_TRY_AGAIN; + // Blink has leap first and then removing of auras with root effect + // need further research with this + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if (!spellEffect) + break; + + if (spellEffect->Effect != SPELL_EFFECT_LEAP) + { + if (m_caster->hasUnitState(UNIT_STAT_ROOT)) + return SPELL_FAILED_ROOTED; + } - // not allow use this effect at battleground until battleground start if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + // not allow use this effect at battleground until battleground start if (BattleGround const* bg = ((Player*)m_caster)->GetBattleGround()) if (bg->GetStatus() != STATUS_IN_PROGRESS) return SPELL_FAILED_TRY_AGAIN; + } + break; } case SPELL_EFFECT_STEAL_BENEFICIAL_BUFF: diff --git a/src/game/WorldHandlers/SpellAuras.cpp b/src/game/WorldHandlers/SpellAuras.cpp index dbc530d06..0ea9620c1 100644 --- a/src/game/WorldHandlers/SpellAuras.cpp +++ b/src/game/WorldHandlers/SpellAuras.cpp @@ -2976,7 +2976,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real) { //AreaTableEntry const* area = GetAreaEntryByAreaID(target->GetAreaId()); - //// Dalaran restricted flight zone (recheck before apply unmount) + //// Dalaran restricstruct boss_freyted flight zone (recheck before apply unmount) //if (area && target->GetTypeId() == TYPEID_PLAYER && (area->flags & AREA_FLAG_CANNOT_FLY) && // ((Player*)target)->IsFreeFlying() && !((Player*)target)->isGameMaster()) //{ diff --git a/src/game/WorldHandlers/SpellEffects.cpp b/src/game/WorldHandlers/SpellEffects.cpp index 88cf11518..1c8ce8365 100644 --- a/src/game/WorldHandlers/SpellEffects.cpp +++ b/src/game/WorldHandlers/SpellEffects.cpp @@ -5384,14 +5384,13 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect) if (summon_prop->Group == SUMMON_PROP_GROUP_PETS && prop_id != 1562) { DoSummonPet(effect); - return; } // Expected Amount: TODO - there are quite some exceptions (like totems, engineering dragonlings..) uint32 amount = damage > 0 ? damage : 1; // basepoints of SUMMON_PROP_GROUP_VEHICLE is often a spellId, set amount to 1 - if (summon_prop->Group == SUMMON_PROP_GROUP_VEHICLE) + if (summon_prop->Group == SUMMON_PROP_GROUP_VEHICLE || summon_prop->Group == SUMMON_PROP_GROUP_UNCONTROLLABLE_VEHICLE || summon_prop->Group == SUMMON_PROP_GROUP_CONTROLLABLE) amount = 1; // Get casting object @@ -5552,6 +5551,7 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect) break; } case SUMMON_PROP_GROUP_VEHICLE: + case SUMMON_PROP_GROUP_UNCONTROLLABLE_VEHICLE: { summonResult = DoSummonVehicle(summonPositions, summon_prop, effect, level); break; @@ -5750,17 +5750,30 @@ bool Spell::DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntr if (m_duration > 0) spawnCreature->SetDuration(m_duration); + CreatureInfo const* cInfo = spawnCreature->GetCreatureInfo(); + // spawnCreature->SetName(""); // generated by client spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid()); - spawnCreature->SetPowerType(POWER_MANA); - spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->NpcFlags); - + spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, cInfo->UnitFlags); + spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, cInfo->NpcFlags); + spawnCreature->setFaction(m_caster->getFaction()); spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0); spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid()); spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - spawnCreature->InitStatsForLevel(level, m_caster); - spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false); + spawnCreature->InitStatsForLevel(level); + + if (CharmInfo* charmInfo = spawnCreature->GetCharmInfo()) + { + charmInfo->SetPetNumber(pet_number, false); + + if (spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)) + charmInfo->SetReactState(REACT_PASSIVE); + else if ((cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_NO_MELEE) || petType == PROTECTOR_PET) + charmInfo->SetReactState(REACT_DEFENSIVE); + else + charmInfo->SetReactState(REACT_AGGRESSIVE); + } m_caster->AddGuardian(spawnCreature); } @@ -10721,24 +10734,159 @@ void Spell::EffectBlock(SpellEffectEntry const* /*effect*/) void Spell::EffectLeapForward(SpellEffectEntry const* effect) { - if (unitTarget->IsTaxiFlying()) - return; + float dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->rangeIndex)); + const float IN_OR_UNDER_LIQUID_RANGE = 0.8f; // range to make player under liquid or on liquid surface from liquid level - if (m_spellInfo->rangeIndex == SPELL_RANGE_IDX_SELF_ONLY) + G3D::Vector3 prevPos, nextPos; + float orientation = unitTarget->GetOrientation(); + + prevPos.x = unitTarget->GetPositionX(); + prevPos.y = unitTarget->GetPositionY(); + prevPos.z = unitTarget->GetPositionZ(); + + float groundZ = prevPos.z; + + // falling case + if (!unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), prevPos.x, prevPos.y, groundZ, 3.0f) && unitTarget->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLING)) { - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(effect->GetRadiusIndex())); + nextPos.x = prevPos.x + dist * cos(orientation); + nextPos.y = prevPos.y + dist * sin(orientation); + nextPos.z = prevPos.z - 2.0f; // little hack to avoid the impression to go up when teleporting instead of continue to fall. This value may need some tweak - // before caster - float fx, fy, fz; - unitTarget->GetClosePoint(fx, fy, fz, unitTarget->GetObjectBoundingRadius(), dis); - float ox, oy, oz; - unitTarget->GetPosition(ox, oy, oz); + // + GridMapLiquidData liquidData; + if (unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData)) + { + if (fabs(nextPos.z - liquidData.level) < 10.0f) + nextPos.z = liquidData.level - IN_OR_UNDER_LIQUID_RANGE; + } + else + { + // fix z to ground if near of it + unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, nextPos.z, 10.0f); + } - if (unitTarget->GetMap()->GetHitPosition(ox, oy, oz + 0.5f, fx, fy, fz, unitTarget->GetPhaseMask(), -0.5f)) - unitTarget->UpdateAllowedPositionZ(fx, fy, fz); + // check any obstacle and fix coords + unitTarget->GetMap()->GetHitPosition(prevPos.x, prevPos.y, prevPos.z + 0.5f, nextPos.x, nextPos.y, nextPos.z, unitTarget->GetPhaseMask(), -0.5f); - unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(), unitTarget == m_caster); + // teleport + unitTarget->NearTeleportTo(nextPos.x, nextPos.y, nextPos.z, orientation, unitTarget == m_caster); + + //sLog.outString("Falling BLINK!"); + return; } + + // fix origin position if player was jumping and near of the ground but not in ground + if (fabs(prevPos.z - groundZ) > 0.5f) + prevPos.z = groundZ; + + //check if in liquid + bool isPrevInLiquid = unitTarget->GetMap()->GetTerrain()->IsInWater(prevPos.x, prevPos.y, prevPos.z); + + const float step = 2.0f; // step length before next check slope/edge/water + const float maxSlope = 50.0f; // 50(degree) max seem best value for walkable slope + const float MAX_SLOPE_IN_RADIAN = maxSlope / 180.0f * M_PI_F; + float nextZPointEstimation = 1.0f; + float destx = prevPos.x + dist * cos(orientation); + float desty = prevPos.y + dist * sin(orientation); + const uint32 numChecks = ceil(fabs(dist / step)); + const float DELTA_X = (destx - prevPos.x) / numChecks; + const float DELTA_Y = (desty - prevPos.y) / numChecks; + + for (uint32 i = 1; i < numChecks + 1; ++i) + { + // compute next point average position + nextPos.x = prevPos.x + DELTA_X; + nextPos.y = prevPos.y + DELTA_Y; + nextPos.z = prevPos.z + nextZPointEstimation; + + bool isInLiquid = false; + bool isInLiquidTested = false; + bool isOnGround = false; + GridMapLiquidData liquidData; + + // try fix height for next position + if (!unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, nextPos.z)) + { + // we cant so test if we are on water + if (!unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData)) + { + // not in water and cannot get correct height, maybe flying? + //sLog.outString("Can't get height of point %u, point value %s", i, nextPos.toString().c_str()); + nextPos = prevPos; + break; + } + else + { + isInLiquid = true; + isInLiquidTested = true; + } + } + else + isOnGround = true; // player is on ground + + if (isInLiquid || (!isInLiquidTested && unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData))) + { + if (!isPrevInLiquid && fabs(liquidData.level - prevPos.z) > 2.0f) + { + // on edge of water with difference a bit to high to continue + //sLog.outString("Ground vs liquid edge detected!"); + nextPos = prevPos; + break; + } + + if ((liquidData.level - IN_OR_UNDER_LIQUID_RANGE) > nextPos.z) + nextPos.z = prevPos.z; // we are under water so next z equal prev z + else + nextPos.z = liquidData.level - IN_OR_UNDER_LIQUID_RANGE; // we are on water surface, so next z equal liquid level + + isInLiquid = true; + + float ground = nextPos.z; + if (unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, ground)) + { + if (nextPos.z < ground) + { + nextPos.z = ground; + isOnGround = true; // player is on ground of the water + } + } + } + + //unitTarget->SummonCreature(VISUAL_WAYPOINT, nextPos.x, nextPos.y, nextPos.z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000); + float hitZ = nextPos.z + 1.5f; + if (unitTarget->GetMap()->GetHitPosition(prevPos.x, prevPos.y, prevPos.z + 1.5f, nextPos.x, nextPos.y, hitZ, unitTarget->GetPhaseMask(), -1.0f)) + { + //sLog.outString("Blink collision detected!"); + nextPos = prevPos; + break; + } + + if (isOnGround) + { + // project vector to get only positive value + float ac = fabs(prevPos.z - nextPos.z); + + // compute slope (in radian) + float slope = atan(ac / step); + + // check slope value + if (slope > MAX_SLOPE_IN_RADIAN) + { + //sLog.outString("bad slope detected! %4.2f max %4.2f, ac(%4.2f)", slope * 180 / M_PI_F, maxSlope, ac); + nextPos = prevPos; + break; + } + //sLog.outString("slope is ok! %4.2f max %4.2f, ac(%4.2f)", slope * 180 / M_PI_F, maxSlope, ac); + } + + //sLog.outString("point %u is ok, coords %s", i, nextPos.toString().c_str()); + nextZPointEstimation = (nextPos.z - prevPos.z) / 2.0f; + isPrevInLiquid = isInLiquid; + prevPos = nextPos; + } + + unitTarget->NearTeleportTo(nextPos.x, nextPos.y, nextPos.z, orientation, unitTarget == m_caster); } void Spell::EffectLeapBack(SpellEffectEntry const* effect) @@ -10922,11 +11070,18 @@ void Spell::EffectPlayerPull(SpellEffectEntry const* effect) if (!unitTarget) return; - float dist = unitTarget->GetDistance2d(m_caster); - if (damage && dist > damage) - dist = float(damage); + float x, y, z; + m_caster->GetPosition(x, y, z); - unitTarget->KnockBackFrom(m_caster, -dist, float(effect->EffectMiscValue) / 10); + // move back a bit + x = x - (0.6 * cos(m_caster->GetOrientation() + M_PI_F)); + y = y - (0.6 * sin(m_caster->GetOrientation() + M_PI_F)); + + // Try to normalize Z coord because GetContactPoint do nothing with Z axis + unitTarget->UpdateAllowedPositionZ(x, y, z); + + float speed = m_spellInfo->speed ? m_spellInfo->speed : 27.0f; + unitTarget->GetMotionMaster()->MoveJump(x, y, z, speed, 2.5f); } void Spell::EffectDispelMechanic(SpellEffectEntry const* effect) diff --git a/src/game/WorldHandlers/SpellHandler.cpp b/src/game/WorldHandlers/SpellHandler.cpp index 66a6eed19..90f8ccea2 100644 --- a/src/game/WorldHandlers/SpellHandler.cpp +++ b/src/game/WorldHandlers/SpellHandler.cpp @@ -293,10 +293,13 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recv_data) if (!_player->IsSelfMover()) return; - GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid); + GameObject* obj = _player->GetMap()->GetGameObject(guid); if (!obj) return; + if (!obj->IsWithinDistInMap(_player, obj->GetInteractionDistance())) + return; + // Additional check preventing exploits (ie loot despawned chests) if (!obj->isSpawned()) { diff --git a/src/game/WorldHandlers/WaypointManager.cpp b/src/game/WorldHandlers/WaypointManager.cpp index 971761e1f..d1f74abfe 100644 --- a/src/game/WorldHandlers/WaypointManager.cpp +++ b/src/game/WorldHandlers/WaypointManager.cpp @@ -635,6 +635,6 @@ void WaypointManager::CheckTextsExistance(std::set& ids) { for (WaypointPath::const_iterator pItr = pmItr->second.begin(); pItr != pmItr->second.end(); ++pItr) if (pItr->second.behavior) - CheckWPText(false, pmItr->first, pItr->first, pItr->second.behavior, ids); + CheckWPText(true, pmItr->first, pItr->first, pItr->second.behavior, ids); } } diff --git a/src/game/WorldHandlers/WaypointManager.h b/src/game/WorldHandlers/WaypointManager.h index cddaef135..b0e4a8cb9 100644 --- a/src/game/WorldHandlers/WaypointManager.h +++ b/src/game/WorldHandlers/WaypointManager.h @@ -91,7 +91,7 @@ class WaypointManager WaypointPath* GetDefaultPath(uint32 entry, uint32 lowGuid, WaypointPathOrigin* wpOrigin = NULL) { - WaypointPath* path = NULL; + WaypointPath* path = GetPath(lowGuid); path = GetPath(lowGuid); if (path && wpOrigin) *wpOrigin = PATH_FROM_GUID; diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 87ab2d502..613ce6e8a 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -531,6 +531,7 @@ void World::LoadConfigSettings(bool reload) setConfig(CONFIG_BOOL_ADDON_CHANNEL, "AddonChannel", true); setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "CleanCharacterDB", true); setConfig(CONFIG_BOOL_GRID_UNLOAD, "GridUnload", true); + setConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS, "MaxWhoListReturns", 49); std::string forceLoadGridOnMaps = sConfig.GetStringDefault("LoadAllGridsOnMaps", ""); if (!forceLoadGridOnMaps.empty()) diff --git a/src/game/WorldHandlers/World.h b/src/game/WorldHandlers/World.h index 327fd1769..4d3ee2c9f 100644 --- a/src/game/WorldHandlers/World.h +++ b/src/game/WorldHandlers/World.h @@ -220,6 +220,8 @@ enum eConfigUInt32Values CONFIG_UINT32_MIN_LEVEL_FOR_RAID, CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY, CONFIG_UINT32_RANDOM_BG_RESET_HOUR, + CONFIG_UINT32_MAX_WHOLIST_RETURNS, + CONFIG_UINT32_VALUE_COUNT, // Warden CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY, CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF, @@ -227,8 +229,7 @@ enum eConfigUInt32Values CONFIG_UINT32_WARDEN_CLIENT_BAN_DURATION, CONFIG_UINT32_WARDEN_NUM_MEM_CHECKS, CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS, - CONFIG_UINT32_WARDEN_DB_LOGLEVEL, - CONFIG_UINT32_VALUE_COUNT + CONFIG_UINT32_WARDEN_DB_LOGLEVEL }; /// Configuration elements diff --git a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_garr.cpp b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_garr.cpp index a8b35378d..45f0e91a6 100644 --- a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_garr.cpp +++ b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_garr.cpp @@ -43,11 +43,14 @@ enum SPELL_MAGMASHACKLES = 19496, SPELL_ERUPTION_TRIGGER = 20482, // target script, dispel and permanent immune to banish anywhere on map SPELL_ENRAGE_TRIGGER = 19515, // target script, effect dummy anywhere on map + SPELL_ENRAGE = 19516, // Add spells + SPELL_THRASH = 8876, + SPELL_IMMOLATE = 15733, SPELL_ERUPTION = 19497, SPELL_MASSIVE_ERUPTION = 20483, // TODO possible on death - SPELL_IMMOLATE = 20294, + SPELL_SEPARATION_ANXIETY_BOSSGARR = 23492, // Used if separated too far from Garr }; struct boss_garr : public CreatureScript @@ -184,6 +187,10 @@ struct mob_firesworn : public CreatureScript mob_fireswornAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + + DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_IMMOLATE, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } ScriptedInstance* m_pInstance; @@ -199,6 +206,12 @@ struct mob_firesworn : public CreatureScript m_bExploding = false; } + void JustReachedHome() override + { + DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_IMMOLATE, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { if (!m_bExploding && m_creature->HealthBelowPctDamaged(10, uiDamage)) diff --git a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_golemagg.cpp b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_golemagg.cpp index 68077154a..66c245d45 100644 --- a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_golemagg.cpp +++ b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_golemagg.cpp @@ -43,9 +43,11 @@ enum SPELL_EARTHQUAKE = 19798, SPELL_ENRAGE = 19953, SPELL_GOLEMAGG_TRUST = 20553, + SPELL_DOUBLE_ATTACK = 18943, // Core Rager EMOTE_LOW_HP = -1409002, + SPELL_THRASH = 12787, SPELL_MANGLE = 19820 }; @@ -60,6 +62,7 @@ struct boss_golemagg : public CreatureScript m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); #if defined (WOTLK) || defined (CATA) DoCastSpellIfCan(m_creature, SPELL_MAGMA_SPLASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); #endif } @@ -185,6 +188,9 @@ struct mob_core_rager : public CreatureScript mob_core_ragerAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + + DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } ScriptedInstance* m_pInstance; @@ -208,6 +214,11 @@ struct mob_core_rager : public CreatureScript } } + void JustReachedHome() override + { + DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) diff --git a/src/modules/SD3/scripts/northrend/naxxramas/boss_anubrekhan.cpp b/src/modules/SD3/scripts/northrend/naxxramas/boss_anubrekhan.cpp index ea1b18888..1446b7a80 100644 --- a/src/modules/SD3/scripts/northrend/naxxramas/boss_anubrekhan.cpp +++ b/src/modules/SD3/scripts/northrend/naxxramas/boss_anubrekhan.cpp @@ -43,6 +43,7 @@ enum EMOTE_INSECT_SWARM = -1533154, EMOTE_CORPSE_SCARABS = -1533155, + SPELL_DOUBLE_ATTACK = 18943, SPELL_IMPALE = 28783, // May be wrong spell id. Causes more dmg than I expect SPELL_IMPALE_H = 56090, SPELL_LOCUSTSWARM = 28785, // This is a self buff that triggers the dmg debuff @@ -82,6 +83,9 @@ struct boss_anubrekhan : public CreatureScript m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); m_introDialogue.InitializeDialogueHelper(m_pInstance); m_bHasTaunted = false; + Reset(); + + DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } ScriptedInstance* m_pInstance; @@ -135,6 +139,8 @@ struct boss_anubrekhan : public CreatureScript { if (m_pInstance) m_pInstance->SetData(TYPE_ANUB_REKHAN, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } void MoveInLineOfSight(Unit* pWho) override diff --git a/src/modules/SD3/scripts/northrend/naxxramas/boss_gluth.cpp b/src/modules/SD3/scripts/northrend/naxxramas/boss_gluth.cpp index debab90fc..06fd3f3d3 100644 --- a/src/modules/SD3/scripts/northrend/naxxramas/boss_gluth.cpp +++ b/src/modules/SD3/scripts/northrend/naxxramas/boss_gluth.cpp @@ -32,7 +32,8 @@ enum EMOTE_ZOMBIE = -1533119, EMOTE_BOSS_GENERIC_ENRAGED = -1000006, EMOTE_DECIMATE = -1533152, - + + SPELL_DOUBLE_ATTACK = 19818, SPELL_MORTALWOUND = 54378, // old vanilla spell was 25646, SPELL_DECIMATE = 28374, SPELL_DECIMATE_H = 54426, @@ -66,6 +67,9 @@ struct boss_gluth : public CreatureScript { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + + DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } ScriptedInstance* m_pInstance; @@ -118,6 +122,8 @@ struct boss_gluth : public CreatureScript { if (m_pInstance) m_pInstance->SetData(TYPE_GLUTH, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } void JustSummoned(Creature* pSummoned) override diff --git a/src/modules/SD3/scripts/northrend/naxxramas/boss_maexxna.cpp b/src/modules/SD3/scripts/northrend/naxxramas/boss_maexxna.cpp index ebcd5914d..6c37c9ad2 100644 --- a/src/modules/SD3/scripts/northrend/naxxramas/boss_maexxna.cpp +++ b/src/modules/SD3/scripts/northrend/naxxramas/boss_maexxna.cpp @@ -34,6 +34,8 @@ enum EMOTE_SPRAY = -1533148, EMOTE_BOSS_GENERIC_FRENZY = -1000005, + SPELL_DOUBLE_ATTACK = 19818, + SPELL_WEBWRAP = 28622, SPELL_WEBWRAP_2 = 28673, // purpose unknown @@ -166,6 +168,9 @@ struct boss_maexxna : public CreatureScript { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + + DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } ScriptedInstance* m_pInstance; @@ -204,6 +209,8 @@ struct boss_maexxna : public CreatureScript { if (m_pInstance) m_pInstance->SetData(TYPE_MAEXXNA, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } void JustSummoned(Creature* pSummoned) override diff --git a/src/modules/SD3/scripts/northrend/ulduar/ulduar/boss_freya.cpp b/src/modules/SD3/scripts/northrend/ulduar/ulduar/boss_freya.cpp index 8e480dcc5..2325f7dc4 100644 --- a/src/modules/SD3/scripts/northrend/ulduar/ulduar/boss_freya.cpp +++ b/src/modules/SD3/scripts/northrend/ulduar/ulduar/boss_freya.cpp @@ -211,6 +211,7 @@ struct boss_freya : public CreatureScript uint32 m_uiEpilogueTimer; uint32 m_uiBerserkTimer; + uint32 m_uiDrainEldersTimer; uint32 m_uiAlliesNatureTimer; uint8 m_uiAlliesWaveCount; @@ -244,6 +245,7 @@ struct boss_freya : public CreatureScript m_uiUnstableEnergyTimer = 0; m_uiIronRootsTimer = 0; m_uiGroundTremorTimer = 0; + m_uiDrainEldersTimer = 0; // make the spawn spells random std::random_shuffle(spawnSpellsVector.begin(), spawnSpellsVector.end()); @@ -292,17 +294,26 @@ struct boss_freya : public CreatureScript if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_BRIGHTLEAF)) { if (pElder->IsAlive()) + { pElder->AI()->EnterEvadeMode(); + pElder->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } } if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_IRONBRACH)) { if (pElder->IsAlive()) + { pElder->AI()->EnterEvadeMode(); + pElder->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } } if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_STONEBARK)) { if (pElder->IsAlive()) + { pElder->AI()->EnterEvadeMode(); + pElder->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } } } } @@ -468,7 +479,7 @@ struct boss_freya : public CreatureScript { if (pElder->IsAlive()) { - pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_BRIGHTLEAF_ESSENCE_CHANNEL : SPELL_BRIGHTLEAF_ESSENCE_CHANNEL_H, true); + pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_BRIGHTLEAF_ESSENCE_CHANNEL : SPELL_BRIGHTLEAF_ESSENCE_CHANNEL_H, false, NULL, NULL, m_creature->GetObjectGuid()); pElder->CastSpell(pElder, SPELL_FULL_HEAL, true); m_uiUnstableEnergyTimer = 25000; @@ -479,7 +490,7 @@ struct boss_freya : public CreatureScript { if (pElder->IsAlive()) { - pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_IRONBRANCH_ESSENCE_CHANNEL : SPELL_IRONBRANCH_ESSENCE_CHANNEL_H, true); + pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_IRONBRANCH_ESSENCE_CHANNEL : SPELL_IRONBRANCH_ESSENCE_CHANNEL_H, false, NULL, NULL, m_creature->GetObjectGuid()); pElder->CastSpell(pElder, SPELL_FULL_HEAL, true); m_uiIronRootsTimer = 60000; @@ -490,7 +501,7 @@ struct boss_freya : public CreatureScript { if (pElder->IsAlive()) { - pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_STONEBARK_ESSEMCE_CHANNEL : SPELL_STONEBARK_ESSEMCE_CHANNEL_H, true); + pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_STONEBARK_ESSEMCE_CHANNEL : SPELL_STONEBARK_ESSEMCE_CHANNEL_H, false, NULL, NULL, m_creature->GetObjectGuid()); pElder->CastSpell(pElder, SPELL_FULL_HEAL, true); m_uiGroundTremorTimer = 10000; @@ -507,6 +518,38 @@ struct boss_freya : public CreatureScript DoScriptText(SAY_AGGRO, m_creature); } + // Function that will drain elders after aggro + void DoDrainElders() + { + if (!m_pInstance) + return; + + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_BRIGHTLEAF)) + { + if (pElder->IsAlive()) + { + pElder->CastSpell(pElder, SPELL_DRAINED_OF_POWER, true); + pElder->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_IRONBRACH)) + { + if (pElder->IsAlive()) + { + pElder->CastSpell(pElder, SPELL_DRAINED_OF_POWER, true); + pElder->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_STONEBARK)) + { + if (pElder->IsAlive()) + { + pElder->CastSpell(pElder, SPELL_DRAINED_OF_POWER, true); + pElder->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + } + void UpdateAI(const uint32 uiDiff) override { if (m_uiEpilogueTimer) @@ -540,6 +583,18 @@ struct boss_freya : public CreatureScript m_uiBerserkTimer -= uiDiff; } + // Drain elders after hard mode aggro + if (m_uiDrainEldersTimer) + { + if (m_uiDrainEldersTimer <= uiDiff) + { + DoDrainElders(); + m_uiDrainEldersTimer = 0; + } + else + m_uiDrainEldersTimer -= uiDiff; + } + if (m_uiThreeAlliesTimer) { if (m_uiThreeAlliesTimer <= uiDiff) diff --git a/src/shared/DataStores/DB2FileLoader.cpp b/src/shared/DataStores/DB2FileLoader.cpp index 5a01c5c38..0799152f4 100644 --- a/src/shared/DataStores/DB2FileLoader.cpp +++ b/src/shared/DataStores/DB2FileLoader.cpp @@ -44,9 +44,8 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) data=NULL; } - FILE* f = fopen(filename, "rb"); - if (!f) - { return false; } + FILE * f = fopen(filename, "rb"); + if(!f)return false; if(fread(&header, 4, 1, f) != 1) // Signature { @@ -59,10 +58,10 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) if(header != 0x32424457) { fclose(f); - return false; + return false; //'WDB2' } - if (fread(&recordCount, 4, 1, f) != 1) // Number of records + if(fread(&recordCount,4,1,f)!=1) // Number of records { fclose(f); return false; @@ -70,7 +69,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) EndianConvert(recordCount); - if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields + if(fread(&fieldCount,4,1,f)!=1) // Number of fields { fclose(f); return false; @@ -78,7 +77,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) EndianConvert(fieldCount); - if (fread(&recordSize, 4, 1, f) != 1) // Size of a record + if(fread(&recordSize,4,1,f)!=1) // Size of a record { fclose(f); return false; @@ -86,7 +85,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) EndianConvert(recordSize); - if (fread(&stringSize, 4, 1, f) != 1) // String size + if(fread(&stringSize,4,1,f)!=1) // String size { fclose(f); return false; @@ -153,19 +152,19 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) fieldsOffset = new uint32[fieldCount]; fieldsOffset[0] = 0; - for (uint32 i = 1; i < fieldCount; ++i) + for(uint32 i = 1; i < fieldCount; i++) { fieldsOffset[i] = fieldsOffset[i - 1]; if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields - { fieldsOffset[i] += 1; } + fieldsOffset[i] += 1; else // 4 byte fields (int32/float/strings) - { fieldsOffset[i] += 4; } + fieldsOffset[i] += 4; } - data = new unsigned char[recordSize * recordCount + stringSize]; - stringTable = data + recordSize * recordCount; + data = new unsigned char[recordSize*recordCount+stringSize]; + stringTable = data + recordSize*recordCount; - if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1) + if(fread(data, recordSize * recordCount + stringSize, 1, f) != 1) { fclose(f); return false;