Merge commit 'dbaf88566be7083408fb8324d7886dc3e0a45cc0' into 4.3.4
Conflicts: .gitattributes CONTRIBUTING.md sql/updates/world/2015_05_11_04_world.sql sql/updates/world/2015_05_27_00_world.sql sql/updates/world/2015_05_27_01_world.sql sql/updates/world/2015_06_06_01_world_335.sql src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp src/server/game/Entities/Creature/Creature.cpp src/server/game/Entities/Creature/Creature.h src/server/game/Entities/Object/ObjectGuid.h src/server/game/Entities/Player/Player.cpp src/server/game/Entities/Player/Player.h src/server/game/Entities/Unit/Unit.cpp src/server/game/Entities/Unit/Unit.h src/server/game/Spells/Auras/SpellAuras.cpp src/server/game/Spells/Spell.cpp src/server/game/Spells/SpellMgr.cpp src/server/scripts/Commands/cs_modify.cpp src/server/scripts/Kalimdor/zone_moonglade.cpp src/server/scripts/Spells/spell_hunter.cpp src/server/scripts/Spells/spell_item.cpp src/server/scripts/Spells/spell_rogue.cpp
This commit is contained in:
commit
6dfaec3d97
119 files changed
+3776
-2162
No files matched your search
@@ -17,3 +17,4 @@ endif()
|
||||
# -Wno-narrowing needed to suppress a warning in g3d
|
||||
# -Wno-deprecated-register is needed to suppress 185 gsoap warnings on Unix systems.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-narrowing -Wno-deprecated-register")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1")
|
||||
@@ -7,8 +7,6 @@ else()
|
||||
MESSAGE(STATUS "Detected 32-bit platform")
|
||||
endif()
|
||||
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/platform/settings.cmake")
|
||||
|
||||
if(WIN32)
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/platform/win/settings.cmake")
|
||||
elseif(UNIX)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# set installation prefix
|
||||
if( PREFIX )
|
||||
set(CMAKE_INSTALL_PREFIX "${PREFIX}")
|
||||
endif()
|
||||
|
||||
@@ -46,11 +46,25 @@ using namespace boost::program_options;
|
||||
# define _TRINITY_REALM_CONFIG "authserver.conf"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "ServiceWin32.h"
|
||||
char serviceName[] = "authserver";
|
||||
char serviceLongName[] = "TrinityCore auth service";
|
||||
char serviceDescription[] = "TrinityCore World of Warcraft emulator auth service";
|
||||
/*
|
||||
* -1 - not in service mode
|
||||
* 0 - stopped
|
||||
* 1 - running
|
||||
* 2 - paused
|
||||
*/
|
||||
int m_ServiceStatus = -1;
|
||||
#endif
|
||||
|
||||
bool StartDB();
|
||||
void StopDB();
|
||||
void SignalHandler(const boost::system::error_code& error, int signalNumber);
|
||||
void KeepDatabaseAliveHandler(const boost::system::error_code& error);
|
||||
variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile);
|
||||
variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService);
|
||||
|
||||
boost::asio::io_service _ioService;
|
||||
boost::asio::deadline_timer _dbPingTimer(_ioService);
|
||||
@@ -60,11 +74,21 @@ LoginDatabaseWorkerPool LoginDatabase;
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::string configFile = _TRINITY_REALM_CONFIG;
|
||||
auto vm = GetConsoleArguments(argc, argv, configFile);
|
||||
std::string configService;
|
||||
auto vm = GetConsoleArguments(argc, argv, configFile, configService);
|
||||
// exit if help is enabled
|
||||
if (vm.count("help"))
|
||||
return 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (configService.compare("install") == 0)
|
||||
return WinServiceInstall() == true ? 0 : 1;
|
||||
else if (configService.compare("uninstall") == 0)
|
||||
return WinServiceUninstall() == true ? 0 : 1;
|
||||
else if (configService.compare("run") == 0)
|
||||
WinServiceRun();
|
||||
#endif
|
||||
|
||||
std::string configError;
|
||||
if (!sConfigMgr->LoadInitial(configFile, configError))
|
||||
{
|
||||
@@ -189,26 +213,34 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error)
|
||||
}
|
||||
}
|
||||
|
||||
variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile)
|
||||
variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService)
|
||||
{
|
||||
options_description all("Allowed options");
|
||||
all.add_options()
|
||||
("help,h", "print usage message")
|
||||
("config,c", value<std::string>(&configFile)->default_value(_TRINITY_REALM_CONFIG), "use <arg> as configuration file")
|
||||
;
|
||||
#ifdef _WIN32
|
||||
options_description win("Windows platform specific options");
|
||||
win.add_options()
|
||||
("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]")
|
||||
;
|
||||
|
||||
all.add(win);
|
||||
#endif
|
||||
variables_map variablesMap;
|
||||
try
|
||||
{
|
||||
store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap);
|
||||
notify(variablesMap);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << "\n";
|
||||
}
|
||||
|
||||
if (variablesMap.count("help")) {
|
||||
if (variablesMap.count("help"))
|
||||
std::cout << all << "\n";
|
||||
}
|
||||
|
||||
return variablesMap;
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Player.h"
|
||||
#include "Spell.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "Util.h"
|
||||
@@ -146,15 +147,15 @@ void PetAI::UpdateAI(uint32 diff)
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
|
||||
if (me->GetCharmInfo() && me->GetSpellHistory()->HasGlobalCooldown(spellInfo))
|
||||
continue;
|
||||
|
||||
if (spellInfo->IsPositive())
|
||||
{
|
||||
if (spellInfo->CanBeUsedInCombat())
|
||||
{
|
||||
// check spell cooldown
|
||||
if (me->HasSpellCooldown(spellInfo->Id))
|
||||
// check spell cooldown & school lock
|
||||
if (!me->GetSpellHistory()->IsReady(spellInfo))
|
||||
continue;
|
||||
|
||||
// Check if we're in combat or commanded to attack
|
||||
|
||||
@@ -128,7 +128,7 @@ class UnitAI
|
||||
|
||||
virtual void InitializeAI() { if (!me->isDead()) Reset(); }
|
||||
|
||||
virtual void Reset() { };
|
||||
virtual void Reset() { }
|
||||
|
||||
// Called when unit is charmed
|
||||
virtual void OnCharmed(bool apply) = 0;
|
||||
|
||||
@@ -811,6 +811,7 @@ class RBACData
|
||||
* @return Success or failure (with reason) to grant the permission
|
||||
*
|
||||
* Example Usage:
|
||||
* @code
|
||||
* // previously defined "RBACData* rbac" with proper initialization
|
||||
* uint32 permissionId = 2;
|
||||
* if (rbac->GrantRole(permissionId) == RBAC_IN_DENIED_LIST)
|
||||
@@ -834,6 +835,7 @@ class RBACData
|
||||
* @return Success or failure (with reason) to deny the permission
|
||||
*
|
||||
* Example Usage:
|
||||
* @code
|
||||
* // previously defined "RBACData* rbac" with proper initialization
|
||||
* uint32 permissionId = 2;
|
||||
* if (rbac->DenyRole(permissionId) == RBAC_ID_DOES_NOT_EXISTS)
|
||||
@@ -858,6 +860,7 @@ class RBACData
|
||||
* @return Success or failure (with reason) to remove the permission
|
||||
*
|
||||
* Example Usage:
|
||||
* @code
|
||||
* // previously defined "RBACData* rbac" with proper initialization
|
||||
* uint32 permissionId = 2;
|
||||
* if (rbac->RevokeRole(permissionId) == RBAC_OK)
|
||||
@@ -948,9 +951,6 @@ class RBACData
|
||||
*
|
||||
* Given a list of permissions, gets all the inherited permissions
|
||||
* @param permissions The list of permissions to expand
|
||||
*
|
||||
* @return new list of permissions containing original permissions and
|
||||
* all other pemissions that are linked to the original ones
|
||||
*/
|
||||
void ExpandPermissions(RBACPermissionContainer& permissions);
|
||||
|
||||
|
||||
@@ -890,7 +890,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
|
||||
// (after what time the ratings aren't taken into account when making teams) then
|
||||
// the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
|
||||
// else leave the discard time on 0, this way all ratings will be discarded
|
||||
uint32 discardTime = getMSTime() - sBattlegroundMgr->GetRatingDiscardTimer();
|
||||
// this has to be signed value - when the server starts, this value would be negative and thus overflow
|
||||
int32 discardTime = getMSTime() - sBattlegroundMgr->GetRatingDiscardTimer();
|
||||
|
||||
// we need to find 2 teams which will play next game
|
||||
GroupsQueueType::iterator itr_teams[BG_TEAMS_COUNT];
|
||||
@@ -906,7 +907,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
|
||||
// if group match conditions, then add it to pool
|
||||
if (!(*itr2)->IsInvitedToBGInstanceGUID
|
||||
&& (((*itr2)->ArenaMatchmakerRating >= arenaMinRating && (*itr2)->ArenaMatchmakerRating <= arenaMaxRating)
|
||||
|| (*itr2)->JoinTime < discardTime))
|
||||
|| (int32)(*itr2)->JoinTime < discardTime))
|
||||
{
|
||||
itr_teams[found++] = itr2;
|
||||
team = i;
|
||||
@@ -924,7 +925,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
|
||||
{
|
||||
if (!(*itr3)->IsInvitedToBGInstanceGUID
|
||||
&& (((*itr3)->ArenaMatchmakerRating >= arenaMinRating && (*itr3)->ArenaMatchmakerRating <= arenaMaxRating)
|
||||
|| (*itr3)->JoinTime < discardTime)
|
||||
|| (int32)(*itr3)->JoinTime < discardTime)
|
||||
&& (*itr_teams[0])->ArenaTeamId != (*itr3)->ArenaTeamId)
|
||||
{
|
||||
itr_teams[found++] = itr3;
|
||||
|
||||
@@ -106,7 +106,7 @@ class BattlegroundQueue
|
||||
class SelectionPool
|
||||
{
|
||||
public:
|
||||
SelectionPool(): PlayerCount(0) { };
|
||||
SelectionPool(): PlayerCount(0) { }
|
||||
void Init();
|
||||
bool AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount);
|
||||
bool KickGroup(uint32 size);
|
||||
|
||||
@@ -99,7 +99,7 @@ bool BattlegroundSA::ResetObjs()
|
||||
for (uint8 i = BG_SA_MAXNPC; i < BG_SA_MAXNPC + BG_SA_MAX_GY; i++)
|
||||
DelCreature(i);
|
||||
|
||||
for (uint8 i = 0; i < 6; i++)
|
||||
for (uint8 i = 0; i < MAX_GATES; ++i)
|
||||
GateStatus[i] = BG_SA_GATE_OK;
|
||||
|
||||
if (!AddCreature(BG_SA_NpcEntries[BG_SA_NPC_KANRETHAD], BG_SA_NPC_KANRETHAD, BG_SA_NpcSpawnlocs[BG_SA_NPC_KANRETHAD]))
|
||||
@@ -179,9 +179,6 @@ bool BattlegroundSA::ResetObjs()
|
||||
GetBGObject(BG_SA_TITAN_RELIC)->SetFaction(atF);
|
||||
GetBGObject(BG_SA_TITAN_RELIC)->Refresh();
|
||||
|
||||
for (uint8 i = 0; i <= 5; i++)
|
||||
GateStatus[i] = BG_SA_GATE_OK;
|
||||
|
||||
TotalTime = 0;
|
||||
ShipsStarted = false;
|
||||
|
||||
@@ -221,6 +218,8 @@ bool BattlegroundSA::ResetObjs()
|
||||
GetBGObject(i)->SetFaction(atF);
|
||||
}
|
||||
|
||||
UpdateObjectInteractionFlags();
|
||||
|
||||
for (uint8 i = BG_SA_BOMB; i < BG_SA_MAXOBJ; i++)
|
||||
{
|
||||
if (!AddObject(i, BG_SA_ObjEntries[BG_SA_BOMB], BG_SA_ObjSpawnlocs[i], 0, 0, 0, 0, RESPAWN_ONE_DAY))
|
||||
@@ -481,28 +480,7 @@ void BattlegroundSA::AddPlayer(Player* player)
|
||||
|
||||
SendTransportInit(player);
|
||||
|
||||
if (!ShipsStarted)
|
||||
{
|
||||
if (player->GetTeamId() == Attackers)
|
||||
{
|
||||
//player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
|
||||
if (urand(0, 1))
|
||||
player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
|
||||
else
|
||||
player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
|
||||
|
||||
}
|
||||
else
|
||||
player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->GetTeamId() == Attackers)
|
||||
player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0);
|
||||
else
|
||||
player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
|
||||
}
|
||||
TeleportToEntrancePosition(player);
|
||||
}
|
||||
|
||||
void BattlegroundSA::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*/) { }
|
||||
@@ -533,25 +511,33 @@ void BattlegroundSA::TeleportPlayers()
|
||||
player->ResetAllPowers();
|
||||
player->CombatStopWithPets(true);
|
||||
|
||||
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
|
||||
if (Player* p = ObjectAccessor::FindPlayer(itr->first))
|
||||
p->CastSpell(p, SPELL_PREPARATION, true);
|
||||
player->CastSpell(player, SPELL_PREPARATION, true);
|
||||
|
||||
if (player->GetTeamId() == Attackers)
|
||||
{
|
||||
//player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
|
||||
if (urand(0, 1))
|
||||
player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
|
||||
else
|
||||
player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
|
||||
}
|
||||
else
|
||||
player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
|
||||
TeleportToEntrancePosition(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundSA::TeleportToEntrancePosition(Player* player)
|
||||
{
|
||||
if (player->GetTeamId() == Attackers)
|
||||
{
|
||||
if (!ShipsStarted)
|
||||
{
|
||||
player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
|
||||
|
||||
if (urand(0, 1))
|
||||
player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
|
||||
else
|
||||
player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
|
||||
}
|
||||
else
|
||||
player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0);
|
||||
}
|
||||
else
|
||||
player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
|
||||
}
|
||||
|
||||
void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker /*= NULL*/)
|
||||
{
|
||||
if (GameObject* go = obj->ToGameObject())
|
||||
@@ -628,6 +614,8 @@ void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateObjectInteractionFlags();
|
||||
}
|
||||
else
|
||||
break;
|
||||
@@ -711,7 +699,7 @@ WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveYard(Player* player)
|
||||
safeloc = BG_SA_GYEntries[BG_SA_DEFENDER_LAST_GY];
|
||||
|
||||
closest = sWorldSafeLocsStore.LookupEntry(safeloc);
|
||||
nearest = std::sqrt((closest->x - x)*(closest->x - x) + (closest->y - y)*(closest->y - y) + (closest->z - z)*(closest->z - z));
|
||||
nearest = player->GetExactDistSq(closest->x, closest->y, closest->z);
|
||||
|
||||
for (uint8 i = BG_SA_RIGHT_CAPTURABLE_GY; i < BG_SA_MAX_GY; i++)
|
||||
{
|
||||
@@ -719,7 +707,7 @@ WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveYard(Player* player)
|
||||
continue;
|
||||
|
||||
ret = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]);
|
||||
dist = std::sqrt((ret->x - x)*(ret->x - x) + (ret->y - y)*(ret->y - y) + (ret->z - z)*(ret->z - z));
|
||||
dist = player->GetExactDistSq(ret->x, ret->y, ret->z);
|
||||
if (dist < nearest)
|
||||
{
|
||||
closest = ret;
|
||||
@@ -738,23 +726,66 @@ void BattlegroundSA::SendTime()
|
||||
UpdateWorldState(BG_SA_TIMER_SEC_DECS, ((end_of_round%60000)%10000)/1000);
|
||||
}
|
||||
|
||||
bool BattlegroundSA::CanInteractWithObject(uint32 objectId)
|
||||
{
|
||||
switch (objectId)
|
||||
{
|
||||
case BG_SA_TITAN_RELIC:
|
||||
if (GateStatus[BG_SA_ANCIENT_GATE] != BG_SA_GATE_DESTROYED || GateStatus[BG_SA_YELLOW_GATE] != BG_SA_GATE_DESTROYED)
|
||||
return false;
|
||||
// no break
|
||||
case BG_SA_CENTRAL_FLAG:
|
||||
if (GateStatus[BG_SA_RED_GATE] != BG_SA_GATE_DESTROYED && GateStatus[BG_SA_PURPLE_GATE] != BG_SA_GATE_DESTROYED)
|
||||
return false;
|
||||
// no break
|
||||
case BG_SA_LEFT_FLAG:
|
||||
case BG_SA_RIGHT_FLAG:
|
||||
if (GateStatus[BG_SA_GREEN_GATE] != BG_SA_GATE_DESTROYED && GateStatus[BG_SA_BLUE_GATE] != BG_SA_GATE_DESTROYED)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundSA::UpdateObjectInteractionFlags(uint32 objectId)
|
||||
{
|
||||
if (GameObject* go = GetBGObject(objectId))
|
||||
{
|
||||
if (CanInteractWithObject(objectId))
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
else
|
||||
go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundSA::UpdateObjectInteractionFlags()
|
||||
{
|
||||
for (uint8 i = BG_SA_CENTRAL_FLAG; i <= BG_SA_LEFT_FLAG; ++i)
|
||||
UpdateObjectInteractionFlags(i);
|
||||
UpdateObjectInteractionFlags(BG_SA_TITAN_RELIC);
|
||||
}
|
||||
|
||||
void BattlegroundSA::EventPlayerClickedOnFlag(Player* source, GameObject* go)
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case 191307:
|
||||
case 191308:
|
||||
if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED)
|
||||
if (CanInteractWithObject(BG_SA_LEFT_FLAG))
|
||||
CaptureGraveyard(BG_SA_LEFT_CAPTURABLE_GY, source);
|
||||
break;
|
||||
case 191305:
|
||||
case 191306:
|
||||
if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED)
|
||||
if (CanInteractWithObject(BG_SA_RIGHT_FLAG))
|
||||
CaptureGraveyard(BG_SA_RIGHT_CAPTURABLE_GY, source);
|
||||
break;
|
||||
case 191310:
|
||||
case 191309:
|
||||
if ((GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) && (GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED))
|
||||
if (CanInteractWithObject(BG_SA_CENTRAL_FLAG))
|
||||
CaptureGraveyard(BG_SA_CENTRAL_CAPTURABLE_GY, source);
|
||||
break;
|
||||
default:
|
||||
@@ -856,10 +887,7 @@ void BattlegroundSA::TitanRelicActivated(Player* clicker)
|
||||
if (!clicker)
|
||||
return;
|
||||
|
||||
if (GateStatus[BG_SA_ANCIENT_GATE] == BG_SA_GATE_DESTROYED &&
|
||||
GateStatus[BG_SA_YELLOW_GATE] == BG_SA_GATE_DESTROYED &&
|
||||
(GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED) &&
|
||||
(GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED))
|
||||
if (CanInteractWithObject(BG_SA_TITAN_RELIC))
|
||||
{
|
||||
if (clicker->GetTeamId() == Attackers)
|
||||
{
|
||||
|
||||
@@ -620,6 +620,7 @@ class BattlegroundSA : public Battleground
|
||||
* -Teleport all players to good location
|
||||
*/
|
||||
void TeleportPlayers();
|
||||
void TeleportToEntrancePosition(Player* player);
|
||||
/**
|
||||
* \brief Called on start and between the two round
|
||||
* -Update faction of all vehicle
|
||||
@@ -627,6 +628,11 @@ class BattlegroundSA : public Battleground
|
||||
void OverrideGunFaction();
|
||||
/// Set selectable or not demolisher, called on battle start, when boats arrive to dock
|
||||
void DemolisherStartState(bool start);
|
||||
/// Checks if a player can interact with the given object
|
||||
bool CanInteractWithObject(uint32 objectId);
|
||||
/// Updates interaction flags of specific objects
|
||||
void UpdateObjectInteractionFlags(uint32 objectId);
|
||||
void UpdateObjectInteractionFlags();
|
||||
/**
|
||||
* \brief Called when a gate is destroy
|
||||
* -Give honor to player witch destroy it
|
||||
|
||||
@@ -184,7 +184,7 @@ class Channel
|
||||
void DeVoice(ObjectGuid guid1, ObjectGuid guid2);
|
||||
void JoinNotify(ObjectGuid guid); // invisible notify
|
||||
void LeaveNotify(ObjectGuid guid); // invisible notify
|
||||
void SetOwnership(bool ownership) { _ownership = ownership; };
|
||||
void SetOwnership(bool ownership) { _ownership = ownership; }
|
||||
static void CleanOldChannelsInDB();
|
||||
|
||||
private:
|
||||
|
||||
@@ -704,8 +704,8 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
|
||||
if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
|
||||
{
|
||||
if (pathLength[entry->path] < entry->index + 1)
|
||||
pathLength[entry->path] = entry->index + 1;
|
||||
if (pathLength[entry->PathID] < entry->NodeIndex + 1)
|
||||
pathLength[entry->PathID] = entry->NodeIndex + 1;
|
||||
}
|
||||
// Set path length
|
||||
sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used
|
||||
@@ -714,7 +714,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
// fill data
|
||||
for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
|
||||
if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
|
||||
sTaxiPathNodesByPath[entry->path].set(entry->index, entry);
|
||||
sTaxiPathNodesByPath[entry->PathID].set(entry->NodeIndex, entry);
|
||||
|
||||
// Initialize global taxinodes mask
|
||||
// include existed nodes that have at least single not spell base (scripted) path
|
||||
|
||||
@@ -30,13 +30,7 @@
|
||||
#include <vector>
|
||||
|
||||
// Structures using to access raw DBC data and required packing to portability
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct AchievementEntry
|
||||
{
|
||||
@@ -2230,17 +2224,17 @@ struct TaxiPathEntry
|
||||
|
||||
struct TaxiPathNodeEntry
|
||||
{
|
||||
// 0 m_ID
|
||||
uint32 path; // 1 m_PathID
|
||||
uint32 index; // 2 m_NodeIndex
|
||||
uint32 mapid; // 3 m_ContinentID
|
||||
float x; // 4 m_LocX
|
||||
float y; // 5 m_LocY
|
||||
float z; // 6 m_LocZ
|
||||
uint32 actionFlag; // 7 m_flags
|
||||
uint32 delay; // 8 m_delay
|
||||
uint32 arrivalEventID; // 9 m_arrivalEventID
|
||||
uint32 departureEventID; // 10 m_departureEventID
|
||||
// 0 ID
|
||||
uint32 PathID; // 1
|
||||
uint32 NodeIndex; // 2
|
||||
uint32 MapID; // 3
|
||||
float LocX; // 4
|
||||
float LocY; // 5
|
||||
float LocZ; // 6
|
||||
uint32 Flags; // 7
|
||||
uint32 Delay; // 8
|
||||
uint32 ArrivalEventID; // 9
|
||||
uint32 DepartureEventID; // 10
|
||||
};
|
||||
|
||||
struct TotemCategoryEntry
|
||||
@@ -2492,12 +2486,7 @@ struct WorldStateUI
|
||||
};
|
||||
*/
|
||||
|
||||
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
struct VectorArray
|
||||
{
|
||||
|
||||
@@ -408,6 +408,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
|
||||
joinData.result = LFG_JOIN_RANDOM_COOLDOWN;
|
||||
else if (dungeons.empty())
|
||||
joinData.result = LFG_JOIN_NOT_MEET_REQS;
|
||||
else if (player->HasAura(9454)) // check Freeze debuff
|
||||
joinData.result = LFG_JOIN_NOT_MEET_REQS;
|
||||
else if (grp)
|
||||
{
|
||||
if (grp->GetMembersCount() > MAXGROUPSIZE)
|
||||
@@ -427,6 +429,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
|
||||
joinData.result = LFG_JOIN_PARTY_RANDOM_COOLDOWN;
|
||||
else if (plrg->InBattleground() || plrg->InArena() || plrg->InBattlegroundQueue())
|
||||
joinData.result = LFG_JOIN_USING_BG_SYSTEM;
|
||||
else if (plrg->HasAura(9454)) // check Freeze debuff
|
||||
joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS;
|
||||
++memberCount;
|
||||
players.insert(plrg->GetGUID());
|
||||
}
|
||||
@@ -1283,6 +1287,8 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
|
||||
error = LFG_TELEPORTERROR_IN_VEHICLE;
|
||||
else if (player->GetCharmGUID())
|
||||
error = LFG_TELEPORTERROR_CHARMING;
|
||||
else if (player->HasAura(9454)) // check Freeze debuff
|
||||
error = LFG_TELEPORTERROR_INVALID_LOCATION;
|
||||
else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance
|
||||
{
|
||||
uint32 mapid = dungeon->map;
|
||||
|
||||
@@ -150,8 +150,6 @@ m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(
|
||||
for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
m_spells[i] = 0;
|
||||
|
||||
m_CreatureSpellCooldowns.clear();
|
||||
m_CreatureCategoryCooldowns.clear();
|
||||
DisableReputationGain = false;
|
||||
|
||||
m_SightDistance = sWorld->getFloatConfig(CONFIG_SIGHT_MONSTER);
|
||||
@@ -1390,9 +1388,6 @@ bool Creature::CanStartAttack(Unit const* who, bool force) const
|
||||
if (IsCivilian())
|
||||
return false;
|
||||
|
||||
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC))
|
||||
return false;
|
||||
|
||||
// Do not attack non-combat pets
|
||||
if (who->GetTypeId() == TYPEID_UNIT && who->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET)
|
||||
return false;
|
||||
@@ -2167,83 +2162,6 @@ void Creature::SetInCombatWithZone()
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time)
|
||||
{
|
||||
m_CreatureSpellCooldowns[spell_id] = end_time;
|
||||
}
|
||||
|
||||
void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time)
|
||||
{
|
||||
m_CreatureCategoryCooldowns[category] = apply_time;
|
||||
}
|
||||
|
||||
void Creature::AddCreatureSpellCooldown(uint32 spellid)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
|
||||
if (!spellInfo)
|
||||
return;
|
||||
|
||||
uint32 cooldown = spellInfo->GetRecoveryTime();
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellid, SPELLMOD_COOLDOWN, cooldown);
|
||||
|
||||
if (cooldown)
|
||||
_AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILLISECONDS);
|
||||
|
||||
if (spellInfo->GetCategory())
|
||||
_AddCreatureCategoryCooldown(spellInfo->GetCategory(), time(NULL));
|
||||
}
|
||||
|
||||
bool Creature::HasCategoryCooldown(uint32 spell_id) const
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
|
||||
CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
|
||||
return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILLISECONDS)) > time(NULL));
|
||||
}
|
||||
|
||||
uint32 Creature::GetCreatureSpellCooldownDelay(uint32 spellId) const
|
||||
{
|
||||
CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spellId);
|
||||
time_t t = time(NULL);
|
||||
return uint32(itr != m_CreatureSpellCooldowns.end() && itr->second > t ? itr->second - t : 0);
|
||||
}
|
||||
|
||||
bool Creature::HasSpellCooldown(uint32 spell_id) const
|
||||
{
|
||||
CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id);
|
||||
return (itr != m_CreatureSpellCooldowns.end() && itr->second > time(NULL)) || HasCategoryCooldown(spell_id);
|
||||
}
|
||||
|
||||
void Creature::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
|
||||
{
|
||||
time_t curTime = time(NULL);
|
||||
for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
{
|
||||
if (m_spells[i] == 0)
|
||||
continue;
|
||||
|
||||
uint32 unSpellId = m_spells[i];
|
||||
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId);
|
||||
|
||||
// Not send cooldown for this spells
|
||||
if (spellInfo->IsCooldownStartedOnEvent())
|
||||
continue;
|
||||
|
||||
if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
|
||||
continue;
|
||||
|
||||
if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetCreatureSpellCooldownDelay(unSpellId) < unTimeMs)
|
||||
{
|
||||
_AddCreatureSpellCooldown(unSpellId, curTime + unTimeMs/IN_MILLISECONDS);
|
||||
if (UnitAI* ai = GetAI())
|
||||
ai->SpellInterrupted(unSpellId, unTimeMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Creature::HasSpell(uint32 spellID) const
|
||||
{
|
||||
uint8 i;
|
||||
|
||||
@@ -174,12 +174,7 @@ struct CreatureTemplate
|
||||
// Benchmarked: Faster than std::map (insert/find)
|
||||
typedef std::unordered_map<uint32, CreatureTemplate> CreatureTemplateContainer;
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
// Defines base stats for creatures (used to calculate HP/mana/armor/attackpower/rangedattackpower/all damage).
|
||||
struct CreatureBaseStats
|
||||
@@ -314,12 +309,7 @@ enum ChatType
|
||||
CHAT_TYPE_END = 255
|
||||
};
|
||||
|
||||
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
// `creature_addon` table
|
||||
struct CreatureAddon
|
||||
@@ -422,8 +412,6 @@ struct TrainerSpellData
|
||||
TrainerSpell const* Find(uint32 spell_id) const;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, time_t> CreatureSpellCooldowns;
|
||||
|
||||
// max different by z coordinate for creature aggro reaction
|
||||
#define CREATURE_Z_ATTACK_RANGE 3
|
||||
|
||||
|
||||
@@ -289,6 +289,16 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 /*phase
|
||||
SetGoAnimProgress(animprogress);
|
||||
break;
|
||||
}
|
||||
|
||||
if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(guidlow))
|
||||
{
|
||||
if (addon->InvisibilityValue)
|
||||
{
|
||||
m_invisibility.AddFlag(addon->invisibilityType);
|
||||
m_invisibility.AddValue(addon->invisibilityType, addon->InvisibilityValue);
|
||||
}
|
||||
}
|
||||
|
||||
LastUsedScriptID = GetGOInfo()->ScriptId;
|
||||
AIM_Initialize();
|
||||
|
||||
|
||||
@@ -585,6 +585,15 @@ struct GameObjectLocale
|
||||
StringVector CastBarCaption;
|
||||
};
|
||||
|
||||
// `gameobject_addon` table
|
||||
struct GameObjectAddon
|
||||
{
|
||||
InvisibilityType invisibilityType;
|
||||
uint32 InvisibilityValue;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<ObjectGuid::LowType, GameObjectAddon> GameObjectAddonContainer;
|
||||
|
||||
// client side GO show states
|
||||
enum GOState
|
||||
{
|
||||
|
||||
@@ -208,8 +208,6 @@ enum ItemUpdateState
|
||||
ITEM_REMOVED = 3
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SPELLS 5
|
||||
|
||||
bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto);
|
||||
|
||||
class Item : public Object
|
||||
|
||||
@@ -1194,61 +1194,6 @@ bool Object::PrintIndexError(uint32 index, bool set) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Position::operator==(Position const &a)
|
||||
{
|
||||
return (G3D::fuzzyEq(a.m_positionX, m_positionX) &&
|
||||
G3D::fuzzyEq(a.m_positionY, m_positionY) &&
|
||||
G3D::fuzzyEq(a.m_positionZ, m_positionZ) &&
|
||||
G3D::fuzzyEq(a.m_orientation, m_orientation));
|
||||
}
|
||||
|
||||
bool Position::HasInLine(WorldObject const* target, float width) const
|
||||
{
|
||||
if (!HasInArc(float(M_PI), target))
|
||||
return false;
|
||||
width += target->GetObjectSize();
|
||||
float angle = GetRelativeAngle(target);
|
||||
return std::fabs(std::sin(angle)) * GetExactDist2d(target->GetPositionX(), target->GetPositionY()) < width;
|
||||
}
|
||||
|
||||
std::string Position::ToString() const
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
|
||||
{
|
||||
float x, y, z, o;
|
||||
buf >> x >> y >> z >> o;
|
||||
streamer.m_pos->Relocate(x, y, z, o);
|
||||
return buf;
|
||||
}
|
||||
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
|
||||
{
|
||||
float x, y, z;
|
||||
streamer.m_pos->GetPosition(x, y, z);
|
||||
buf << x << y << z;
|
||||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
|
||||
{
|
||||
float x, y, z;
|
||||
buf >> x >> y >> z;
|
||||
streamer.m_pos->Relocate(x, y, z);
|
||||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
|
||||
{
|
||||
float x, y, z, o;
|
||||
streamer.m_pos->GetPosition(x, y, z, o);
|
||||
buf << x << y << z << o;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void MovementInfo::OutDebug()
|
||||
{
|
||||
TC_LOG_DEBUG("misc", "MOVEMENT INFO");
|
||||
@@ -1614,92 +1559,6 @@ bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float m
|
||||
return distsq < maxdist * maxdist;
|
||||
}
|
||||
|
||||
void Position::RelocateOffset(const Position & offset)
|
||||
{
|
||||
m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI)));
|
||||
m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation()));
|
||||
m_positionZ = GetPositionZ() + offset.GetPositionZ();
|
||||
SetOrientation(GetOrientation() + offset.GetOrientation());
|
||||
}
|
||||
|
||||
void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const
|
||||
{
|
||||
float dx = endPos.GetPositionX() - GetPositionX();
|
||||
float dy = endPos.GetPositionY() - GetPositionY();
|
||||
|
||||
retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation());
|
||||
retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation());
|
||||
retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ();
|
||||
retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation());
|
||||
}
|
||||
|
||||
Position Position::GetPositionWithOffset(Position const& offset) const
|
||||
{
|
||||
Position ret(*this);
|
||||
ret.RelocateOffset(offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
float Position::GetAngle(const Position* obj) const
|
||||
{
|
||||
if (!obj)
|
||||
return 0;
|
||||
|
||||
return GetAngle(obj->GetPositionX(), obj->GetPositionY());
|
||||
}
|
||||
|
||||
// Return angle in range 0..2*pi
|
||||
float Position::GetAngle(const float x, const float y) const
|
||||
{
|
||||
float dx = x - GetPositionX();
|
||||
float dy = y - GetPositionY();
|
||||
|
||||
float ang = std::atan2(dy, dx);
|
||||
ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang;
|
||||
return ang;
|
||||
}
|
||||
|
||||
void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const
|
||||
{
|
||||
float dx = GetPositionX() - x;
|
||||
float dy = GetPositionY() - y;
|
||||
|
||||
if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f)
|
||||
{
|
||||
float angle = (float)rand_norm()*static_cast<float>(2*M_PI);
|
||||
vcos = std::cos(angle);
|
||||
vsin = std::sin(angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
float dist = std::sqrt((dx*dx) + (dy*dy));
|
||||
vcos = dx / dist;
|
||||
vsin = dy / dist;
|
||||
}
|
||||
}
|
||||
|
||||
bool Position::HasInArc(float arc, const Position* obj, float border) const
|
||||
{
|
||||
// always have self in arc
|
||||
if (obj == this)
|
||||
return true;
|
||||
|
||||
// move arc to range 0.. 2*pi
|
||||
arc = NormalizeOrientation(arc);
|
||||
|
||||
float angle = GetAngle(obj);
|
||||
angle -= m_orientation;
|
||||
|
||||
// move angle to range -pi ... +pi
|
||||
angle = NormalizeOrientation(angle);
|
||||
if (angle > float(M_PI))
|
||||
angle -= 2.0f * float(M_PI);
|
||||
|
||||
float lborder = -1 * (arc/border); // in range -pi..0
|
||||
float rborder = (arc/border); // in range 0..pi
|
||||
return ((angle >= lborder) && (angle <= rborder));
|
||||
}
|
||||
|
||||
bool WorldObject::IsInBetween(const WorldObject* obj1, const WorldObject* obj2, float size) const
|
||||
{
|
||||
if (!obj1 || !obj2)
|
||||
@@ -1833,11 +1692,6 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
|
||||
}
|
||||
}
|
||||
|
||||
bool Position::IsPositionValid() const
|
||||
{
|
||||
return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation);
|
||||
}
|
||||
|
||||
float WorldObject::GetGridActivationRange() const
|
||||
{
|
||||
if (ToPlayer())
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define _OBJECT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Position.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "GridReference.h"
|
||||
#include "ObjectDefines.h"
|
||||
@@ -250,141 +251,6 @@ class Object
|
||||
Object& operator=(Object const& right) = delete;
|
||||
};
|
||||
|
||||
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(const Position &loc) { Relocate(loc); }
|
||||
|
||||
struct PositionXYZStreamer
|
||||
{
|
||||
explicit PositionXYZStreamer(Position& pos) : m_pos(&pos) { }
|
||||
Position* m_pos;
|
||||
};
|
||||
|
||||
struct PositionXYZOStreamer
|
||||
{
|
||||
explicit PositionXYZOStreamer(Position& pos) : m_pos(&pos) { }
|
||||
Position* m_pos;
|
||||
};
|
||||
|
||||
float m_positionX;
|
||||
float m_positionY;
|
||||
float m_positionZ;
|
||||
// Better to limit access to m_orientation field, but this will be hard to achieve with many scripts using array initialization for this structure
|
||||
//private:
|
||||
float m_orientation;
|
||||
//public:
|
||||
|
||||
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;}
|
||||
void Relocate(float x, float y, float 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; SetOrientation(orientation); }
|
||||
void Relocate(Position const &pos)
|
||||
{ m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation); }
|
||||
void Relocate(Position const* pos)
|
||||
{ m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation); }
|
||||
void RelocateOffset(Position const &offset);
|
||||
void SetOrientation(float orientation)
|
||||
{ m_orientation = NormalizeOrientation(orientation); }
|
||||
|
||||
float GetPositionX() const { return m_positionX; }
|
||||
float GetPositionY() const { return m_positionY; }
|
||||
float GetPositionZ() const { return m_positionZ; }
|
||||
float GetOrientation() const { return m_orientation; }
|
||||
|
||||
void GetPosition(float &x, float &y) const
|
||||
{ x = m_positionX; y = m_positionY; }
|
||||
void GetPosition(float &x, float &y, float &z) const
|
||||
{ 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; }
|
||||
|
||||
Position GetPosition() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
Position::PositionXYZStreamer PositionXYZStream()
|
||||
{
|
||||
return PositionXYZStreamer(*this);
|
||||
}
|
||||
Position::PositionXYZOStreamer PositionXYZOStream()
|
||||
{
|
||||
return PositionXYZOStreamer(*this);
|
||||
}
|
||||
|
||||
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 GetExactDist2d(const float x, const float y) const
|
||||
{ return std::sqrt(GetExactDist2dSq(x, y)); }
|
||||
float GetExactDist2dSq(Position const* pos) const
|
||||
{ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; }
|
||||
float GetExactDist2d(Position const* pos) const
|
||||
{ return std::sqrt(GetExactDist2dSq(pos)); }
|
||||
float GetExactDistSq(float x, float y, float z) const
|
||||
{ float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; }
|
||||
float GetExactDist(float x, float y, float z) const
|
||||
{ return std::sqrt(GetExactDistSq(x, y, z)); }
|
||||
float GetExactDistSq(Position const* 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 GetExactDist(Position const* pos) const
|
||||
{ return std::sqrt(GetExactDistSq(pos)); }
|
||||
|
||||
void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const;
|
||||
Position GetPositionWithOffset(Position const& offset) const;
|
||||
|
||||
float GetAngle(Position const* pos) const;
|
||||
float GetAngle(float x, float y) const;
|
||||
float GetRelativeAngle(Position const* pos) const
|
||||
{ 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; }
|
||||
bool IsInDist2d(Position const* pos, float dist) const
|
||||
{ return GetExactDist2dSq(pos) < dist * dist; }
|
||||
bool IsInDist(float x, float y, float z, float dist) const
|
||||
{ return GetExactDistSq(x, y, z) < dist * dist; }
|
||||
bool IsInDist(Position const* pos, float dist) const
|
||||
{ return GetExactDistSq(pos) < dist * dist; }
|
||||
bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const;
|
||||
bool HasInLine(WorldObject const* target, float width) const;
|
||||
std::string ToString() const;
|
||||
|
||||
// modulos a radian orientation to the range of 0..2PI
|
||||
static float NormalizeOrientation(float o)
|
||||
{
|
||||
// fmod only supports positive numbers. Thus we have
|
||||
// to emulate negative numbers
|
||||
if (o < 0)
|
||||
{
|
||||
float mod = o *-1;
|
||||
mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI));
|
||||
mod = -mod + 2.0f * static_cast<float>(M_PI);
|
||||
return mod;
|
||||
}
|
||||
return std::fmod(o, 2.0f * static_cast<float>(M_PI));
|
||||
}
|
||||
};
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer 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);
|
||||
|
||||
struct MovementInfo
|
||||
{
|
||||
// common
|
||||
|
||||
@@ -88,51 +88,41 @@ class ObjectGuid
|
||||
public:
|
||||
static ObjectGuid const Empty;
|
||||
|
||||
ObjectGuid() { _data._guid = UI64LIT(0); }
|
||||
explicit ObjectGuid(uint64 guid) { _data._guid = guid; }
|
||||
ObjectGuid(HighGuid hi, uint32 entry, uint32 counter) { _data._guid = counter ? uint64(counter) | (uint64(entry) << 32) | (uint64(hi) << ((hi == HIGHGUID_CORPSE || hi == HIGHGUID_AREATRIGGER) ? 48 : 52)) : 0; }
|
||||
ObjectGuid(HighGuid hi, uint32 counter) { _data._guid = counter ? uint64(counter) | (uint64(hi) << ((hi == HIGHGUID_CORPSE || hi == HIGHGUID_AREATRIGGER) ? 48 : 52)) : 0; }
|
||||
typedef uint32 LowType;
|
||||
|
||||
operator uint64() const { return _data._guid; }
|
||||
ObjectGuid() : _guid(0) { }
|
||||
explicit ObjectGuid(uint64 guid) : _guid(guid) { }
|
||||
ObjectGuid(HighGuid hi, uint32 entry, LowType counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { }
|
||||
ObjectGuid(HighGuid hi, LowType counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { }
|
||||
|
||||
operator uint64() const { return _guid; }
|
||||
PackedGuidReader ReadAsPacked() { return PackedGuidReader(*this); }
|
||||
|
||||
void Set(uint64 guid) { _data._guid = guid; }
|
||||
void Clear() { _data._guid = 0; }
|
||||
void Set(uint64 guid) { _guid = guid; }
|
||||
void Clear() { _guid = 0; }
|
||||
|
||||
PackedGuid WriteAsPacked() const;
|
||||
|
||||
uint64 GetRawValue() const { return _data._guid; }
|
||||
HighGuid GetHigh() const
|
||||
uint64 GetRawValue() const { return _guid; }
|
||||
HighGuid GetHigh() const { return HighGuid((_guid >> 48) & 0x0000FFFF); }
|
||||
uint32 GetEntry() const { return HasEntry() ? uint32((_guid >> 24) & UI64LIT(0x0000000000FFFFFF)) : 0; }
|
||||
LowType GetCounter() const
|
||||
{
|
||||
uint32 temp = ((uint64(_data._guid) >> 48) & 0x0000FFFF);
|
||||
return HighGuid((temp == HIGHGUID_CORPSE || temp == HIGHGUID_AREATRIGGER) ? temp : ((temp >> 4) & 0x00000FFF));
|
||||
}
|
||||
uint32 GetEntry() const { return HasEntry() ? uint32((_data._guid >> 32) & UI64LIT(0x00000000000FFFFF)) : 0; }
|
||||
uint32 GetCounter() const
|
||||
{
|
||||
return uint32(_data._guid & UI64LIT(0x00000000FFFFFFFF));
|
||||
return HasEntry()
|
||||
? LowType(_guid & UI64LIT(0x0000000000FFFFFF))
|
||||
: LowType(_guid & UI64LIT(0x00000000FFFFFFFF));
|
||||
}
|
||||
|
||||
static uint32 GetMaxCounter(HighGuid /*high*/)
|
||||
static uint32 GetMaxCounter(HighGuid high)
|
||||
{
|
||||
return uint32(0xFFFFFFFF);
|
||||
return HasEntry(high)
|
||||
? uint32(0x00FFFFFF)
|
||||
: uint32(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
uint32 GetMaxCounter() const { return GetMaxCounter(GetHigh()); }
|
||||
|
||||
uint8& operator[](uint32 index)
|
||||
{
|
||||
ASSERT(index < sizeof(uint64));
|
||||
return _data._bytes[index];
|
||||
}
|
||||
|
||||
uint8 const& operator[](uint32 index) const
|
||||
{
|
||||
ASSERT(index < sizeof(uint64));
|
||||
return _data._bytes[index];
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return _data._guid == 0; }
|
||||
bool IsEmpty() const { return _guid == 0; }
|
||||
bool IsCreature() const { return GetHigh() == HIGHGUID_UNIT; }
|
||||
bool IsPet() const { return GetHigh() == HIGHGUID_PET; }
|
||||
bool IsVehicle() const { return GetHigh() == HIGHGUID_VEHICLE; }
|
||||
@@ -218,11 +208,7 @@ class ObjectGuid
|
||||
ObjectGuid(HighGuid, uint32, uint64 counter) = delete; // no implementation, used to catch wrong type assignment
|
||||
ObjectGuid(HighGuid, uint64 counter) = delete; // no implementation, used to catch wrong type assignment
|
||||
|
||||
union
|
||||
{
|
||||
uint64 _guid;
|
||||
uint8 _bytes[sizeof(uint64)];
|
||||
} _data;
|
||||
uint64 _guid;
|
||||
};
|
||||
|
||||
// Some Shared defines
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2015 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/>.
|
||||
*/
|
||||
|
||||
#include "Position.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "GridDefines.h"
|
||||
|
||||
bool Position::operator==(Position const &a)
|
||||
{
|
||||
return (G3D::fuzzyEq(a.m_positionX, m_positionX) &&
|
||||
G3D::fuzzyEq(a.m_positionY, m_positionY) &&
|
||||
G3D::fuzzyEq(a.m_positionZ, m_positionZ) &&
|
||||
G3D::fuzzyEq(a.m_orientation, m_orientation));
|
||||
}
|
||||
|
||||
void Position::RelocateOffset(const Position & offset)
|
||||
{
|
||||
m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI)));
|
||||
m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation()));
|
||||
m_positionZ = GetPositionZ() + offset.GetPositionZ();
|
||||
SetOrientation(GetOrientation() + offset.GetOrientation());
|
||||
}
|
||||
|
||||
bool Position::IsPositionValid() const
|
||||
{
|
||||
return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation);
|
||||
}
|
||||
|
||||
void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const
|
||||
{
|
||||
float dx = endPos.GetPositionX() - GetPositionX();
|
||||
float dy = endPos.GetPositionY() - GetPositionY();
|
||||
|
||||
retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation());
|
||||
retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation());
|
||||
retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ();
|
||||
retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation());
|
||||
}
|
||||
|
||||
Position Position::GetPositionWithOffset(Position const& offset) const
|
||||
{
|
||||
Position ret(*this);
|
||||
ret.RelocateOffset(offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
float Position::GetAngle(const Position* obj) const
|
||||
{
|
||||
if (!obj)
|
||||
return 0;
|
||||
|
||||
return GetAngle(obj->GetPositionX(), obj->GetPositionY());
|
||||
}
|
||||
|
||||
// Return angle in range 0..2*pi
|
||||
float Position::GetAngle(float x, float y) const
|
||||
{
|
||||
float dx = x - GetPositionX();
|
||||
float dy = y - GetPositionY();
|
||||
|
||||
float ang = std::atan2(dy, dx);
|
||||
ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang;
|
||||
return ang;
|
||||
}
|
||||
|
||||
void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const
|
||||
{
|
||||
float dx = GetPositionX() - x;
|
||||
float dy = GetPositionY() - y;
|
||||
|
||||
if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f)
|
||||
{
|
||||
float angle = (float)rand_norm()*static_cast<float>(2 * M_PI);
|
||||
vcos = std::cos(angle);
|
||||
vsin = std::sin(angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
float dist = std::sqrt((dx*dx) + (dy*dy));
|
||||
vcos = dx / dist;
|
||||
vsin = dy / dist;
|
||||
}
|
||||
}
|
||||
|
||||
bool Position::HasInArc(float arc, const Position* obj, float border) const
|
||||
{
|
||||
// always have self in arc
|
||||
if (obj == this)
|
||||
return true;
|
||||
|
||||
// move arc to range 0.. 2*pi
|
||||
arc = NormalizeOrientation(arc);
|
||||
|
||||
float angle = GetAngle(obj);
|
||||
angle -= m_orientation;
|
||||
|
||||
// move angle to range -pi ... +pi
|
||||
angle = NormalizeOrientation(angle);
|
||||
if (angle > float(M_PI))
|
||||
angle -= 2.0f * float(M_PI);
|
||||
|
||||
float lborder = -1 * (arc / border); // in range -pi..0
|
||||
float rborder = (arc / border); // in range 0..pi
|
||||
return ((angle >= lborder) && (angle <= rborder));
|
||||
}
|
||||
|
||||
bool Position::HasInLine(Position const* pos, float width) const
|
||||
{
|
||||
if (!HasInArc(float(M_PI), pos))
|
||||
return false;
|
||||
|
||||
float angle = GetRelativeAngle(pos);
|
||||
return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width;
|
||||
}
|
||||
|
||||
std::string Position::ToString() const
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer)
|
||||
{
|
||||
buf << streamer.Pos->GetPositionX();
|
||||
buf << streamer.Pos->GetPositionY();
|
||||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer)
|
||||
{
|
||||
float x, y;
|
||||
buf >> x >> y;
|
||||
streamer.Pos->Relocate(x, y);
|
||||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
|
||||
{
|
||||
buf << streamer.Pos->GetPositionX();
|
||||
buf << streamer.Pos->GetPositionY();
|
||||
buf << streamer.Pos->GetPositionZ();
|
||||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
|
||||
{
|
||||
float x, y, z;
|
||||
buf >> x >> y >> z;
|
||||
streamer.Pos->Relocate(x, y, z);
|
||||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
|
||||
{
|
||||
buf << streamer.Pos->GetPositionX();
|
||||
buf << streamer.Pos->GetPositionY();
|
||||
buf << streamer.Pos->GetPositionZ();
|
||||
buf << streamer.Pos->GetOrientation();
|
||||
return buf;
|
||||
}
|
||||
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
|
||||
{
|
||||
float x, y, z, o;
|
||||
buf >> x >> y >> z >> o;
|
||||
streamer.Pos->Relocate(x, y, z, o);
|
||||
return buf;
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2015 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/>.
|
||||
*/
|
||||
|
||||
#ifndef Trinity_game_Position_h__
|
||||
#define Trinity_game_Position_h__
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
class ByteBuffer;
|
||||
|
||||
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) : Pos(&pos) { }
|
||||
Position* Pos;
|
||||
};
|
||||
|
||||
struct PositionXYZOStreamer
|
||||
{
|
||||
explicit PositionXYZOStreamer(Position& pos) : Pos(&pos) { }
|
||||
Position* Pos;
|
||||
};
|
||||
|
||||
float m_positionX;
|
||||
float m_positionY;
|
||||
float m_positionZ;
|
||||
// Better to limit access to _orientation field, to guarantee the value is normalized
|
||||
private:
|
||||
float m_orientation;
|
||||
|
||||
public:
|
||||
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;
|
||||
}
|
||||
|
||||
void Relocate(float x, float y, float 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; SetOrientation(orientation);
|
||||
}
|
||||
|
||||
void Relocate(Position const &pos)
|
||||
{
|
||||
m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation);
|
||||
}
|
||||
|
||||
void Relocate(Position const* pos)
|
||||
{
|
||||
m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation);
|
||||
}
|
||||
|
||||
void RelocateOffset(Position const &offset);
|
||||
|
||||
void SetOrientation(float orientation)
|
||||
{
|
||||
m_orientation = NormalizeOrientation(orientation);
|
||||
}
|
||||
|
||||
float GetPositionX() const { return m_positionX; }
|
||||
float GetPositionY() const { return m_positionY; }
|
||||
float GetPositionZ() const { return m_positionZ; }
|
||||
float GetOrientation() const { return m_orientation; }
|
||||
|
||||
void GetPosition(float &x, float &y) const
|
||||
{
|
||||
x = m_positionX; y = m_positionY;
|
||||
}
|
||||
|
||||
void GetPosition(float &x, float &y, float &z) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
Position GetPosition() const { return *this; }
|
||||
|
||||
Position::PositionXYStreamer PositionXYStream() { return PositionXYStreamer(*this); }
|
||||
Position::PositionXYZStreamer PositionXYZStream() { return PositionXYZStreamer(*this); }
|
||||
Position::PositionXYZOStreamer PositionXYZOStream() { return PositionXYZOStreamer(*this); }
|
||||
|
||||
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 GetExactDist2d(const float x, const float y) const
|
||||
{
|
||||
return std::sqrt(GetExactDist2dSq(x, y));
|
||||
}
|
||||
|
||||
float GetExactDist2dSq(Position const* pos) const
|
||||
{
|
||||
float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy;
|
||||
}
|
||||
|
||||
float GetExactDist2d(Position const* pos) const
|
||||
{
|
||||
return std::sqrt(GetExactDist2dSq(pos));
|
||||
}
|
||||
|
||||
float GetExactDistSq(float x, float y, float z) const
|
||||
{
|
||||
float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz;
|
||||
}
|
||||
|
||||
float GetExactDist(float x, float y, float z) const
|
||||
{
|
||||
return std::sqrt(GetExactDistSq(x, y, z));
|
||||
}
|
||||
|
||||
float GetExactDistSq(Position const* 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 GetExactDist(Position const* pos) const
|
||||
{
|
||||
return std::sqrt(GetExactDistSq(pos));
|
||||
}
|
||||
|
||||
void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const;
|
||||
Position GetPositionWithOffset(Position const& offset) const;
|
||||
|
||||
float GetAngle(Position const* pos) const;
|
||||
float GetAngle(float x, float y) const;
|
||||
float GetRelativeAngle(Position const* pos) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool IsInDist2d(Position const* pos, float dist) const
|
||||
{
|
||||
return GetExactDist2dSq(pos) < dist * dist;
|
||||
}
|
||||
|
||||
bool IsInDist(float x, float y, float z, float dist) const
|
||||
{
|
||||
return GetExactDistSq(x, y, z) < dist * dist;
|
||||
}
|
||||
|
||||
bool IsInDist(Position const* pos, float dist) const
|
||||
{
|
||||
return GetExactDistSq(pos) < dist * dist;
|
||||
}
|
||||
|
||||
bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const;
|
||||
bool HasInLine(Position const* pos, float width) const;
|
||||
std::string ToString() const;
|
||||
|
||||
// modulos a radian orientation to the range of 0..2PI
|
||||
static float NormalizeOrientation(float o)
|
||||
{
|
||||
// fmod only supports positive numbers. Thus we have
|
||||
// to emulate negative numbers
|
||||
if (o < 0)
|
||||
{
|
||||
float mod = o *-1;
|
||||
mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI));
|
||||
mod = -mod + 2.0f * static_cast<float>(M_PI);
|
||||
return mod;
|
||||
}
|
||||
return std::fmod(o, 2.0f * static_cast<float>(M_PI));
|
||||
}
|
||||
};
|
||||
|
||||
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::PositionXYZOStreamer const& streamer);
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
|
||||
|
||||
#endif // Trinity_game_Position_h__
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "SpellMgr.h"
|
||||
#include "Pet.h"
|
||||
#include "Formulas.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "Unit.h"
|
||||
@@ -409,7 +410,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||
RemoveAllAuras();
|
||||
|
||||
_SaveSpells(trans);
|
||||
_SaveSpellCooldowns(trans);
|
||||
GetSpellHistory()->SaveToDB<Pet>(trans);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
// current/stable/not_in_slot
|
||||
@@ -1069,77 +1070,11 @@ uint32 Pet::GetCurrentFoodBenefitLevel(uint32 itemlevel) const
|
||||
|
||||
void Pet::_LoadSpellCooldowns()
|
||||
{
|
||||
m_CreatureSpellCooldowns.clear();
|
||||
m_CreatureCategoryCooldowns.clear();
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_COOLDOWN);
|
||||
stmt->setUInt32(0, m_charmInfo->GetPetNumber());
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
PreparedQueryResult cooldownsResult = CharacterDatabase.Query(stmt);
|
||||
|
||||
if (result)
|
||||
{
|
||||
time_t curTime = time(NULL);
|
||||
|
||||
PacketCooldowns cooldowns;
|
||||
WorldPacket data;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 spell_id = fields[0].GetUInt32();
|
||||
time_t db_time = time_t(fields[1].GetUInt32());
|
||||
|
||||
if (!sSpellMgr->GetSpellInfo(spell_id))
|
||||
{
|
||||
TC_LOG_ERROR("entities.pet", "Pet %u have unknown spell %u in `pet_spell_cooldown`, skipping.", m_charmInfo->GetPetNumber(), spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip outdated cooldown
|
||||
if (db_time <= curTime)
|
||||
continue;
|
||||
|
||||
cooldowns[spell_id] = uint32(db_time - curTime)*IN_MILLISECONDS;
|
||||
|
||||
_AddCreatureSpellCooldown(spell_id, db_time);
|
||||
|
||||
TC_LOG_DEBUG("entities.pet", "Pet (Number: %u) spell %u cooldown loaded (%u secs).", m_charmInfo->GetPetNumber(), spell_id, uint32(db_time-curTime));
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
if (!cooldowns.empty())
|
||||
{
|
||||
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
|
||||
GetOwner()->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pet::_SaveSpellCooldowns(SQLTransaction& trans)
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_SPELL_COOLDOWNS);
|
||||
stmt->setUInt32(0, m_charmInfo->GetPetNumber());
|
||||
trans->Append(stmt);
|
||||
|
||||
time_t curTime = time(NULL);
|
||||
|
||||
// remove oudated and save active
|
||||
for (CreatureSpellCooldowns::iterator itr = m_CreatureSpellCooldowns.begin(); itr != m_CreatureSpellCooldowns.end();)
|
||||
{
|
||||
if (itr->second <= curTime)
|
||||
m_CreatureSpellCooldowns.erase(itr++);
|
||||
else
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_SPELL_COOLDOWN);
|
||||
stmt->setUInt32(0, m_charmInfo->GetPetNumber());
|
||||
stmt->setUInt32(1, itr->first);
|
||||
stmt->setUInt32(2, uint32(itr->second));
|
||||
trans->Append(stmt);
|
||||
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
GetSpellHistory()->LoadFromDB<Pet>(cooldownsResult);
|
||||
}
|
||||
|
||||
void Pet::_LoadSpells()
|
||||
@@ -1989,40 +1924,6 @@ void Pet::SynchronizeLevelWithOwner()
|
||||
}
|
||||
}
|
||||
|
||||
void Pet::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
|
||||
{
|
||||
PacketCooldowns cooldowns;
|
||||
WorldPacket data;
|
||||
time_t curTime = time(NULL);
|
||||
for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
|
||||
{
|
||||
if (itr->second.state == PETSPELL_REMOVED)
|
||||
continue;
|
||||
|
||||
uint32 unSpellId = itr->first;
|
||||
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId);
|
||||
|
||||
// Not send cooldown for this spells
|
||||
if (spellInfo->IsCooldownStartedOnEvent())
|
||||
continue;
|
||||
|
||||
if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
|
||||
continue;
|
||||
|
||||
if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetCreatureSpellCooldownDelay(unSpellId) < unTimeMs)
|
||||
{
|
||||
cooldowns[unSpellId] = unTimeMs;
|
||||
_AddCreatureSpellCooldown(unSpellId, curTime + unTimeMs/IN_MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cooldowns.empty())
|
||||
{
|
||||
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
|
||||
GetOwner()->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
Player* Pet::GetOwner() const
|
||||
{
|
||||
return Minion::GetOwner()->ToPlayer();
|
||||
|
||||
@@ -106,7 +106,6 @@ class Pet : public Guardian
|
||||
bool IsPetAura(Aura const* aura);
|
||||
|
||||
void _LoadSpellCooldowns();
|
||||
void _SaveSpellCooldowns(SQLTransaction& trans);
|
||||
void _LoadAuras(uint32 timediff);
|
||||
void _SaveAuras(SQLTransaction& trans);
|
||||
void _LoadSpells();
|
||||
@@ -119,7 +118,6 @@ class Pet : public Guardian
|
||||
bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
|
||||
bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
|
||||
void CleanupActionBar();
|
||||
virtual void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
|
||||
|
||||
PetSpellMap m_spells;
|
||||
AutoSpellList m_autospells;
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "Transport.h"
|
||||
#include "UpdateData.h"
|
||||
#include "UpdateFieldFlags.h"
|
||||
@@ -3420,12 +3421,10 @@ void Player::InitStatsForLevel(bool reapplyMods)
|
||||
|
||||
void Player::SendInitialSpells()
|
||||
{
|
||||
time_t curTime = time(NULL);
|
||||
time_t infTime = curTime + infinityCooldownDelayCheck;
|
||||
|
||||
uint16 spellCooldowns = GetSpellHistory()->GetCooldownsSizeForPacket();
|
||||
uint16 spellCount = 0;
|
||||
|
||||
WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4)));
|
||||
WorldPacket data(SMSG_INITIAL_SPELLS, (1 + 2 + 4 * m_spells.size() + 2 + spellCooldowns * (2 + 2 + 2 + 4 + 4)));
|
||||
data << uint8(0);
|
||||
|
||||
size_t countPos = data.wpos();
|
||||
@@ -3447,40 +3446,7 @@ void Player::SendInitialSpells()
|
||||
|
||||
data.put<uint16>(countPos, spellCount); // write real count value
|
||||
|
||||
uint16 spellCooldowns = m_spellCooldowns.size();
|
||||
data << uint16(spellCooldowns);
|
||||
for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr)
|
||||
{
|
||||
SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(itr->first);
|
||||
if (!sEntry)
|
||||
continue;
|
||||
|
||||
data << uint32(itr->first);
|
||||
|
||||
data << uint32(itr->second.itemid); // cast item id
|
||||
data << uint16(sEntry->GetCategory()); // spell category
|
||||
|
||||
// send infinity cooldown in special format
|
||||
if (itr->second.end >= infTime)
|
||||
{
|
||||
data << uint32(1); // cooldown
|
||||
data << uint32(0x80000000); // category cooldown
|
||||
continue;
|
||||
}
|
||||
|
||||
time_t cooldown = itr->second.end > curTime ? (itr->second.end-curTime)*IN_MILLISECONDS : 0;
|
||||
|
||||
if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing...
|
||||
{
|
||||
data << uint32(0); // cooldown
|
||||
data << uint32(cooldown); // category cooldown
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(cooldown); // cooldown
|
||||
data << uint32(0); // category cooldown
|
||||
}
|
||||
}
|
||||
GetSpellHistory()->WritePacket<Player>(data);
|
||||
|
||||
GetSession()->SendPacket(&data);
|
||||
|
||||
@@ -4230,152 +4196,19 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */)
|
||||
{
|
||||
m_spellCooldowns.erase(spell_id);
|
||||
|
||||
if (update)
|
||||
SendClearCooldown(spell_id, this);
|
||||
}
|
||||
|
||||
// I am not sure which one is more efficient
|
||||
void Player::RemoveCategoryCooldown(uint32 cat)
|
||||
{
|
||||
SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat);
|
||||
if (i_scstore != sSpellsByCategoryStore.end())
|
||||
for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
|
||||
RemoveSpellCooldown(*i_scset, true);
|
||||
}
|
||||
|
||||
void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */)
|
||||
{
|
||||
SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat);
|
||||
if (ct == sSpellsByCategoryStore.end())
|
||||
return;
|
||||
|
||||
const SpellCategorySet& ct_set = ct->second;
|
||||
for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end();)
|
||||
{
|
||||
if (ct_set.find(i->first) != ct_set.end())
|
||||
RemoveSpellCooldown((i++)->first, update);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
|
||||
{
|
||||
// remove cooldowns on spells that have < 10 min CD
|
||||
|
||||
SpellCooldowns::iterator itr, next;
|
||||
for (itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); itr = next)
|
||||
GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
|
||||
{
|
||||
next = itr;
|
||||
++next;
|
||||
SpellInfo const* entry = sSpellMgr->GetSpellInfo(itr->first);
|
||||
// check if spellentry is present and if the cooldown is less than 10 min
|
||||
if (entry &&
|
||||
entry->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS &&
|
||||
entry->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS)
|
||||
{
|
||||
// remove & notify
|
||||
RemoveSpellCooldown(itr->first, true);
|
||||
}
|
||||
}
|
||||
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
|
||||
return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS;
|
||||
}, true);
|
||||
|
||||
// pet cooldowns
|
||||
if (removeActivePetCooldowns)
|
||||
if (Pet* pet = GetPet())
|
||||
{
|
||||
// notify player
|
||||
for (CreatureSpellCooldowns::const_iterator itr2 = pet->m_CreatureSpellCooldowns.begin(); itr2 != pet->m_CreatureSpellCooldowns.end(); ++itr2)
|
||||
SendClearCooldown(itr2->first, pet);
|
||||
|
||||
// actually clear cooldowns
|
||||
pet->m_CreatureSpellCooldowns.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RemoveAllSpellCooldown()
|
||||
{
|
||||
if (!m_spellCooldowns.empty())
|
||||
{
|
||||
SendClearAllCooldowns(this);
|
||||
m_spellCooldowns.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::_LoadSpellCooldowns(PreparedQueryResult result)
|
||||
{
|
||||
// some cooldowns can be already set at aura loading...
|
||||
|
||||
//QueryResult* result = CharacterDatabase.PQuery("SELECT spell, item, time FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow());
|
||||
|
||||
if (result)
|
||||
{
|
||||
time_t curTime = time(NULL);
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 spell_id = fields[0].GetUInt32();
|
||||
uint32 item_id = fields[1].GetUInt32();
|
||||
time_t db_time = time_t(fields[2].GetUInt32());
|
||||
|
||||
if (!sSpellMgr->GetSpellInfo(spell_id))
|
||||
{
|
||||
TC_LOG_ERROR("entities.player.loading", "Player %u has unknown spell %u in `character_spell_cooldown`, skipping.", GetGUIDLow(), spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip outdated cooldown
|
||||
if (db_time <= curTime)
|
||||
continue;
|
||||
|
||||
AddSpellCooldown(spell_id, item_id, db_time);
|
||||
|
||||
TC_LOG_DEBUG("entities.player.loading", "Player (GUID: %u) spell %u, item %u cooldown loaded (%u secs).", GetGUIDLow(), spell_id, item_id, uint32(db_time-curTime));
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
void Player::_SaveSpellCooldowns(SQLTransaction& trans)
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
|
||||
stmt->setUInt32(0, GetGUIDLow());
|
||||
trans->Append(stmt);
|
||||
|
||||
time_t curTime = time(NULL);
|
||||
time_t infTime = curTime + infinityCooldownDelayCheck;
|
||||
|
||||
bool first_round = true;
|
||||
std::ostringstream ss;
|
||||
|
||||
// remove outdated and save active
|
||||
for (SpellCooldowns::iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end();)
|
||||
{
|
||||
if (itr->second.end <= curTime)
|
||||
m_spellCooldowns.erase(itr++);
|
||||
else if (itr->second.end <= infTime) // not save locked cooldowns, it will be reset or set at reload
|
||||
{
|
||||
if (first_round)
|
||||
{
|
||||
ss << "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES ";
|
||||
first_round = false;
|
||||
}
|
||||
// next new/changed record prefix
|
||||
else
|
||||
ss << ',';
|
||||
ss << '(' << GetGUIDLow() << ',' << itr->first << ',' << itr->second.itemid << ',' << uint64(itr->second.end) << ')';
|
||||
++itr;
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
// if something changed execute
|
||||
if (!first_round)
|
||||
trans->Append(ss.str().c_str());
|
||||
pet->GetSpellHistory()->ResetAllCooldowns();
|
||||
}
|
||||
|
||||
uint32 Player::GetNextResetTalentsCost() const
|
||||
@@ -4919,7 +4752,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
|
||||
stmt->setUInt32(0, guid);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS);
|
||||
stmt->setUInt32(0, guid);
|
||||
trans->Append(stmt);
|
||||
|
||||
@@ -8631,7 +8464,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
|
||||
if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
|
||||
//if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i)
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
{
|
||||
_Spell const& spellData = proto->Spells[i];
|
||||
|
||||
@@ -12252,10 +12085,9 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
|
||||
{
|
||||
m_weaponChangeTimer = spellProto->StartRecoveryTime;
|
||||
|
||||
GetGlobalCooldownMgr().AddGlobalCooldown(spellProto, m_weaponChangeTimer);
|
||||
|
||||
GetSpellHistory()->AddGlobalCooldown(spellProto, m_weaponChangeTimer);
|
||||
WorldPacket data;
|
||||
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_INCLUDE_GCD, cooldownSpell, 0);
|
||||
GetSpellHistory()->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_INCLUDE_GCD, cooldownSpell, 0);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
@@ -17905,7 +17737,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
|
||||
// has to be called after last Relocate() in Player::LoadFromDB
|
||||
SetFallInformation(0, GetPositionZ());
|
||||
|
||||
_LoadSpellCooldowns(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS));
|
||||
GetSpellHistory()->LoadFromDB<Player>(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS));
|
||||
|
||||
// Spell code allow apply any auras to dead character in load time in aura/spell/item loading
|
||||
// Do now before stats re-calculation cleanup for ghost state unexpected auras
|
||||
@@ -19748,7 +19580,7 @@ void Player::SaveToDB(bool create /*=false*/)
|
||||
_SaveMonthlyQuestStatus(trans);
|
||||
_SaveTalents(trans);
|
||||
_SaveSpells(trans);
|
||||
_SaveSpellCooldowns(trans);
|
||||
GetSpellHistory()->SaveToDB<Player>(trans);
|
||||
_SaveActions(trans);
|
||||
_SaveAuras(trans);
|
||||
_SaveSkills(trans);
|
||||
@@ -21070,41 +20902,8 @@ void Player::PetSpellInitialize()
|
||||
|
||||
data.put<uint8>(spellsCountPos, addlist);
|
||||
|
||||
uint8 cooldownsCount = pet->m_CreatureSpellCooldowns.size() + pet->m_CreatureCategoryCooldowns.size();
|
||||
data << uint8(cooldownsCount);
|
||||
|
||||
time_t curTime = time(NULL);
|
||||
|
||||
for (CreatureSpellCooldowns::const_iterator itr = pet->m_CreatureSpellCooldowns.begin(); itr != pet->m_CreatureSpellCooldowns.end(); ++itr)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
|
||||
if (!spellInfo)
|
||||
{
|
||||
data << uint32(0);
|
||||
data << uint16(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
time_t cooldown = (itr->second > curTime) ? (itr->second - curTime) * IN_MILLISECONDS : 0;
|
||||
data << uint32(itr->first); // spell ID
|
||||
|
||||
CreatureSpellCooldowns::const_iterator categoryitr = pet->m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
|
||||
if (categoryitr != pet->m_CreatureCategoryCooldowns.end())
|
||||
{
|
||||
time_t categoryCooldown = (categoryitr->second > curTime) ? (categoryitr->second - curTime) * IN_MILLISECONDS : 0;
|
||||
data << uint16(spellInfo->GetCategory()); // spell category
|
||||
data << uint32(cooldown); // spell cooldown
|
||||
data << uint32(categoryCooldown); // category cooldown
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint16(0);
|
||||
data << uint32(cooldown);
|
||||
data << uint32(0);
|
||||
}
|
||||
}
|
||||
//Cooldowns
|
||||
pet->GetSpellHistory()->WritePacket<Pet>(data);
|
||||
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
@@ -21143,7 +20942,7 @@ void Player::VehicleSpellInitialize()
|
||||
if (!vehicle)
|
||||
return;
|
||||
|
||||
uint8 cooldownCount = vehicle->m_CreatureSpellCooldowns.size();
|
||||
uint8 cooldownCount = vehicle->GetSpellHistory()->GetCooldownsSizeForPacket();
|
||||
|
||||
WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * 10 + 1 + 1 + cooldownCount * (4 + 2 + 4 + 4));
|
||||
data << uint64(vehicle->GetGUID()); // Guid
|
||||
@@ -21184,41 +20983,7 @@ void Player::VehicleSpellInitialize()
|
||||
data << uint8(0); // Auras?
|
||||
|
||||
// Cooldowns
|
||||
data << uint8(cooldownCount);
|
||||
|
||||
time_t now = sWorld->GetGameTime();
|
||||
|
||||
for (CreatureSpellCooldowns::const_iterator itr = vehicle->m_CreatureSpellCooldowns.begin(); itr != vehicle->m_CreatureSpellCooldowns.end(); ++itr)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
|
||||
if (!spellInfo)
|
||||
{
|
||||
data << uint32(0);
|
||||
data << uint16(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
time_t cooldown = (itr->second > now) ? (itr->second - now) * IN_MILLISECONDS : 0;
|
||||
data << uint32(itr->first); // spell ID
|
||||
|
||||
CreatureSpellCooldowns::const_iterator categoryitr = vehicle->m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
|
||||
if (categoryitr != vehicle->m_CreatureCategoryCooldowns.end())
|
||||
{
|
||||
time_t categoryCooldown = (categoryitr->second > now) ? (categoryitr->second - now) * IN_MILLISECONDS : 0;
|
||||
data << uint16(spellInfo->GetCategory()); // spell category
|
||||
data << uint32(cooldown); // spell cooldown
|
||||
data << uint32(categoryCooldown); // category cooldown
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint16(0);
|
||||
data << uint32(cooldown);
|
||||
data << uint32(0);
|
||||
}
|
||||
}
|
||||
|
||||
vehicle->GetSpellHistory()->WritePacket<Pet>(data);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
@@ -21842,9 +21607,9 @@ void Player::ContinueTaxiFlight()
|
||||
|
||||
float distPrev = MAP_SIZE*MAP_SIZE;
|
||||
float distNext =
|
||||
(nodeList[0].x-GetPositionX())*(nodeList[0].x-GetPositionX())+
|
||||
(nodeList[0].y-GetPositionY())*(nodeList[0].y-GetPositionY())+
|
||||
(nodeList[0].z-GetPositionZ())*(nodeList[0].z-GetPositionZ());
|
||||
(nodeList[0].LocX-GetPositionX())*(nodeList[0].LocX-GetPositionX())+
|
||||
(nodeList[0].LocY-GetPositionY())*(nodeList[0].LocY-GetPositionY())+
|
||||
(nodeList[0].LocZ-GetPositionZ())*(nodeList[0].LocZ-GetPositionZ());
|
||||
|
||||
for (uint32 i = 1; i < nodeList.size(); ++i)
|
||||
{
|
||||
@@ -21852,20 +21617,20 @@ void Player::ContinueTaxiFlight()
|
||||
TaxiPathNodeEntry const& prevNode = nodeList[i-1];
|
||||
|
||||
// skip nodes at another map
|
||||
if (node.mapid != GetMapId())
|
||||
if (node.MapID != GetMapId())
|
||||
continue;
|
||||
|
||||
distPrev = distNext;
|
||||
|
||||
distNext =
|
||||
(node.x-GetPositionX())*(node.x-GetPositionX())+
|
||||
(node.y-GetPositionY())*(node.y-GetPositionY())+
|
||||
(node.z-GetPositionZ())*(node.z-GetPositionZ());
|
||||
(node.LocX-GetPositionX())*(node.LocX-GetPositionX())+
|
||||
(node.LocY-GetPositionY())*(node.LocY-GetPositionY())+
|
||||
(node.LocZ-GetPositionZ())*(node.LocZ-GetPositionZ());
|
||||
|
||||
float distNodes =
|
||||
(node.x-prevNode.x)*(node.x-prevNode.x)+
|
||||
(node.y-prevNode.y)*(node.y-prevNode.y)+
|
||||
(node.z-prevNode.z)*(node.z-prevNode.z);
|
||||
(node.LocX-prevNode.LocX)*(node.LocX-prevNode.LocX)+
|
||||
(node.LocY-prevNode.LocY)*(node.LocY-prevNode.LocY)+
|
||||
(node.LocZ-prevNode.LocZ)*(node.LocZ-prevNode.LocZ);
|
||||
|
||||
if (distNext + distPrev < distNodes)
|
||||
{
|
||||
@@ -21877,39 +21642,6 @@ void Player::ContinueTaxiFlight()
|
||||
GetSession()->SendDoFlight(mountDisplayId, path, startNode);
|
||||
}
|
||||
|
||||
void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
|
||||
{
|
||||
PacketCooldowns cooldowns;
|
||||
WorldPacket data;
|
||||
time_t curTime = time(NULL);
|
||||
for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
|
||||
{
|
||||
if (itr->second->state == PLAYERSPELL_REMOVED)
|
||||
continue;
|
||||
uint32 unSpellId = itr->first;
|
||||
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId);
|
||||
|
||||
// Not send cooldown for this spells
|
||||
if (spellInfo->IsCooldownStartedOnEvent())
|
||||
continue;
|
||||
|
||||
if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
|
||||
continue;
|
||||
|
||||
if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetSpellCooldownDelay(unSpellId) < unTimeMs)
|
||||
{
|
||||
cooldowns[unSpellId] = unTimeMs;
|
||||
AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/IN_MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cooldowns.empty())
|
||||
{
|
||||
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::InitDataForForm(bool reapplyMods)
|
||||
{
|
||||
ShapeshiftForm form = GetShapeshiftForm();
|
||||
@@ -22545,94 +22277,6 @@ void Player::UpdatePvP(bool state, bool _override)
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::HasSpellCooldown(uint32 spell_id) const
|
||||
{
|
||||
SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id);
|
||||
return itr != m_spellCooldowns.end() && itr->second.end > time(NULL);
|
||||
}
|
||||
|
||||
uint32 Player::GetSpellCooldownDelay(uint32 spell_id) const
|
||||
{
|
||||
SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id);
|
||||
time_t t = time(NULL);
|
||||
return uint32(itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0);
|
||||
}
|
||||
|
||||
void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell, bool infinityCooldown)
|
||||
{
|
||||
// init cooldown values
|
||||
uint32 cat = 0;
|
||||
int32 rec = -1;
|
||||
int32 catrec = -1;
|
||||
|
||||
// some special item spells without correct cooldown in SpellInfo
|
||||
// cooldown information stored in item prototype
|
||||
// This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
|
||||
|
||||
if (itemId)
|
||||
{
|
||||
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
|
||||
{
|
||||
for (uint8 idx = 0; idx < MAX_ITEM_SPELLS; ++idx)
|
||||
{
|
||||
if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id)
|
||||
{
|
||||
cat = proto->Spells[idx].SpellCategory;
|
||||
rec = proto->Spells[idx].SpellCooldown;
|
||||
catrec = proto->Spells[idx].SpellCategoryCooldown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no cooldown found above then base at DBC data
|
||||
if (rec < 0 && catrec < 0)
|
||||
{
|
||||
cat = spellInfo->GetCategory();
|
||||
rec = spellInfo->RecoveryTime;
|
||||
catrec = spellInfo->CategoryRecoveryTime;
|
||||
}
|
||||
|
||||
time_t curTime = time(NULL);
|
||||
|
||||
time_t catrecTime;
|
||||
time_t recTime;
|
||||
|
||||
bool needsCooldownPacket = false;
|
||||
|
||||
// overwrite time for selected category
|
||||
if (infinityCooldown)
|
||||
{
|
||||
// use +MONTH as infinity mark for spell cooldown (will checked as MONTH/2 at save ans skipped)
|
||||
// but not allow ignore until reset or re-login
|
||||
catrecTime = catrec > 0 ? curTime+infinityCooldownDelay : 0;
|
||||
recTime = rec > 0 ? curTime+infinityCooldownDelay : catrecTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
|
||||
// prevent 0 cooldowns set by another way
|
||||
if (rec <= 0 && catrec <= 0 && (cat == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75)))
|
||||
rec = GetAttackTime(RANGED_ATTACK);
|
||||
|
||||
// Now we have cooldown data (if found any), time to apply mods
|
||||
if (rec > 0)
|
||||
ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell);
|
||||
|
||||
if (catrec > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
|
||||
ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell);
|
||||
|
||||
if (int32 cooldownMod = GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
|
||||
{
|
||||
// Apply SPELL_AURA_MOD_COOLDOWN only to own spells
|
||||
if (HasSpell(spellInfo->Id))
|
||||
{
|
||||
needsCooldownPacket = true;
|
||||
rec += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks
|
||||
}
|
||||
}
|
||||
|
||||
// Apply SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN modifiers
|
||||
// Note: This aura applies its modifiers to all cooldowns of spells with set category, not to category cooldown only
|
||||
if (cat)
|
||||
@@ -22656,121 +22300,9 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
|
||||
}
|
||||
}
|
||||
|
||||
// replace negative cooldowns by 0
|
||||
if (rec < 0)
|
||||
rec = 0;
|
||||
|
||||
if (catrec < 0)
|
||||
catrec = 0;
|
||||
|
||||
// no cooldown after applying spell mods
|
||||
if (rec == 0 && catrec == 0)
|
||||
return;
|
||||
|
||||
catrecTime = catrec ? curTime+catrec/IN_MILLISECONDS : 0;
|
||||
recTime = rec ? curTime+rec/IN_MILLISECONDS : catrecTime;
|
||||
}
|
||||
|
||||
// self spell cooldown
|
||||
if (recTime > 0)
|
||||
{
|
||||
AddSpellCooldown(spellInfo->Id, itemId, recTime);
|
||||
|
||||
if (needsCooldownPacket)
|
||||
{
|
||||
WorldPacket data;
|
||||
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, rec);
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
// category spells
|
||||
if (cat && catrec > 0)
|
||||
{
|
||||
SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat);
|
||||
if (i_scstore != sSpellsByCategoryStore.end())
|
||||
{
|
||||
for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
|
||||
{
|
||||
if (*i_scset == spellInfo->Id) // skip main spell, already handled above
|
||||
continue;
|
||||
|
||||
AddSpellCooldown(*i_scset, itemId, catrecTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time)
|
||||
{
|
||||
SpellCooldown sc;
|
||||
sc.end = end_time;
|
||||
sc.itemid = itemid;
|
||||
m_spellCooldowns[spellid] = sc;
|
||||
}
|
||||
|
||||
void Player::ModifySpellCooldown(uint32 spellId, int32 cooldown)
|
||||
{
|
||||
SpellCooldowns::iterator itr = m_spellCooldowns.find(spellId);
|
||||
if (itr == m_spellCooldowns.end())
|
||||
return;
|
||||
|
||||
time_t now = time(NULL);
|
||||
if (itr->second.end + (cooldown / IN_MILLISECONDS) > now)
|
||||
itr->second.end += (cooldown / IN_MILLISECONDS);
|
||||
else
|
||||
m_spellCooldowns.erase(itr);
|
||||
|
||||
WorldPacket data(SMSG_MODIFY_COOLDOWN, 4 + 8 + 4);
|
||||
data << uint32(spellId); // Spell ID
|
||||
data << uint64(GetGUID()); // Player GUID
|
||||
data << int32(cooldown); // Cooldown mod in milliseconds
|
||||
GetSession()->SendPacket(&data);
|
||||
|
||||
TC_LOG_DEBUG("misc", "ModifySpellCooldown:: Player: %s (GUID: %u) Spell: %u cooldown: %u", GetName().c_str(), GetGUIDLow(), spellId, GetSpellCooldownDelay(spellId));
|
||||
}
|
||||
|
||||
void Player::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= NULL*/, bool setCooldown /*= true*/)
|
||||
{
|
||||
// start cooldowns at server side, if any
|
||||
if (setCooldown)
|
||||
AddSpellAndCategoryCooldowns(spellInfo, itemId, spell);
|
||||
|
||||
// Send activate cooldown timer (possible 0) at client side
|
||||
WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
|
||||
data << uint32(spellInfo->Id);
|
||||
data << uint64(GetGUID());
|
||||
SendDirectMessage(&data);
|
||||
|
||||
uint32 cat = spellInfo->GetCategory();
|
||||
if (cat && spellInfo->CategoryRecoveryTime)
|
||||
{
|
||||
SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat);
|
||||
if (ct != sSpellsByCategoryStore.end())
|
||||
{
|
||||
SpellCategorySet const& catSet = ct->second;
|
||||
for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end(); ++i)
|
||||
{
|
||||
if (i->first == spellInfo->Id) // skip main spell, already handled above
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(i->first);
|
||||
if (!spellInfo2 || !spellInfo2->IsCooldownStartedOnEvent())
|
||||
continue;
|
||||
|
||||
if (catSet.find(i->first) != catSet.end())
|
||||
{
|
||||
// Send activate cooldown timer (possible 0) at client side
|
||||
WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
|
||||
data << uint32(i->first);
|
||||
data << uint64(GetGUID());
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdatePotionCooldown(Spell* spell)
|
||||
{
|
||||
// no potion used i combat or still in combat
|
||||
@@ -22782,14 +22314,14 @@ void Player::UpdatePotionCooldown(Spell* spell)
|
||||
{
|
||||
// spell/item pair let set proper cooldown (except not existed charged spell cooldown spellmods for potions)
|
||||
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(m_lastPotionId))
|
||||
for (uint8 idx = 0; idx < MAX_ITEM_SPELLS; ++idx)
|
||||
for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx)
|
||||
if (proto->Spells[idx].SpellId && proto->Spells[idx].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[idx].SpellId))
|
||||
SendCooldownEvent(spellInfo, m_lastPotionId);
|
||||
GetSpellHistory()->SendCooldownEvent(spellInfo, m_lastPotionId);
|
||||
}
|
||||
// from spell cases (m_lastPotionId set in Spell::SendSpellCooldown)
|
||||
else
|
||||
SendCooldownEvent(spell->m_spellInfo, m_lastPotionId, spell);
|
||||
GetSpellHistory()->SendCooldownEvent(spell->m_spellInfo, m_lastPotionId, spell);
|
||||
|
||||
m_lastPotionId = 0;
|
||||
}
|
||||
@@ -23703,14 +23235,13 @@ void Player::ApplyEquipCooldown(Item* pItem)
|
||||
continue;
|
||||
|
||||
// Don't replace longer cooldowns by equip cooldown if we have any.
|
||||
SpellCooldowns::iterator itr = m_spellCooldowns.find(spellData.SpellId);
|
||||
if (itr != m_spellCooldowns.end() && itr->second.itemid == pItem->GetEntry() && itr->second.end > time(NULL) + 30)
|
||||
if (GetSpellHistory()->GetRemainingCooldown(spellData.SpellId) > 30 * IN_MILLISECONDS)
|
||||
continue;
|
||||
|
||||
AddSpellCooldown(spellData.SpellId, pItem->GetEntry(), time(NULL) + 30);
|
||||
GetSpellHistory()->AddCooldown(spellData.SpellId, pItem->GetEntry(), std::chrono::seconds(30));
|
||||
|
||||
WorldPacket data(SMSG_ITEM_COOLDOWN, 12);
|
||||
data << pItem->GetGUID();
|
||||
WorldPacket data(SMSG_ITEM_COOLDOWN, 8 + 4);
|
||||
data << uint64(pItem->GetGUID());
|
||||
data << uint32(spellData.SpellId);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
@@ -24582,7 +24113,7 @@ uint32 Player::GetResurrectionSpellId()
|
||||
}
|
||||
|
||||
// Reincarnation (passive spell) // prio: 1 // Glyph of Renewed Life
|
||||
if (prio < 1 && HasSpell(20608) && !HasSpellCooldown(21169) && (HasAura(58059) || HasItemCount(17030)))
|
||||
if (prio < 1 && HasSpell(20608) && !GetSpellHistory()->HasCooldown(21169) && (HasAura(58059) || HasItemCount(17030)))
|
||||
spell_id = 21169;
|
||||
|
||||
return spell_id;
|
||||
@@ -26708,14 +26239,6 @@ void Player::RemoveAtLoginFlag(AtLoginFlags flags, bool persist /*= false*/)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::SendClearCooldown(uint32 spell_id, Unit* target)
|
||||
{
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
|
||||
data << uint32(spell_id);
|
||||
data << uint64(target->GetGUID());
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
|
||||
void Player::SendClearAllCooldowns(Unit* target)
|
||||
{
|
||||
uint32 spellCount = m_spellCooldowns.size();
|
||||
|
||||
@@ -276,13 +276,6 @@ struct CUFProfile
|
||||
// More fields can be added to BoolOptions without changing DB schema (up to 32, currently 27)
|
||||
};
|
||||
|
||||
struct SpellCooldown
|
||||
{
|
||||
time_t end;
|
||||
uint16 itemid;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, SpellCooldown> SpellCooldowns;
|
||||
typedef std::unordered_map<uint32 /*instanceId*/, time_t/*releaseTime*/> InstanceTimeMap;
|
||||
|
||||
enum TrainerSpellState
|
||||
@@ -489,9 +482,9 @@ struct Runes
|
||||
|
||||
struct EnchantDuration
|
||||
{
|
||||
EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { };
|
||||
EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { }
|
||||
EnchantDuration(Item* _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot),
|
||||
leftduration(_leftduration){ ASSERT(item); };
|
||||
leftduration(_leftduration){ ASSERT(item); }
|
||||
|
||||
Item* item;
|
||||
EnchantmentSlot slot;
|
||||
@@ -1858,8 +1851,6 @@ class Player : public Unit, public GridObject<Player>
|
||||
PlayerSpellMap const& GetSpellMap() const { return m_spells; }
|
||||
PlayerSpellMap & GetSpellMap() { return m_spells; }
|
||||
|
||||
SpellCooldowns const& GetSpellCooldownMap() const { return m_spellCooldowns; }
|
||||
|
||||
void AddSpellMod(SpellModifier* mod, bool apply);
|
||||
bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = NULL);
|
||||
template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell = NULL);
|
||||
@@ -1869,27 +1860,8 @@ class Player : public Unit, public GridObject<Player>
|
||||
void DropModCharge(SpellModifier* mod, Spell* spell);
|
||||
void SetSpellModTakingSpell(Spell* spell, bool apply);
|
||||
|
||||
static uint32 const infinityCooldownDelay = MONTH; // used for set "infinity cooldowns" for spells and check
|
||||
static uint32 const infinityCooldownDelayCheck = MONTH/2;
|
||||
bool HasSpellCooldown(uint32 spell_id) const;
|
||||
uint32 GetSpellCooldownDelay(uint32 spell_id) const;
|
||||
void AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false);
|
||||
void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);
|
||||
void ModifySpellCooldown(uint32 spellId, int32 cooldown);
|
||||
void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = NULL, bool setCooldown = true);
|
||||
void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
|
||||
void RemoveSpellCooldown(uint32 spell_id, bool update = false);
|
||||
void RemoveSpellCategoryCooldown(uint32 cat, bool update = false);
|
||||
void SendClearCooldown(uint32 spell_id, Unit* target);
|
||||
void SendClearAllCooldowns(Unit* target);
|
||||
|
||||
GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; }
|
||||
|
||||
void RemoveCategoryCooldown(uint32 cat);
|
||||
void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false);
|
||||
void RemoveAllSpellCooldown();
|
||||
void _LoadSpellCooldowns(PreparedQueryResult result);
|
||||
void _SaveSpellCooldowns(SQLTransaction& trans);
|
||||
uint32 GetLastPotionId() { return m_lastPotionId; }
|
||||
void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; }
|
||||
void UpdatePotionCooldown(Spell* spell = NULL);
|
||||
@@ -2083,7 +2055,7 @@ class Player : public Unit, public GridObject<Player>
|
||||
bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
|
||||
void UpdateUnderwaterState(Map* m, float x, float y, float z) override;
|
||||
|
||||
void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet
|
||||
void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); }// overwrite Object::SendMessageToSet
|
||||
void SendMessageToSetInRange(WorldPacket* data, float fist, bool self) override;// overwrite Object::SendMessageToSetInRange
|
||||
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only);
|
||||
void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) override;
|
||||
@@ -2178,8 +2150,6 @@ class Player : public Unit, public GridObject<Player>
|
||||
|
||||
//End of PvP System
|
||||
|
||||
inline SpellCooldowns GetSpellCooldowns() const { return m_spellCooldowns; }
|
||||
|
||||
void SetDrunkValue(uint8 newDrunkValue, uint32 itemId = 0);
|
||||
uint8 GetDrunkValue() const { return GetByteValue(PLAYER_BYTES_3, 1); }
|
||||
static DrunkenState GetDrunkenstateByValue(uint8 value);
|
||||
@@ -2754,8 +2724,6 @@ class Player : public Unit, public GridObject<Player>
|
||||
PlayerSpellMap m_spells;
|
||||
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
|
||||
|
||||
GlobalCooldownMgr m_GlobalCooldownMgr;
|
||||
|
||||
PlayerTalentInfo* _talentMgr;
|
||||
|
||||
ActionButtonList m_actionButtons;
|
||||
@@ -2914,8 +2882,6 @@ class Player : public Unit, public GridObject<Player>
|
||||
AchievementMgr<Player>* m_achievementMgr;
|
||||
ReputationMgr* m_reputationMgr;
|
||||
|
||||
SpellCooldowns m_spellCooldowns;
|
||||
|
||||
uint32 m_ChampioningFaction;
|
||||
|
||||
std::queue<uint32> m_timeSyncQueue;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Group.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "WorldPacket.h"
|
||||
@@ -122,7 +123,7 @@ void Totem::UnSummon(uint32 msTime)
|
||||
owner->SendAutoRepeatCancel(this);
|
||||
|
||||
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
|
||||
owner->SendCooldownEvent(spell, 0, NULL, false);
|
||||
GetSpellHistory()->SendCooldownEvent(spell, 0, nullptr, false);
|
||||
|
||||
if (Group* group = owner->GetGroup())
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
Transport::Transport() : GameObject(),
|
||||
_transportInfo(NULL), _isMoving(true), _pendingStop(false),
|
||||
_triggeredArrivalEvent(false), _triggeredDepartureEvent(false),
|
||||
_passengerTeleportItr(_passengers.begin()), _delayedAddModel(false)
|
||||
_passengerTeleportItr(_passengers.begin()), _delayedAddModel(false), _delayedTeleport(false)
|
||||
{
|
||||
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
|
||||
}
|
||||
@@ -173,13 +173,13 @@ void Transport::Update(uint32 diff)
|
||||
|
||||
MoveToNextWaypoint();
|
||||
|
||||
sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
|
||||
sScriptMgr->OnRelocate(this, _currentFrame->Node->NodeIndex, _currentFrame->Node->MapID, _currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ);
|
||||
|
||||
TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
|
||||
TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->NodeIndex, _currentFrame->Node->MapID, _currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ);
|
||||
|
||||
// Departure event
|
||||
if (_currentFrame->IsTeleportFrame())
|
||||
if (TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z, _nextFrame->InitialOrientation))
|
||||
if (TeleportTransport(_nextFrame->Node->MapID, _nextFrame->Node->LocX, _nextFrame->Node->LocY, _nextFrame->Node->LocZ, _nextFrame->InitialOrientation))
|
||||
return; // Update more in new map thread
|
||||
}
|
||||
|
||||
@@ -226,6 +226,14 @@ void Transport::Update(uint32 diff)
|
||||
sScriptMgr->OnTransportUpdate(this, diff);
|
||||
}
|
||||
|
||||
void Transport::DelayedUpdate(uint32 /*diff*/)
|
||||
{
|
||||
if (GetKeyFrames().size() <= 1)
|
||||
return;
|
||||
|
||||
DelayedTeleportTransport();
|
||||
}
|
||||
|
||||
void Transport::AddPassenger(WorldObject* passenger)
|
||||
{
|
||||
if (!IsInWorld())
|
||||
@@ -600,36 +608,8 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
|
||||
|
||||
if (oldMap->GetId() != newMapid)
|
||||
{
|
||||
Map* newMap = sMapMgr->CreateBaseMap(newMapid);
|
||||
_delayedTeleport = true;
|
||||
UnloadStaticPassengers();
|
||||
GetMap()->RemoveFromMap<Transport>(this, false);
|
||||
SetMap(newMap);
|
||||
|
||||
for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();)
|
||||
{
|
||||
WorldObject* obj = (*_passengerTeleportItr++);
|
||||
|
||||
float destX, destY, destZ, destO;
|
||||
obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
|
||||
TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
|
||||
|
||||
switch (obj->GetTypeId())
|
||||
{
|
||||
case TYPEID_PLAYER:
|
||||
if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
|
||||
RemovePassenger(obj);
|
||||
break;
|
||||
case TYPEID_DYNAMICOBJECT:
|
||||
obj->AddObjectToRemoveList();
|
||||
break;
|
||||
default:
|
||||
RemovePassenger(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Relocate(x, y, z, o);
|
||||
GetMap()->AddToMap<Transport>(this);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -652,6 +632,48 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
|
||||
}
|
||||
}
|
||||
|
||||
void Transport::DelayedTeleportTransport()
|
||||
{
|
||||
if (!_delayedTeleport)
|
||||
return;
|
||||
|
||||
_delayedTeleport = false;
|
||||
Map* newMap = sMapMgr->CreateBaseMap(_nextFrame->Node->MapID);
|
||||
GetMap()->RemoveFromMap<Transport>(this, false);
|
||||
SetMap(newMap);
|
||||
|
||||
float x = _nextFrame->Node->LocX,
|
||||
y = _nextFrame->Node->LocY,
|
||||
z = _nextFrame->Node->LocZ,
|
||||
o =_nextFrame->InitialOrientation;
|
||||
|
||||
for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();)
|
||||
{
|
||||
WorldObject* obj = (*_passengerTeleportItr++);
|
||||
|
||||
float destX, destY, destZ, destO;
|
||||
obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
|
||||
TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
|
||||
|
||||
switch (obj->GetTypeId())
|
||||
{
|
||||
case TYPEID_PLAYER:
|
||||
if (!obj->ToPlayer()->TeleportTo(_nextFrame->Node->MapID, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
|
||||
RemovePassenger(obj);
|
||||
break;
|
||||
case TYPEID_DYNAMICOBJECT:
|
||||
obj->AddObjectToRemoveList();
|
||||
break;
|
||||
default:
|
||||
RemovePassenger(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Relocate(x, y, z, o);
|
||||
GetMap()->AddToMap<Transport>(this);
|
||||
}
|
||||
|
||||
void Transport::UpdatePassengerPositions(PassengerSet& passengers)
|
||||
{
|
||||
for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
|
||||
@@ -706,9 +728,9 @@ void Transport::UpdatePassengerPositions(PassengerSet& passengers)
|
||||
|
||||
void Transport::DoEventIfAny(KeyFrame const& node, bool departure)
|
||||
{
|
||||
if (uint32 eventid = departure ? node.Node->departureEventID : node.Node->arrivalEventID)
|
||||
if (uint32 eventid = departure ? node.Node->DepartureEventID : node.Node->ArrivalEventID)
|
||||
{
|
||||
TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->index, GetName().c_str());
|
||||
TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->NodeIndex, GetName().c_str());
|
||||
GetMap()->ScriptsStart(sEventScripts, eventid, this, this);
|
||||
EventInform(eventid);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class Transport : public GameObject, public TransportBase
|
||||
void CleanupsBeforeDelete(bool finalCleanup = true) override;
|
||||
|
||||
void Update(uint32 diff) override;
|
||||
void DelayedUpdate(uint32 diff);
|
||||
|
||||
void BuildUpdate(UpdateDataMapType& data_map) override;
|
||||
|
||||
@@ -103,6 +104,7 @@ class Transport : public GameObject, public TransportBase
|
||||
void MoveToNextWaypoint();
|
||||
float CalculateSegmentPos(float perc);
|
||||
bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o);
|
||||
void DelayedTeleportTransport();
|
||||
void UpdatePassengerPositions(PassengerSet& passengers);
|
||||
void DoEventIfAny(KeyFrame const& node, bool departure);
|
||||
|
||||
@@ -127,6 +129,7 @@ class Transport : public GameObject, public TransportBase
|
||||
PassengerSet _staticPassengers;
|
||||
|
||||
bool _delayedAddModel;
|
||||
bool _delayedTeleport;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "SpellAuras.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Totem.h"
|
||||
@@ -163,7 +164,7 @@ Unit::Unit(bool isWorldObject) :
|
||||
i_AI(NULL), i_disabledAI(NULL), m_AutoRepeatFirstCast(false), m_procDeep(0),
|
||||
m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_ThreatManager(this),
|
||||
m_vehicle(NULL), m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE),
|
||||
m_HostileRefManager(this), _lastDamagedTime(0)
|
||||
m_HostileRefManager(this), _lastDamagedTime(0), m_spellHistory(new SpellHistory(this))
|
||||
{
|
||||
m_objectType |= TYPEMASK_UNIT;
|
||||
m_objectTypeId = TYPEID_UNIT;
|
||||
@@ -259,24 +260,6 @@ Unit::Unit(bool isWorldObject) :
|
||||
_meleeAnimKitId = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Methods of class GlobalCooldownMgr
|
||||
bool GlobalCooldownMgr::HasGlobalCooldown(SpellInfo const* spellInfo) const
|
||||
{
|
||||
GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory);
|
||||
return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration;
|
||||
}
|
||||
|
||||
void GlobalCooldownMgr::AddGlobalCooldown(SpellInfo const* spellInfo, uint32 gcd)
|
||||
{
|
||||
m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime());
|
||||
}
|
||||
|
||||
void GlobalCooldownMgr::CancelGlobalCooldown(SpellInfo const* spellInfo)
|
||||
{
|
||||
m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Methods of class Unit
|
||||
Unit::~Unit()
|
||||
@@ -294,6 +277,7 @@ Unit::~Unit()
|
||||
delete i_motionMaster;
|
||||
delete m_charmInfo;
|
||||
delete movespline;
|
||||
delete m_spellHistory;
|
||||
|
||||
ASSERT(!m_duringRemoveFromWorld);
|
||||
ASSERT(!m_attacking);
|
||||
@@ -2702,6 +2686,8 @@ void Unit::_UpdateSpells(uint32 time)
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
m_spellHistory->Update();
|
||||
}
|
||||
|
||||
void Unit::_UpdateAutoRepeatSpell()
|
||||
@@ -4641,13 +4627,13 @@ void Unit::AddGameObject(GameObject* gameObj)
|
||||
m_gameObj.push_back(gameObj);
|
||||
gameObj->SetOwnerGUID(GetGUID());
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER && gameObj->GetSpellId())
|
||||
if (gameObj->GetSpellId())
|
||||
{
|
||||
SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId());
|
||||
// Need disable spell use for owner
|
||||
if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
|
||||
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
|
||||
ToPlayer()->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true);
|
||||
GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4672,14 +4658,11 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del)
|
||||
{
|
||||
RemoveAurasDueToSpell(spellid);
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid);
|
||||
// Need activate spell use for owner
|
||||
if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
|
||||
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
|
||||
ToPlayer()->SendCooldownEvent(createBySpell);
|
||||
}
|
||||
SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid);
|
||||
// Need activate spell use for owner
|
||||
if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
|
||||
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
|
||||
GetSpellHistory()->SendCooldownEvent(createBySpell);
|
||||
}
|
||||
|
||||
m_gameObj.remove(gameObj);
|
||||
@@ -5387,8 +5370,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
|
||||
for (std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
|
||||
{
|
||||
if (!ToPlayer()->HasSpellCooldown(*itr))
|
||||
ToPlayer()->AddSpellCooldown(*itr, 0, time(NULL) + cooldown);
|
||||
if (!GetSpellHistory()->HasCooldown(*itr))
|
||||
GetSpellHistory()->AddCooldown(*itr, 0, std::chrono::seconds(cooldown));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5433,8 +5416,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
|
||||
for (std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
|
||||
{
|
||||
if (!ToPlayer()->HasSpellCooldown(*itr))
|
||||
ToPlayer()->AddSpellCooldown(*itr, 0, time(NULL) + cooldown);
|
||||
if (!GetSpellHistory()->HasCooldown(*itr))
|
||||
GetSpellHistory()->AddCooldown(*itr, 0, std::chrono::seconds(cooldown));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5683,9 +5666,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
|
||||
target = this;
|
||||
triggered_spell_id = 34299;
|
||||
// Regenerate 4% mana
|
||||
int32 mana = CalculatePct(GetCreateMana(), triggerAmount);
|
||||
CastCustomSpell(this, 68285, &mana, NULL, NULL, true, castItem, triggeredByAura);
|
||||
if (triggeredByAura->GetCasterGUID() != GetGUID())
|
||||
break;
|
||||
int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2);
|
||||
// Improved Leader of the Pack
|
||||
// Check cooldown of heal spell cooldown
|
||||
if (!GetSpellHistory()->HasCooldown(34299))
|
||||
CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura);
|
||||
break;
|
||||
}
|
||||
// Healing Touch (Dreamwalker Raiment set)
|
||||
@@ -6022,7 +6009,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
return false;
|
||||
|
||||
// custom cooldown processing case
|
||||
if (cooldown && player->HasSpellCooldown(dummySpell->Id))
|
||||
if (cooldown && GetSpellHistory()->HasCooldown(dummySpell->Id))
|
||||
return false;
|
||||
|
||||
if (triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID())
|
||||
@@ -6069,7 +6056,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
|
||||
// apply cooldown before cast to prevent processing itself
|
||||
if (cooldown)
|
||||
player->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
|
||||
player->GetSpellHistory()->AddCooldown(dummySpell->Id, 0, std::chrono::seconds(cooldown));
|
||||
|
||||
// Attack Twice
|
||||
for (uint32 i = 0; i < 2; ++i)
|
||||
@@ -6252,8 +6239,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
uint32 spell = 26364;
|
||||
|
||||
// custom cooldown processing case
|
||||
if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(spell))
|
||||
ToPlayer()->RemoveSpellCooldown(spell);
|
||||
if (GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(spell))
|
||||
GetSpellHistory()->ResetCooldown(spell);
|
||||
|
||||
CastSpell(target, spell, true, castItem, triggeredByAura);
|
||||
return true;
|
||||
@@ -6400,7 +6387,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
if (cooldown_spell_id == 0)
|
||||
cooldown_spell_id = triggered_spell_id;
|
||||
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(cooldown_spell_id))
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(cooldown_spell_id))
|
||||
return false;
|
||||
|
||||
if (basepoints0)
|
||||
@@ -6409,7 +6396,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster);
|
||||
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER)
|
||||
ToPlayer()->AddSpellCooldown(cooldown_spell_id, 0, time(NULL) + cooldown);
|
||||
GetSpellHistory()->AddCooldown(cooldown_spell_id, 0, std::chrono::seconds(cooldown));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -6596,9 +6583,9 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 /*damage*/, Aura* triggeredByAura
|
||||
*handled = true;
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (ToPlayer()->HasSpellCooldown(100000))
|
||||
if (GetSpellHistory()->HasCooldown(100000))
|
||||
return false;
|
||||
ToPlayer()->AddSpellCooldown(100000, 0, time(NULL) + cooldown);
|
||||
GetSpellHistory()->AddCooldown(100000, 0, std::chrono::seconds(cooldown));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -7073,6 +7060,9 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
|
||||
}
|
||||
break;
|
||||
}
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
|
||||
return spellInfo && spellInfo->GetCategory() == 1209;
|
||||
}, true);
|
||||
// Maelstrom Weapon
|
||||
case 53817:
|
||||
{
|
||||
@@ -7125,7 +7115,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
|
||||
}
|
||||
}
|
||||
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id))
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(trigger_spell_id))
|
||||
return false;
|
||||
|
||||
// extra attack should hit same target
|
||||
@@ -7142,7 +7132,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
|
||||
CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
|
||||
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER)
|
||||
ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
|
||||
GetSpellHistory()->AddCooldown(trigger_spell_id, 0, std::chrono::seconds(cooldown));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -7197,13 +7187,13 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, Au
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(triggered_spell_id))
|
||||
return false;
|
||||
|
||||
CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura);
|
||||
|
||||
if (cooldown && GetTypeId() == TYPEID_PLAYER)
|
||||
ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
|
||||
GetSpellHistory()->AddCooldown(triggered_spell_id, 0, std::chrono::seconds(cooldown));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -7934,14 +7924,11 @@ void Unit::SetMinion(Minion *minion, bool apply)
|
||||
if (minion->IsPetGhoul())
|
||||
minion->setPowerType(POWER_ENERGY);
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
// Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
|
||||
// Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
|
||||
|
||||
if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
|
||||
ToPlayer()->AddSpellAndCategoryCooldowns(spellInfo, 0, NULL, true);
|
||||
}
|
||||
if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
|
||||
GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -7975,13 +7962,10 @@ void Unit::SetMinion(Minion *minion, bool apply)
|
||||
}
|
||||
}
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
|
||||
// Remove infinity cooldown
|
||||
if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
|
||||
ToPlayer()->SendCooldownEvent(spellInfo);
|
||||
}
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
|
||||
// Remove infinity cooldown
|
||||
if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
|
||||
GetSpellHistory()->SendCooldownEvent(spellInfo);
|
||||
|
||||
//if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
|
||||
{
|
||||
@@ -8542,11 +8526,15 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
|
||||
DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
|
||||
}
|
||||
|
||||
// Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods.
|
||||
float tmpDamage = (int32(pdamage) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellDamagePctDone(victim, spellProto, damagetype));
|
||||
// apply spellmod to Done damage (flat and pct)
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
|
||||
float tmpDamage = float(int32(pdamage) + DoneTotal);
|
||||
// SPELLMOD_DOT will be applied in AuraEffect::HandlePeriodicDamageAurasTick.
|
||||
if (damagetype != DOT)
|
||||
{
|
||||
tmpDamage *= SpellDamagePctDone(victim, spellProto, damagetype);
|
||||
// apply spellmod to Done damage (flat and pct)
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
|
||||
}
|
||||
|
||||
return uint32(std::max(tmpDamage, 0.0f));
|
||||
}
|
||||
@@ -9251,11 +9239,15 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
|
||||
DoneTotal = 0;
|
||||
}
|
||||
|
||||
// Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods.
|
||||
float heal = float(int32(healamount) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellHealingPctDone(victim, spellProto));
|
||||
// apply spellmod to Done amount
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
|
||||
float heal = float(int32(healamount) + DoneTotal);
|
||||
// SPELLMOD_DOT will be applied in AuraEffect::HandlePeriodicHealAurasTick.
|
||||
if (damagetype != DOT)
|
||||
{
|
||||
heal *= SpellHealingPctDone(victim, spellProto);
|
||||
// apply spellmod to Done amount
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, heal);
|
||||
}
|
||||
|
||||
return uint32(std::max(heal, 0.0f));
|
||||
}
|
||||
@@ -14854,6 +14846,9 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
|
||||
float vcos, vsin;
|
||||
GetSinCos(x, y, vsin, vcos);
|
||||
SendMoveKnockBack(player, speedXY, -speedZ, vcos, vsin);
|
||||
|
||||
if (player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || player->HasAuraType(SPELL_AURA_FLY))
|
||||
player->SetCanFly(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16320,7 +16315,7 @@ bool Unit::SetSwim(bool enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Unit::SetCanFly(bool enable)
|
||||
bool Unit::SetCanFly(bool enable, bool /*packetOnly = false */)
|
||||
{
|
||||
if (enable == HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY))
|
||||
return false;
|
||||
@@ -16642,27 +16637,6 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
|
||||
data->append(fieldBuffer);
|
||||
}
|
||||
|
||||
void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown)
|
||||
{
|
||||
data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4);
|
||||
data << uint64(GetGUID());
|
||||
data << uint8(flags);
|
||||
data << uint32(spellId);
|
||||
data << uint32(cooldown);
|
||||
}
|
||||
|
||||
void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns)
|
||||
{
|
||||
data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + (4 + 4) * cooldowns.size());
|
||||
data << uint64(GetGUID());
|
||||
data << uint8(flags);
|
||||
for (std::unordered_map<uint32, uint32>::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr)
|
||||
{
|
||||
data << uint32(itr->first);
|
||||
data << uint32(itr->second);
|
||||
}
|
||||
}
|
||||
|
||||
int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
|
||||
{
|
||||
int32 val = 0;
|
||||
|
||||
@@ -274,13 +274,6 @@ enum UnitRename
|
||||
#define MAX_AGGRO_RESET_TIME 10 // in seconds
|
||||
#define MAX_AGGRO_RADIUS 45.0f // yards
|
||||
|
||||
enum Swing
|
||||
{
|
||||
NOSWING = 0,
|
||||
SINGLEHANDEDSWING = 1,
|
||||
TWOHANDEDSWING = 2
|
||||
};
|
||||
|
||||
enum VictimState
|
||||
{
|
||||
VICTIMSTATE_INTACT = 0, // set when attacker misses
|
||||
@@ -340,6 +333,7 @@ class AuraEffect;
|
||||
class Creature;
|
||||
class Spell;
|
||||
class SpellInfo;
|
||||
class SpellHistory;
|
||||
class DynamicObject;
|
||||
class GameObject;
|
||||
class Item;
|
||||
@@ -361,7 +355,7 @@ namespace Movement
|
||||
}
|
||||
|
||||
typedef std::list<Unit*> UnitList;
|
||||
typedef std::list< std::pair<Aura*, uint8> > DispelChargesList;
|
||||
typedef std::list<std::pair<Aura*, uint8>> DispelChargesList;
|
||||
|
||||
struct SpellImmune
|
||||
{
|
||||
@@ -386,13 +380,6 @@ enum WeaponDamageRange
|
||||
MAXDAMAGE
|
||||
};
|
||||
|
||||
enum DamageTypeToSchool
|
||||
{
|
||||
RESISTANCE,
|
||||
DAMAGE_DEALT,
|
||||
DAMAGE_TAKEN
|
||||
};
|
||||
|
||||
enum AuraRemoveMode
|
||||
{
|
||||
AURA_REMOVE_NONE = 0,
|
||||
@@ -1047,30 +1034,6 @@ enum CurrentSpellTypes
|
||||
#define CURRENT_FIRST_NON_MELEE_SPELL 1
|
||||
#define CURRENT_MAX_SPELL 4
|
||||
|
||||
struct GlobalCooldown
|
||||
{
|
||||
explicit GlobalCooldown(uint32 _dur = 0, uint32 _time = 0) : duration(_dur), cast_time(_time) { }
|
||||
|
||||
uint32 duration;
|
||||
uint32 cast_time;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32 /*category*/, GlobalCooldown> GlobalCooldownList;
|
||||
|
||||
class GlobalCooldownMgr // Shared by Player and CharmInfo
|
||||
{
|
||||
public:
|
||||
GlobalCooldownMgr() { }
|
||||
|
||||
public:
|
||||
bool HasGlobalCooldown(SpellInfo const* spellInfo) const;
|
||||
void AddGlobalCooldown(SpellInfo const* spellInfo, uint32 gcd);
|
||||
void CancelGlobalCooldown(SpellInfo const* spellInfo);
|
||||
|
||||
private:
|
||||
GlobalCooldownList m_GlobalCooldowns;
|
||||
};
|
||||
|
||||
enum ActiveStates
|
||||
{
|
||||
ACT_PASSIVE = 0x01, // 0x01 - passive
|
||||
@@ -1188,8 +1151,6 @@ struct CharmInfo
|
||||
|
||||
CharmSpellInfo* GetCharmSpell(uint8 index) { return &(_charmspells[index]); }
|
||||
|
||||
GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; }
|
||||
|
||||
void SetIsCommandAttack(bool val);
|
||||
bool IsCommandAttack();
|
||||
void SetIsCommandFollow(bool val);
|
||||
@@ -1222,8 +1183,6 @@ struct CharmInfo
|
||||
float _stayX;
|
||||
float _stayY;
|
||||
float _stayZ;
|
||||
|
||||
GlobalCooldownMgr m_GlobalCooldownMgr;
|
||||
};
|
||||
|
||||
// for clearing special attacks
|
||||
@@ -1254,16 +1213,6 @@ enum PlayerTotemType
|
||||
SUMMON_TYPE_TOTEM_AIR = 83
|
||||
};
|
||||
|
||||
/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN
|
||||
enum SpellCooldownFlags
|
||||
{
|
||||
SPELL_COOLDOWN_FLAG_NONE = 0x0,
|
||||
SPELL_COOLDOWN_FLAG_INCLUDE_GCD = 0x1, ///< Starts GCD in addition to normal cooldown specified in the packet
|
||||
SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS = 0x2 ///< Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUDE_GCD set
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32, uint32> PacketCooldowns;
|
||||
|
||||
// delay time next attack to prevent client attack animation problems
|
||||
#define ATTACK_DISPLAY_DELAY 200
|
||||
#define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player
|
||||
@@ -1600,8 +1549,6 @@ class Unit : public WorldObject
|
||||
Aura* AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target);
|
||||
void SetAuraStack(uint32 spellId, Unit* target, uint32 stack);
|
||||
void SendPlaySpellVisualKit(uint32 id, uint32 unkParam);
|
||||
void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown);
|
||||
void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns);
|
||||
|
||||
void DeMorph();
|
||||
|
||||
@@ -1862,7 +1809,6 @@ class Unit : public WorldObject
|
||||
void SetChannelObjectGuid(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_CHANNEL_OBJECT, guid); }
|
||||
|
||||
void SetCurrentCastSpell(Spell* pSpell);
|
||||
virtual void ProhibitSpellSchool(SpellSchoolMask /*idSchoolMask*/, uint32 /*unTimeMs*/) { }
|
||||
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed = true, bool withInstant = true);
|
||||
void FinishSpell(CurrentSpellTypes spellType, bool ok = true);
|
||||
|
||||
@@ -1880,6 +1826,9 @@ class Unit : public WorldObject
|
||||
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
|
||||
int32 GetCurrentSpellCastTime(uint32 spell_id) const;
|
||||
|
||||
SpellHistory* GetSpellHistory() { return m_spellHistory; }
|
||||
SpellHistory const* GetSpellHistory() const { return m_spellHistory; }
|
||||
|
||||
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT];
|
||||
ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT];
|
||||
|
||||
@@ -1950,7 +1899,7 @@ class Unit : public WorldObject
|
||||
void TauntApply(Unit* victim);
|
||||
void TauntFadeOut(Unit* taunter);
|
||||
ThreatManager& getThreatManager() { return m_ThreatManager; }
|
||||
void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); };
|
||||
void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); }
|
||||
void removeHatedBy(HostileReference* /*pHostileReference*/) { /* nothing to do yet */ }
|
||||
HostileRefManager& getHostileRefManager() { return m_HostileRefManager; }
|
||||
|
||||
@@ -2312,6 +2261,7 @@ class Unit : public WorldObject
|
||||
|
||||
time_t _lastDamagedTime; // Part of Evade mechanics
|
||||
|
||||
SpellHistory* m_spellHistory;
|
||||
uint16 _aiAnimKitId;
|
||||
uint16 _movementAnimKitId;
|
||||
uint16 _meleeAnimKitId;
|
||||
|
||||
@@ -97,7 +97,7 @@ class GameEventMgr
|
||||
{
|
||||
private:
|
||||
GameEventMgr();
|
||||
~GameEventMgr() { };
|
||||
~GameEventMgr() { }
|
||||
|
||||
public:
|
||||
static GameEventMgr* instance()
|
||||
|
||||
@@ -1079,6 +1079,66 @@ void ObjectMgr::LoadCreatureAddons()
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u creature addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadGameObjectAddons()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2
|
||||
QueryResult result = WorldDatabase.Query("SELECT guid, invisibilityType, invisibilityValue FROM gameobject_addon");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 gameobject addon definitions. DB table `gameobject_addon` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
ObjectGuid::LowType guid = fields[0].GetUInt32();
|
||||
|
||||
const GameObjectData* goData = GetGOData(guid);
|
||||
if (!goData)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) does not exist but has a record in `gameobject_addon`", guid);
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObjectAddon& gameObjectAddon = _gameObjectAddonStore[guid];
|
||||
gameObjectAddon.invisibilityType = InvisibilityType(fields[1].GetUInt8());
|
||||
gameObjectAddon.InvisibilityValue = fields[2].GetUInt32();
|
||||
|
||||
if (gameObjectAddon.invisibilityType >= TOTAL_INVISIBILITY_TYPES)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) has invalid InvisibilityType in `gameobject_addon`", guid);
|
||||
gameObjectAddon.invisibilityType = INVISIBILITY_GENERAL;
|
||||
gameObjectAddon.InvisibilityValue = 0;
|
||||
}
|
||||
|
||||
if (gameObjectAddon.invisibilityType && !gameObjectAddon.InvisibilityValue)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) has InvisibilityType set but has no InvisibilityValue in `gameobject_addon`, set to 1", guid);
|
||||
gameObjectAddon.InvisibilityValue = 1;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u gameobject addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
GameObjectAddon const* ObjectMgr::GetGameObjectAddon(ObjectGuid::LowType lowguid)
|
||||
{
|
||||
GameObjectAddonContainer::const_iterator itr = _gameObjectAddonStore.find(lowguid);
|
||||
if (itr != _gameObjectAddonStore.end())
|
||||
return &(itr->second);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CreatureAddon const* ObjectMgr::GetCreatureAddon(uint32 lowguid)
|
||||
{
|
||||
CreatureAddonContainer::const_iterator itr = _creatureAddonStore.find(lowguid);
|
||||
@@ -5011,11 +5071,11 @@ void ObjectMgr::LoadEventScripts()
|
||||
{
|
||||
TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx];
|
||||
|
||||
if (node.arrivalEventID)
|
||||
evt_scripts.insert(node.arrivalEventID);
|
||||
if (node.ArrivalEventID)
|
||||
evt_scripts.insert(node.ArrivalEventID);
|
||||
|
||||
if (node.departureEventID)
|
||||
evt_scripts.insert(node.departureEventID);
|
||||
if (node.DepartureEventID)
|
||||
evt_scripts.insert(node.DepartureEventID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,12 +48,7 @@ struct AccessRequirement;
|
||||
struct PlayerInfo;
|
||||
struct PlayerLevelInfo;
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct PageText
|
||||
{
|
||||
@@ -81,12 +76,7 @@ private:
|
||||
uint8 _summonGroup; ///< Summon's group id
|
||||
};
|
||||
|
||||
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
// DB scripting commands
|
||||
enum ScriptCommands
|
||||
@@ -743,6 +733,7 @@ class ObjectMgr
|
||||
static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data = NULL);
|
||||
EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id);
|
||||
CreatureAddon const* GetCreatureAddon(uint32 lowguid);
|
||||
GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid);
|
||||
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry);
|
||||
ItemTemplate const* GetItemTemplate(uint32 entry);
|
||||
ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; }
|
||||
@@ -972,6 +963,7 @@ class ObjectMgr
|
||||
void LoadLinkedRespawn();
|
||||
bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid);
|
||||
void LoadCreatureAddons();
|
||||
void LoadGameObjectAddons();
|
||||
void LoadCreatureModelInfo();
|
||||
void LoadEquipmentTemplates();
|
||||
void LoadGameObjectLocales();
|
||||
@@ -1451,6 +1443,7 @@ class ObjectMgr
|
||||
CreatureModelContainer _creatureModelStore;
|
||||
CreatureAddonContainer _creatureAddonStore;
|
||||
CreatureAddonContainer _creatureTemplateAddonStore;
|
||||
GameObjectAddonContainer _gameObjectAddonStore;
|
||||
EquipmentInfoContainer _equipmentInfoStore;
|
||||
LinkedRespawnContainer _linkedRespawnStore;
|
||||
CreatureLocaleContainer _creatureLocaleStore;
|
||||
|
||||
@@ -1905,6 +1905,9 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
|
||||
// check if someone in party is using dungeon system
|
||||
if (member->isUsingLfg())
|
||||
return ERR_LFG_CANT_USE_BATTLEGROUND;
|
||||
// check Freeze debuff
|
||||
if (member->HasAura(9454))
|
||||
return ERR_BATTLEGROUND_JOIN_FAILED;
|
||||
}
|
||||
|
||||
// only check for MinPlayerCount since MinPlayerCount == MaxPlayerCount for arenas...
|
||||
|
||||
@@ -222,7 +222,7 @@ class Group
|
||||
ObjectGuid GetMasterLooterGuid() const;
|
||||
ItemQualities GetLootThreshold() const;
|
||||
|
||||
uint32 GetDbStoreId() const { return m_dbStoreId; };
|
||||
uint32 GetDbStoreId() const { return m_dbStoreId; }
|
||||
|
||||
// member manipulation methods
|
||||
bool IsMember(ObjectGuid guid) const;
|
||||
|
||||
@@ -194,6 +194,10 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
// check Freeze debuff
|
||||
if (_player->HasAura(9454))
|
||||
return;
|
||||
|
||||
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
|
||||
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
|
||||
|
||||
@@ -519,6 +523,10 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
|
||||
WorldPacket data;
|
||||
if (action)
|
||||
{
|
||||
// check Freeze debuff
|
||||
if (_player->HasAura(9454))
|
||||
return;
|
||||
|
||||
if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId))
|
||||
return; // cheating?
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "Pet.h"
|
||||
#include "World.h"
|
||||
#include "Group.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "Player.h"
|
||||
|
||||
@@ -361,8 +362,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
|
||||
|
||||
if (result == SPELL_CAST_OK)
|
||||
{
|
||||
pet->ToCreature()->AddCreatureSpellCooldown(spellid);
|
||||
|
||||
unit_target = spell->m_targets.GetUnitTarget();
|
||||
|
||||
//10% chance to play special pet attack talk, else growl
|
||||
@@ -396,8 +395,8 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
|
||||
else
|
||||
spell->SendPetCastResult(result);
|
||||
|
||||
if (!pet->ToCreature()->HasSpellCooldown(spellid))
|
||||
GetPlayer()->SendClearCooldown(spellid, pet);
|
||||
if (!pet->GetSpellHistory()->HasCooldown(spellid))
|
||||
pet->GetSpellHistory()->ResetCooldown(spellid, true);
|
||||
|
||||
spell->finish(false);
|
||||
delete spell;
|
||||
@@ -803,7 +802,6 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
if (Creature* creature = caster->ToCreature())
|
||||
{
|
||||
creature->AddCreatureSpellCooldown(spellId);
|
||||
if (Pet* pet = creature->ToPet())
|
||||
{
|
||||
// 10% chance to play special pet attack talk, else growl
|
||||
@@ -821,16 +819,8 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
spell->SendPetCastResult(result);
|
||||
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (!caster->ToPlayer()->HasSpellCooldown(spellId))
|
||||
GetPlayer()->SendClearCooldown(spellId, caster);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!caster->ToCreature()->HasSpellCooldown(spellId))
|
||||
GetPlayer()->SendClearCooldown(spellId, caster);
|
||||
}
|
||||
if (!caster->GetSpellHistory()->HasCooldown(spellId))
|
||||
caster->GetSpellHistory()->ResetCooldown(spellId, true);
|
||||
|
||||
spell->finish(false);
|
||||
delete spell;
|
||||
|
||||
@@ -536,8 +536,6 @@ void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket)
|
||||
}
|
||||
|
||||
pet->RemoveOwnedAura(spellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_CANCEL);
|
||||
|
||||
pet->AddCreatureSpellCooldown(spellId);
|
||||
}
|
||||
|
||||
void WorldSession::HandleCancelGrowthAuraOpcode(WorldPacket& /*recvPacket*/) { }
|
||||
|
||||
@@ -234,7 +234,7 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData)
|
||||
TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()];
|
||||
flight->SkipCurrentNode();
|
||||
|
||||
GetPlayer()->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, GetPlayer()->GetOrientation());
|
||||
GetPlayer()->TeleportTo(curDestNode->map_id, node.LocX, node.LocY, node.LocZ, GetPlayer()->GetOrientation());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -426,7 +426,26 @@ void InstanceScript::DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime /
|
||||
TC_LOG_ERROR("scripts", "InstanceScript: DoUseDoorOrButton can't use gameobject entry %u, because type is %u.", go->GetEntry(), go->GetGoType());
|
||||
}
|
||||
else
|
||||
TC_LOG_DEBUG("scripts", "InstanceScript: HandleGameObject failed");
|
||||
TC_LOG_DEBUG("scripts", "InstanceScript: DoUseDoorOrButton failed");
|
||||
}
|
||||
|
||||
void InstanceScript::DoCloseDoorOrButton(ObjectGuid guid)
|
||||
{
|
||||
if (!guid)
|
||||
return;
|
||||
|
||||
if (GameObject* go = instance->GetGameObject(guid))
|
||||
{
|
||||
if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR || go->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
|
||||
{
|
||||
if (go->getLootState() == GO_ACTIVATED)
|
||||
go->ResetDoorOrButton();
|
||||
}
|
||||
else
|
||||
TC_LOG_ERROR("scripts", "InstanceScript: DoCloseDoorOrButton can't use gameobject entry %u, because type is %u.", go->GetEntry(), go->GetGoType());
|
||||
}
|
||||
else
|
||||
TC_LOG_DEBUG("scripts", "InstanceScript: DoCloseDoorOrButton failed");
|
||||
}
|
||||
|
||||
void InstanceScript::DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn /*= MINUTE*/)
|
||||
|
||||
@@ -194,6 +194,7 @@ class InstanceScript : public ZoneScript
|
||||
|
||||
// Change active state of doors or buttons
|
||||
void DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime = 0, bool useAlternativeState = false);
|
||||
void DoCloseDoorOrButton(ObjectGuid guid);
|
||||
|
||||
// Respawns a GO having negative spawntimesecs in gameobject-table
|
||||
void DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn = MINUTE);
|
||||
|
||||
@@ -2586,6 +2586,17 @@ inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y)
|
||||
|
||||
void Map::DelayedUpdate(const uint32 t_diff)
|
||||
{
|
||||
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
|
||||
{
|
||||
Transport* transport = *_transportsUpdateIter;
|
||||
++_transportsUpdateIter;
|
||||
|
||||
if (!transport->IsInWorld())
|
||||
continue;
|
||||
|
||||
transport->DelayedUpdate(t_diff);
|
||||
}
|
||||
|
||||
RemoveAllObjectsInRemoveList();
|
||||
|
||||
// Don't unload grids if it's battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load !
|
||||
|
||||
@@ -210,12 +210,7 @@ public:
|
||||
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
|
||||
};
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct InstanceTemplate
|
||||
{
|
||||
@@ -241,11 +236,7 @@ struct ZoneDynamicInfo
|
||||
uint32 LightFadeInTime;
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface
|
||||
#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
|
||||
|
||||
@@ -112,7 +112,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
|
||||
Movement::PointsArray splinePath, allPoints;
|
||||
bool mapChange = false;
|
||||
for (size_t i = 0; i < path.size(); ++i)
|
||||
allPoints.push_back(G3D::Vector3(path[i].x, path[i].y, path[i].z));
|
||||
allPoints.push_back(G3D::Vector3(path[i].LocX, path[i].LocY, path[i].LocZ));
|
||||
|
||||
// Add extra points to allow derivative calculations for all path nodes
|
||||
allPoints.insert(allPoints.begin(), allPoints.front().lerp(allPoints[1], -0.2f));
|
||||
@@ -129,7 +129,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
|
||||
if (!mapChange)
|
||||
{
|
||||
TaxiPathNodeEntry const& node_i = path[i];
|
||||
if (i != path.size() - 1 && (node_i.actionFlag & 1 || node_i.mapid != path[i + 1].mapid))
|
||||
if (i != path.size() - 1 && (node_i.Flags & 1 || node_i.MapID != path[i + 1].MapID))
|
||||
{
|
||||
keyFrames.back().Teleport = true;
|
||||
mapChange = true;
|
||||
@@ -142,8 +142,8 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
|
||||
k.InitialOrientation = Position::NormalizeOrientation(std::atan2(h.y, h.x) + float(M_PI));
|
||||
|
||||
keyFrames.push_back(k);
|
||||
splinePath.push_back(G3D::Vector3(node_i.x, node_i.y, node_i.z));
|
||||
transport->mapsUsed.insert(k.Node->mapid);
|
||||
splinePath.push_back(G3D::Vector3(node_i.LocX, node_i.LocY, node_i.LocZ));
|
||||
transport->mapsUsed.insert(k.Node->MapID);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -153,12 +153,12 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
|
||||
if (splinePath.size() >= 2)
|
||||
{
|
||||
// Remove special catmull-rom spline points
|
||||
if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->arrivalEventID && !keyFrames.front().Node->departureEventID)
|
||||
if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->ArrivalEventID && !keyFrames.front().Node->DepartureEventID)
|
||||
{
|
||||
splinePath.erase(splinePath.begin());
|
||||
keyFrames.erase(keyFrames.begin());
|
||||
}
|
||||
if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->arrivalEventID && !keyFrames.back().Node->departureEventID)
|
||||
if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->ArrivalEventID && !keyFrames.back().Node->DepartureEventID)
|
||||
{
|
||||
splinePath.pop_back();
|
||||
keyFrames.pop_back();
|
||||
@@ -311,7 +311,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
|
||||
float curPathTime = 0.0f;
|
||||
if (keyFrames[0].IsStopFrame())
|
||||
{
|
||||
curPathTime = float(keyFrames[0].Node->delay);
|
||||
curPathTime = float(keyFrames[0].Node->Delay);
|
||||
keyFrames[0].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
|
||||
{
|
||||
keyFrames[i].ArriveTime = uint32(curPathTime * IN_MILLISECONDS);
|
||||
keyFrames[i - 1].NextArriveTime = keyFrames[i].ArriveTime;
|
||||
curPathTime += float(keyFrames[i].Node->delay);
|
||||
curPathTime += float(keyFrames[i].Node->Delay);
|
||||
keyFrames[i].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
|
||||
}
|
||||
else
|
||||
@@ -374,10 +374,10 @@ Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map*
|
||||
|
||||
// ...at first waypoint
|
||||
TaxiPathNodeEntry const* startNode = tInfo->keyFrames.begin()->Node;
|
||||
uint32 mapId = startNode->mapid;
|
||||
float x = startNode->x;
|
||||
float y = startNode->y;
|
||||
float z = startNode->z;
|
||||
uint32 mapId = startNode->MapID;
|
||||
float x = startNode->LocX;
|
||||
float y = startNode->LocY;
|
||||
float z = startNode->LocZ;
|
||||
float o = tInfo->keyFrames.begin()->InitialOrientation;
|
||||
|
||||
// initialize the gameobject base
|
||||
|
||||
@@ -61,7 +61,7 @@ struct KeyFrame
|
||||
uint32 NextArriveTime;
|
||||
|
||||
bool IsTeleportFrame() const { return Teleport; }
|
||||
bool IsStopFrame() const { return Node->actionFlag == 2; }
|
||||
bool IsStopFrame() const { return Node->Flags == 2; }
|
||||
};
|
||||
|
||||
struct TransportTemplate
|
||||
|
||||
@@ -29,8 +29,8 @@ class ZoneScript
|
||||
ZoneScript() { }
|
||||
virtual ~ZoneScript() { }
|
||||
|
||||
virtual uint32 GetCreatureEntry(uint32 /*guidlow*/, CreatureData const* data) { return data->id; }
|
||||
virtual uint32 GetGameObjectEntry(uint32 /*guidlow*/, uint32 entry) { return entry; }
|
||||
virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) { return data->id; }
|
||||
virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) { return entry; }
|
||||
|
||||
virtual void OnCreatureCreate(Creature* ) { }
|
||||
virtual void OnCreatureRemove(Creature* ) { }
|
||||
|
||||
@@ -4143,4 +4143,12 @@ enum DiminishingLevels
|
||||
DIMINISHING_LEVEL_TAUNT_IMMUNE = 4
|
||||
};
|
||||
|
||||
/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN
|
||||
enum SpellCooldownFlags
|
||||
{
|
||||
SPELL_COOLDOWN_FLAG_NONE = 0x0,
|
||||
SPELL_COOLDOWN_FLAG_INCLUDE_GCD = 0x1, ///< Starts GCD in addition to normal cooldown specified in the packet
|
||||
SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS = 0x2 ///< Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUDE_GCD set
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -182,7 +182,7 @@ class MotionMaster //: private std::stack<MovementGenerator *>
|
||||
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
|
||||
void MoveJumpTo(float angle, float speedXY, float speedZ);
|
||||
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP)
|
||||
{ MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); };
|
||||
{ MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); }
|
||||
void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = EVENT_JUMP);
|
||||
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount);
|
||||
void MoveFall(uint32 id = 0);
|
||||
|
||||
@@ -248,10 +248,10 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
|
||||
if (i_currentNode >= i_path->size())
|
||||
return i_path->size();
|
||||
|
||||
uint32 curMapId = (*i_path)[i_currentNode].mapid;
|
||||
uint32 curMapId = (*i_path)[i_currentNode].MapID;
|
||||
for (uint32 i = i_currentNode; i < i_path->size(); ++i)
|
||||
{
|
||||
if ((*i_path)[i].mapid != curMapId)
|
||||
if ((*i_path)[i].MapID != curMapId)
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ void FlightPathMovementGenerator::DoReset(Player* player)
|
||||
uint32 end = GetPathAtMapEnd();
|
||||
for (uint32 i = GetCurrentNode(); i != end; ++i)
|
||||
{
|
||||
G3D::Vector3 vertice((*i_path)[i].x, (*i_path)[i].y, (*i_path)[i].z);
|
||||
G3D::Vector3 vertice((*i_path)[i].LocX, (*i_path)[i].LocY, (*i_path)[i].LocZ);
|
||||
init.Path().push_back(vertice);
|
||||
}
|
||||
init.SetFirstPointId(GetCurrentNode());
|
||||
@@ -335,10 +335,10 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
|
||||
if (i_path->empty())
|
||||
return;
|
||||
|
||||
uint32 map0 = (*i_path)[0].mapid;
|
||||
uint32 map0 = (*i_path)[0].MapID;
|
||||
for (size_t i = 1; i < i_path->size(); ++i)
|
||||
{
|
||||
if ((*i_path)[i].mapid != map0)
|
||||
if ((*i_path)[i].MapID != map0)
|
||||
{
|
||||
i_currentNode = i;
|
||||
return;
|
||||
@@ -348,9 +348,9 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
|
||||
|
||||
void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure)
|
||||
{
|
||||
if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
|
||||
if (uint32 eventid = departure ? node.DepartureEventID : node.ArrivalEventID)
|
||||
{
|
||||
TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player->GetName().c_str());
|
||||
TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.NodeIndex, node.PathID, player->GetName().c_str());
|
||||
player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
|
||||
}
|
||||
}
|
||||
@@ -358,7 +358,7 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry
|
||||
bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z)
|
||||
{
|
||||
const TaxiPathNodeEntry& node = (*i_path)[i_currentNode];
|
||||
x = node.x; y = node.y; z = node.z;
|
||||
x = node.LocX; y = node.LocY; z = node.LocZ;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -367,10 +367,10 @@ void FlightPathMovementGenerator::InitEndGridInfo()
|
||||
/*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
|
||||
be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */
|
||||
uint32 nodeCount = (*i_path).size(); //! Number of nodes in path.
|
||||
_endMapId = (*i_path)[nodeCount - 1].mapid; //! MapId of last node
|
||||
_endMapId = (*i_path)[nodeCount - 1].MapID; //! MapId of last node
|
||||
_preloadTargetNode = nodeCount - 3;
|
||||
_endGridX = (*i_path)[nodeCount - 1].x;
|
||||
_endGridY = (*i_path)[nodeCount - 1].y;
|
||||
_endGridX = (*i_path)[nodeCount - 1].LocX;
|
||||
_endGridY = (*i_path)[nodeCount - 1].LocY;
|
||||
}
|
||||
|
||||
void FlightPathMovementGenerator::PreloadEndGrid()
|
||||
|
||||
@@ -24,11 +24,7 @@
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
#if defined( __GNUC__ )
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
class MoveSplineFlag
|
||||
{
|
||||
@@ -144,11 +140,7 @@ namespace Movement
|
||||
bool unknown8 : 1;
|
||||
bool unknown9 : 1;
|
||||
};
|
||||
#if defined( __GNUC__ )
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
@@ -634,6 +634,7 @@ void AddSC_instance_magtheridons_lair();
|
||||
void AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls
|
||||
void AddSC_boss_warbringer_omrogg();
|
||||
void AddSC_boss_warchief_kargath_bladefist();
|
||||
void AddSC_shattered_halls();
|
||||
void AddSC_instance_shattered_halls();
|
||||
void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts
|
||||
void AddSC_boss_omor_the_unscarred();
|
||||
@@ -1188,6 +1189,7 @@ void AddOutlandScripts()
|
||||
AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls
|
||||
AddSC_boss_warbringer_omrogg();
|
||||
AddSC_boss_warchief_kargath_bladefist();
|
||||
AddSC_shattered_halls();
|
||||
AddSC_instance_shattered_halls();
|
||||
AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts
|
||||
AddSC_boss_omor_the_unscarred();
|
||||
|
||||
@@ -1408,11 +1408,7 @@ class WorldSession;
|
||||
|
||||
typedef void(WorldSession::*pOpcodeHandler)(WorldPacket& recvPacket);
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct OpcodeHandler
|
||||
{
|
||||
@@ -1460,11 +1456,7 @@ class OpcodeTable
|
||||
|
||||
extern OpcodeTable opcodeTable;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
void InitOpcodes();
|
||||
|
||||
|
||||
@@ -1343,6 +1343,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co
|
||||
case MSG_RANDOM_ROLL: // not profiled
|
||||
case CMSG_TIME_SYNC_RESP: // not profiled
|
||||
case CMSG_TRAINER_BUY_SPELL: // not profiled
|
||||
case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: // not profiled
|
||||
{
|
||||
// "0" is a magic number meaning there's no limit for the opcode.
|
||||
// All the opcodes above must cause little CPU usage and no sync/async database queries at all
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Util.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "Battleground.h"
|
||||
#include "OutdoorPvPMgr.h"
|
||||
@@ -1197,15 +1198,13 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
|
||||
// Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell
|
||||
if (spellId)
|
||||
{
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
target->ToPlayer()->RemoveSpellCooldown(spellId);
|
||||
target->GetSpellHistory()->ResetCooldown(spellId);
|
||||
target->CastSpell(target, spellId, true, NULL, this);
|
||||
}
|
||||
|
||||
if (spellId2)
|
||||
{
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
target->ToPlayer()->RemoveSpellCooldown(spellId2);
|
||||
target->GetSpellHistory()->ResetCooldown(spellId2);
|
||||
target->CastSpell(target, spellId2, true, NULL, this);
|
||||
}
|
||||
|
||||
@@ -3919,10 +3918,11 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint
|
||||
}
|
||||
else
|
||||
{
|
||||
if (int32(target->GetHealth()) > GetAmount())
|
||||
target->ModifyHealth(-GetAmount());
|
||||
else
|
||||
target->SetHealth(1);
|
||||
if (target->GetHealth() > 0)
|
||||
{
|
||||
int32 value = std::min<int32>(target->GetHealth() - 1, GetAmount());
|
||||
target->ModifyHealth(-value);
|
||||
}
|
||||
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
}
|
||||
}
|
||||
@@ -3934,19 +3934,15 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
uint32 oldhealth = target->GetHealth();
|
||||
double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth();
|
||||
float percent = target->GetHealthPct();
|
||||
|
||||
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
|
||||
// refresh percentage
|
||||
if (oldhealth > 0)
|
||||
if (target->GetHealth() > 0)
|
||||
{
|
||||
uint32 newhealth = uint32(ceil((double)target->GetMaxHealth() * healthPercentage));
|
||||
if (newhealth == 0)
|
||||
newhealth = 1;
|
||||
|
||||
target->SetHealth(newhealth);
|
||||
uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1);
|
||||
target->SetHealth(newHealth);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4010,8 +4006,12 @@ void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurAp
|
||||
// Unit will keep hp% after MaxHealth being modified if unit is alive.
|
||||
float percent = target->GetHealthPct();
|
||||
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply);
|
||||
if (target->IsAlive())
|
||||
target->SetHealth(target->CountPctFromMaxHealth(int32(percent)));
|
||||
|
||||
if (target->GetHealth() > 0)
|
||||
{
|
||||
uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1);
|
||||
target->SetHealth(newHealth);
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -5846,6 +5846,9 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
|
||||
else
|
||||
damage = std::max(int32(damage * GetDonePct()), 0);
|
||||
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
|
||||
|
||||
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
|
||||
|
||||
// Calculate armor mitigation
|
||||
@@ -6131,6 +6134,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
|
||||
else
|
||||
damage = std::max(int32(damage * GetDonePct()), 0);
|
||||
|
||||
if (Player* modOwner = caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
|
||||
|
||||
damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Player.h"
|
||||
#include "Unit.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "ObjectAccessor.h"
|
||||
@@ -427,7 +428,7 @@ void Aura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication * auraApp
|
||||
if (m_spellInfo->IsCooldownStartedOnEvent())
|
||||
{
|
||||
Item* castItem = m_castItemGuid ? caster->ToPlayer()->GetItemByGuid(m_castItemGuid) : NULL;
|
||||
caster->ToPlayer()->AddSpellAndCategoryCooldowns(m_spellInfo, castItem ? castItem->GetEntry() : 0, NULL, true);
|
||||
caster->GetSpellHistory()->StartCooldown(m_spellInfo, castItem ? castItem->GetEntry() : 0, nullptr, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,12 +456,9 @@ void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * auraA
|
||||
m_removedApplications.push_back(auraApp);
|
||||
|
||||
// reset cooldown state for spells
|
||||
if (caster && caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (GetSpellInfo()->IsCooldownStartedOnEvent())
|
||||
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
|
||||
caster->ToPlayer()->SendCooldownEvent(GetSpellInfo());
|
||||
}
|
||||
if (caster && GetSpellInfo()->IsCooldownStartedOnEvent())
|
||||
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
|
||||
caster->GetSpellHistory()->SendCooldownEvent(GetSpellInfo());
|
||||
}
|
||||
|
||||
// removes aura from all targets
|
||||
@@ -1244,7 +1242,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
break;
|
||||
case 60970: // Heroic Fury (remove Intercept cooldown)
|
||||
if (target->GetTypeId() == TYPEID_PLAYER)
|
||||
target->ToPlayer()->RemoveSpellCooldown(20252, true);
|
||||
target->GetSpellHistory()->ResetCooldown(20252, true);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1404,15 +1402,15 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
// check cooldown
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (caster->ToPlayer()->HasSpellCooldown(aura->GetId()))
|
||||
if (caster->GetSpellHistory()->HasCooldown(aura->GetId()))
|
||||
{
|
||||
// This additional check is needed to add a minimal delay before cooldown in in effect
|
||||
// to allow all bubbles broken by a single damage source proc mana return
|
||||
if (caster->ToPlayer()->GetSpellCooldownDelay(aura->GetId()) <= 11)
|
||||
if (caster->GetSpellHistory()->GetRemainingCooldown(aura->GetId()) <= 11)
|
||||
break;
|
||||
}
|
||||
else // and add if needed
|
||||
caster->ToPlayer()->AddSpellCooldown(aura->GetId(), 0, uint32(time(NULL) + 12));
|
||||
caster->GetSpellHistory()->AddCooldown(aura->GetId(), 0, std::chrono::seconds(12));
|
||||
}
|
||||
|
||||
// effect on caster
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "SpellScript.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "Battlefield.h"
|
||||
#include "BattlefieldMgr.h"
|
||||
@@ -3235,7 +3236,7 @@ void Spell::cast(bool skipCheck)
|
||||
|
||||
//Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
|
||||
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
|
||||
m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true);
|
||||
m_caster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
|
||||
}
|
||||
|
||||
SetExecutedCurrently(false);
|
||||
@@ -3442,30 +3443,7 @@ void Spell::_handle_finish_phase()
|
||||
|
||||
void Spell::SendSpellCooldown()
|
||||
{
|
||||
Player* _player = m_caster->ToPlayer();
|
||||
if (!_player)
|
||||
{
|
||||
// Handle pet cooldowns here if needed instead of in PetAI to avoid hidden cooldown restarts
|
||||
Creature* _creature = m_caster->ToCreature();
|
||||
if (_creature && (_creature->IsPet() || _creature->IsGuardian()))
|
||||
_creature->AddCreatureSpellCooldown(m_spellInfo->Id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// mana/health/etc potions, disabled by client (until combat out as declarate)
|
||||
if (m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
|
||||
{
|
||||
// need in some way provided data for Spell::finish SendCooldownEvent
|
||||
_player->SetLastPotionId(m_CastItem->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
// have infinity cooldown but set at aura apply // do not set cooldown for triggered spells (needed by reincarnation)
|
||||
if (m_spellInfo->IsCooldownStartedOnEvent() || m_spellInfo->IsPassive() || (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD))
|
||||
return;
|
||||
|
||||
_player->AddSpellAndCategoryCooldowns(m_spellInfo, m_CastItem ? m_CastItem->GetEntry() : 0, this);
|
||||
m_caster->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_CastItem, this);
|
||||
}
|
||||
|
||||
void Spell::update(uint32 difftime)
|
||||
@@ -4702,23 +4680,26 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
return SPELL_FAILED_CASTER_DEAD;
|
||||
|
||||
// check cooldowns to prevent cheating
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE))
|
||||
if (!m_spellInfo->IsPassive())
|
||||
{
|
||||
//can cast triggered (by aura only?) spells while have this flag
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
|
||||
return SPELL_FAILED_SPELL_IN_PROGRESS;
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
//can cast triggered (by aura only?) spells while have this flag
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
|
||||
return SPELL_FAILED_SPELL_IN_PROGRESS;
|
||||
|
||||
if (m_caster->ToPlayer()->HasSpellCooldown(m_spellInfo->Id))
|
||||
// check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
|
||||
if (m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
|
||||
return SPELL_FAILED_NOT_READY;
|
||||
}
|
||||
|
||||
if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo))
|
||||
{
|
||||
if (m_triggeredByAuraSpell)
|
||||
return SPELL_FAILED_DONT_REPORT;
|
||||
else
|
||||
return SPELL_FAILED_NOT_READY;
|
||||
}
|
||||
|
||||
// check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
|
||||
if (m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
|
||||
return SPELL_FAILED_NOT_READY;
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR7_IS_CHEAT_SPELL) && !m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS))
|
||||
@@ -5570,13 +5551,13 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
|
||||
}
|
||||
|
||||
// cooldown
|
||||
if (Creature const* creatureCaster = m_caster->ToCreature())
|
||||
if (creatureCaster->HasSpellCooldown(m_spellInfo->Id))
|
||||
if (Creature* creatureCaster = m_caster->ToCreature())
|
||||
if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo))
|
||||
return SPELL_FAILED_NOT_READY;
|
||||
|
||||
// Check if spell is affected by GCD
|
||||
if (m_spellInfo->StartRecoveryCategory > 0)
|
||||
if (m_caster->GetCharmInfo() && m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo))
|
||||
if (m_caster->GetCharmInfo() && m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
|
||||
return SPELL_FAILED_NOT_READY;
|
||||
|
||||
return CheckCast(true);
|
||||
@@ -5899,7 +5880,7 @@ SpellCastResult Spell::CheckItems()
|
||||
if (!proto)
|
||||
return SPELL_FAILED_ITEM_NOT_READY;
|
||||
|
||||
for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i)
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
if (proto->Spells[i].SpellCharges)
|
||||
if (m_CastItem->GetSpellCharges(i) == 0)
|
||||
return SPELL_FAILED_NO_CHARGES_REMAIN;
|
||||
@@ -7283,13 +7264,11 @@ enum GCDLimits
|
||||
|
||||
bool Spell::HasGlobalCooldown() const
|
||||
{
|
||||
// Only player or controlled units have global cooldown
|
||||
if (m_caster->GetCharmInfo())
|
||||
return m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo);
|
||||
else if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
return m_caster->ToPlayer()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo);
|
||||
else
|
||||
// Only players or controlled units have global cooldown
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
|
||||
return false;
|
||||
|
||||
return m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo);
|
||||
}
|
||||
|
||||
void Spell::TriggerGlobalCooldown()
|
||||
@@ -7298,6 +7277,10 @@ void Spell::TriggerGlobalCooldown()
|
||||
if (!gcd)
|
||||
return;
|
||||
|
||||
// Only players or controlled units have global cooldown
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
|
||||
return;
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
|
||||
return;
|
||||
@@ -7319,11 +7302,7 @@ void Spell::TriggerGlobalCooldown()
|
||||
gcd = MAX_GCD;
|
||||
}
|
||||
|
||||
// Only players or controlled units have global cooldown
|
||||
if (m_caster->GetCharmInfo())
|
||||
m_caster->GetCharmInfo()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd);
|
||||
else if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
m_caster->ToPlayer()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd);
|
||||
m_caster->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd);
|
||||
}
|
||||
|
||||
void Spell::CancelGlobalCooldown()
|
||||
@@ -7336,10 +7315,10 @@ void Spell::CancelGlobalCooldown()
|
||||
return;
|
||||
|
||||
// Only players or controlled units have global cooldown
|
||||
if (m_caster->GetCharmInfo())
|
||||
m_caster->GetCharmInfo()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo);
|
||||
else if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo);
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
|
||||
return;
|
||||
|
||||
m_caster->GetSpellHistory()->CancelGlobalCooldown(m_spellInfo);
|
||||
}
|
||||
|
||||
namespace Trinity
|
||||
@@ -7458,7 +7437,7 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
|
||||
}
|
||||
else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE))
|
||||
{
|
||||
if (!_caster->HasInLine(target, _caster->GetObjectSize()))
|
||||
if (!_caster->HasInLine(target, _caster->GetObjectSize() + target->GetObjectSize()))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -7475,7 +7454,7 @@ WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Po
|
||||
bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target)
|
||||
{
|
||||
// return all targets on missile trajectory (0 - size of a missile)
|
||||
if (!_caster->HasInLine(target, 0))
|
||||
if (!_caster->HasInLine(target, target->GetObjectSize()))
|
||||
return false;
|
||||
return WorldObjectSpellAreaTargetCheck::operator ()(target);
|
||||
}
|
||||
|
||||
@@ -478,6 +478,7 @@ class Spell
|
||||
void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; }
|
||||
bool IsNextMeleeSwingSpell() const;
|
||||
bool IsTriggered() const { return (_triggeredCastFlags & TRIGGERED_FULL_MASK) != 0; }
|
||||
bool IsIgnoringCooldowns() const { return (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD) != 0; }
|
||||
bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; }
|
||||
bool IsAutoActionResetSpell() const;
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "GridNotifiers.h"
|
||||
#include "Formulas.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "GameObjectAI.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
@@ -632,8 +633,8 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
|
||||
return;
|
||||
|
||||
// Reset cooldown on stealth if needed
|
||||
if (unitTarget->ToPlayer()->HasSpellCooldown(1784))
|
||||
unitTarget->ToPlayer()->RemoveSpellCooldown(1784);
|
||||
if (unitTarget->GetSpellHistory()->HasCooldown(1784))
|
||||
unitTarget->GetSpellHistory()->ResetCooldown(1784);
|
||||
|
||||
unitTarget->CastSpell(unitTarget, 1784, true);
|
||||
return;
|
||||
@@ -738,7 +739,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
|
||||
// Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
|
||||
&& m_spellInfo->GetCategory() == spellInfo->GetCategory())
|
||||
m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id);
|
||||
m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id);
|
||||
|
||||
// original caster guid only for GO cast
|
||||
m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
|
||||
@@ -791,7 +792,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex)
|
||||
// Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
|
||||
&& m_spellInfo->GetCategory() == spellInfo->GetCategory())
|
||||
m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id);
|
||||
m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id);
|
||||
|
||||
// original caster guid only for GO cast
|
||||
m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
|
||||
@@ -3166,7 +3167,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex)
|
||||
if (m_originalCaster)
|
||||
{
|
||||
int32 duration = m_spellInfo->GetDuration();
|
||||
unitTarget->ProhibitSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
|
||||
unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
|
||||
}
|
||||
ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
|
||||
unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
|
||||
@@ -5600,7 +5601,7 @@ void Spell::EffectCastButtons(SpellEffIndex effIndex)
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (!p_caster->HasSpell(spell_id) || p_caster->HasSpellCooldown(spell_id))
|
||||
if (!p_caster->HasSpell(spell_id) || p_caster->GetSpellHistory()->HasCooldown(spell_id))
|
||||
continue;
|
||||
|
||||
if (!(spellInfo->AttributesEx9 & SPELL_ATTR9_SUMMON_PLAYER_TOTEM))
|
||||
|
||||
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2015 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/>.
|
||||
*/
|
||||
|
||||
#include "WorldPacket.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "Spell.h"
|
||||
#include "World.h"
|
||||
#include "Opcodes.h"
|
||||
|
||||
SpellHistory::Clock::duration const SpellHistory::InfinityCooldownDelay = std::chrono::duration_cast<SpellHistory::Clock::duration>(std::chrono::seconds(MONTH));
|
||||
SpellHistory::Clock::duration const SpellHistory::InfinityCooldownDelayCheck = std::chrono::duration_cast<SpellHistory::Clock::duration>(std::chrono::seconds(MONTH / 2));
|
||||
|
||||
template<>
|
||||
struct SpellHistory::PersistenceHelper<Player>
|
||||
{
|
||||
static CharacterDatabaseStatements const CooldownsDeleteStatement = CHAR_DEL_CHAR_SPELL_COOLDOWNS;
|
||||
static CharacterDatabaseStatements const CooldownsInsertStatement = CHAR_INS_CHAR_SPELL_COOLDOWN;
|
||||
|
||||
static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetGUID().GetCounter()); }
|
||||
|
||||
static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry)
|
||||
{
|
||||
*spellId = fields[0].GetUInt32();
|
||||
if (!sSpellMgr->GetSpellInfo(*spellId))
|
||||
return false;
|
||||
|
||||
cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[2].GetUInt32()));
|
||||
cooldownEntry->ItemId = fields[1].GetUInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown)
|
||||
{
|
||||
stmt->setUInt32(index++, cooldown.first);
|
||||
stmt->setUInt32(index++, cooldown.second.ItemId);
|
||||
stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd)));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SpellHistory::PersistenceHelper<Pet>
|
||||
{
|
||||
static CharacterDatabaseStatements const CooldownsDeleteStatement = CHAR_DEL_PET_SPELL_COOLDOWNS;
|
||||
static CharacterDatabaseStatements const CooldownsInsertStatement = CHAR_INS_PET_SPELL_COOLDOWN;
|
||||
|
||||
static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetCharmInfo()->GetPetNumber()); }
|
||||
|
||||
static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry)
|
||||
{
|
||||
*spellId = fields[0].GetUInt32();
|
||||
if (!sSpellMgr->GetSpellInfo(*spellId))
|
||||
return false;
|
||||
|
||||
cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[1].GetUInt32()));
|
||||
cooldownEntry->ItemId = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown)
|
||||
{
|
||||
stmt->setUInt32(index++, cooldown.first);
|
||||
stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd)));
|
||||
}
|
||||
};
|
||||
|
||||
template<class OwnerType>
|
||||
void SpellHistory::LoadFromDB(PreparedQueryResult cooldownsResult)
|
||||
{
|
||||
typedef PersistenceHelper<OwnerType> StatementInfo;
|
||||
|
||||
if (cooldownsResult)
|
||||
{
|
||||
do
|
||||
{
|
||||
uint32 spellId;
|
||||
CooldownEntry cooldown;
|
||||
if (StatementInfo::ReadCooldown(cooldownsResult->Fetch(), &spellId, &cooldown))
|
||||
_spellCooldowns[spellId] = cooldown;
|
||||
|
||||
} while (cooldownsResult->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
template<class OwnerType>
|
||||
void SpellHistory::SaveToDB(SQLTransaction& trans)
|
||||
{
|
||||
typedef PersistenceHelper<OwnerType> StatementInfo;
|
||||
|
||||
uint8 index = 0;
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsDeleteStatement);
|
||||
StatementInfo::SetIdentifier(stmt, index++, _owner);
|
||||
trans->Append(stmt);
|
||||
|
||||
for (auto const& p : _spellCooldowns)
|
||||
{
|
||||
if (!p.second.OnHold)
|
||||
{
|
||||
index = 0;
|
||||
stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsInsertStatement);
|
||||
StatementInfo::SetIdentifier(stmt, index++, _owner);
|
||||
StatementInfo::WriteCooldown(stmt, index, p);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHistory::Update()
|
||||
{
|
||||
SQLTransaction t;
|
||||
Clock::time_point now = Clock::now();
|
||||
for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
|
||||
{
|
||||
if (itr->second.CooldownEnd < now)
|
||||
itr = _spellCooldowns.erase(itr);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHistory::HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell /*= nullptr*/)
|
||||
{
|
||||
if (Player* player = _owner->ToPlayer())
|
||||
{
|
||||
// potions start cooldown until exiting combat
|
||||
if (item && (item->IsPotion() || spellInfo->IsCooldownStartedOnEvent()))
|
||||
{
|
||||
player->SetLastPotionId(item->GetEntry());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (spellInfo->IsCooldownStartedOnEvent() || spellInfo->IsPassive() || (spell && spell->IsIgnoringCooldowns()))
|
||||
return;
|
||||
|
||||
StartCooldown(spellInfo, item ? item->GetEntry() : 0, spell);
|
||||
}
|
||||
|
||||
bool SpellHistory::IsReady(SpellInfo const* spellInfo) const
|
||||
{
|
||||
if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
|
||||
if (IsSchoolLocked(spellInfo->GetSchoolMask()))
|
||||
return false;
|
||||
|
||||
if (HasCooldown(spellInfo->Id))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void SpellHistory::WritePacket<Pet>(WorldPacket& packet) const
|
||||
{
|
||||
Clock::time_point now = Clock::now();
|
||||
|
||||
uint8 cooldownsCount = _spellCooldowns.size();
|
||||
packet << uint8(cooldownsCount);
|
||||
|
||||
for (auto const& spellCooldown : _spellCooldowns)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellCooldown.first);
|
||||
if (!spellInfo)
|
||||
{
|
||||
packet << uint32(0);
|
||||
packet << uint16(0);
|
||||
packet << uint32(0);
|
||||
packet << uint32(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
packet << uint32(spellCooldown.first); // spell ID
|
||||
packet << uint16(spellInfo->GetCategory()); // spell category
|
||||
if (!spellCooldown.second.OnHold)
|
||||
{
|
||||
uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0;
|
||||
if (cooldownDuration <= 0)
|
||||
{
|
||||
packet << uint32(0);
|
||||
packet << uint32(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spellInfo->GetCategory())
|
||||
{
|
||||
packet << uint32(0);
|
||||
packet << uint32(cooldownDuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet << uint32(cooldownDuration);
|
||||
packet << uint32(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void SpellHistory::WritePacket<Player>(WorldPacket& packet) const
|
||||
{
|
||||
Clock::time_point now = Clock::now();
|
||||
Clock::time_point infTime = now + InfinityCooldownDelayCheck;
|
||||
|
||||
uint16 cooldownsCount = _spellCooldowns.size();
|
||||
size_t dataPos = packet.wpos();
|
||||
packet << uint16(cooldownsCount);
|
||||
|
||||
for (auto const& spellCooldown : _spellCooldowns)
|
||||
{
|
||||
SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(spellCooldown.first);
|
||||
if (!sEntry)
|
||||
{
|
||||
--cooldownsCount;
|
||||
continue;
|
||||
}
|
||||
|
||||
packet << uint32(spellCooldown.first);
|
||||
|
||||
packet << uint16(spellCooldown.second.ItemId); // cast item id
|
||||
packet << uint16(sEntry->GetCategory()); // spell category
|
||||
|
||||
// send infinity cooldown in special format
|
||||
if (spellCooldown.second.CooldownEnd >= infTime)
|
||||
{
|
||||
packet << uint32(1); // cooldown
|
||||
packet << uint32(0x80000000); // category cooldown
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0;
|
||||
|
||||
if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing...
|
||||
{
|
||||
packet << uint32(0); // cooldown
|
||||
packet << uint32(cooldownDuration); // category cooldown
|
||||
}
|
||||
else
|
||||
{
|
||||
packet << uint32(cooldownDuration); // cooldown
|
||||
packet << uint32(0); // category cooldown
|
||||
}
|
||||
}
|
||||
|
||||
packet.put<uint16>(dataPos, cooldownsCount);
|
||||
}
|
||||
|
||||
void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell /*= nullptr*/, bool onHold /*= false*/)
|
||||
{
|
||||
// init cooldown values
|
||||
uint32 categoryId = 0;
|
||||
int32 cooldown = -1;
|
||||
int32 categoryCooldown = -1;
|
||||
|
||||
// some special item spells without correct cooldown in SpellInfo
|
||||
// cooldown information stored in item prototype
|
||||
if (itemId)
|
||||
{
|
||||
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
|
||||
{
|
||||
for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx)
|
||||
{
|
||||
if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id)
|
||||
{
|
||||
categoryId = proto->Spells[idx].SpellCategory;
|
||||
cooldown = proto->Spells[idx].SpellCooldown;
|
||||
categoryCooldown = proto->Spells[idx].SpellCategoryCooldown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no cooldown found above then base at DBC data
|
||||
if (cooldown < 0 && categoryCooldown < 0)
|
||||
{
|
||||
categoryId = spellInfo->GetCategory();
|
||||
cooldown = spellInfo->RecoveryTime;
|
||||
categoryCooldown = spellInfo->CategoryRecoveryTime;
|
||||
}
|
||||
|
||||
Clock::time_point curTime = Clock::now();
|
||||
Clock::time_point catrecTime;
|
||||
Clock::time_point recTime;
|
||||
bool needsCooldownPacket = false;
|
||||
|
||||
// overwrite time for selected category
|
||||
if (onHold)
|
||||
{
|
||||
// use +MONTH as infinite cooldown marker
|
||||
catrecTime = categoryCooldown > 0 ? (curTime + InfinityCooldownDelay) : curTime;
|
||||
recTime = cooldown > 0 ? (curTime + InfinityCooldownDelay) : catrecTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
|
||||
// prevent 0 cooldowns set by another way
|
||||
if (cooldown <= 0 && categoryCooldown <= 0 && (categoryId == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75)))
|
||||
cooldown = _owner->GetAttackTime(RANGED_ATTACK);
|
||||
|
||||
// Now we have cooldown data (if found any), time to apply mods
|
||||
if (Player* modOwner = _owner->GetSpellModOwner())
|
||||
{
|
||||
if (cooldown > 0)
|
||||
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown, spell);
|
||||
|
||||
if (categoryCooldown > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
|
||||
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categoryCooldown, spell);
|
||||
}
|
||||
|
||||
if (int32 cooldownMod = _owner->GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
|
||||
{
|
||||
// Apply SPELL_AURA_MOD_COOLDOWN only to own spells
|
||||
Player* playerOwner = GetPlayerOwner();
|
||||
if (!playerOwner || playerOwner->HasSpell(spellInfo->Id))
|
||||
{
|
||||
needsCooldownPacket = true;
|
||||
cooldown += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks
|
||||
}
|
||||
}
|
||||
|
||||
// replace negative cooldowns by 0
|
||||
if (cooldown < 0)
|
||||
cooldown = 0;
|
||||
|
||||
if (categoryCooldown < 0)
|
||||
categoryCooldown = 0;
|
||||
|
||||
// no cooldown after applying spell mods
|
||||
if (cooldown == 0 && categoryCooldown == 0)
|
||||
return;
|
||||
|
||||
catrecTime = categoryCooldown ? curTime + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(categoryCooldown)) : curTime;
|
||||
recTime = cooldown ? curTime + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(cooldown)) : catrecTime;
|
||||
}
|
||||
|
||||
// self spell cooldown
|
||||
if (recTime != curTime)
|
||||
{
|
||||
AddCooldown(spellInfo->Id, itemId, recTime, onHold);
|
||||
|
||||
if (needsCooldownPacket)
|
||||
{
|
||||
if (Player* playerOwner = GetPlayerOwner())
|
||||
{
|
||||
WorldPacket spellCooldown;
|
||||
BuildCooldownPacket(spellCooldown, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, cooldown);
|
||||
playerOwner->SendDirectMessage(&spellCooldown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category spells
|
||||
if (categoryId && catrecTime != curTime)
|
||||
{
|
||||
SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(categoryId);
|
||||
if (i_scstore != sSpellsByCategoryStore.end())
|
||||
{
|
||||
for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
|
||||
{
|
||||
if (*i_scset == spellInfo->Id) // skip main spell, already handled above
|
||||
continue;
|
||||
|
||||
AddCooldown(*i_scset, itemId, catrecTime, onHold);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHistory::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= nullptr*/, bool startCooldown /*= true*/)
|
||||
{
|
||||
// start cooldowns at server side, if any
|
||||
if (startCooldown)
|
||||
StartCooldown(spellInfo, itemId, spell);
|
||||
|
||||
if (Player* player = GetPlayerOwner())
|
||||
{
|
||||
// Send activate cooldown timer (possible 0) at client side
|
||||
WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
|
||||
data << uint32(spellInfo->Id);
|
||||
data << uint64(_owner->GetGUID());
|
||||
player->SendDirectMessage(&data);
|
||||
|
||||
uint32 category = spellInfo->GetCategory();
|
||||
if (category && spellInfo->CategoryRecoveryTime)
|
||||
{
|
||||
SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(category);
|
||||
if (ct != sSpellsByCategoryStore.end())
|
||||
{
|
||||
for (auto const& cooldownPair : _spellCooldowns)
|
||||
{
|
||||
uint32 categorySpell = cooldownPair.first;
|
||||
if (!ct->second.count(categorySpell))
|
||||
continue;
|
||||
|
||||
if (categorySpell == spellInfo->Id) // skip main spell, already handled above
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo2 = sSpellMgr->EnsureSpellInfo(categorySpell);
|
||||
if (!spellInfo2->IsCooldownStartedOnEvent())
|
||||
continue;
|
||||
|
||||
data.Initialize(SMSG_COOLDOWN_EVENT, 4 + 8);
|
||||
data << uint32(categorySpell);
|
||||
data << uint64(_owner->GetGUID());
|
||||
player->SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHistory::AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold /*= false*/)
|
||||
{
|
||||
CooldownEntry& cooldownEntry = _spellCooldowns[spellId];
|
||||
cooldownEntry.CooldownEnd = cooldownEnd;
|
||||
cooldownEntry.ItemId = itemId;
|
||||
cooldownEntry.OnHold = onHold;
|
||||
}
|
||||
|
||||
void SpellHistory::ModifyCooldown(uint32 spellId, int32 cooldownModMs)
|
||||
{
|
||||
auto itr = _spellCooldowns.find(spellId);
|
||||
if (!cooldownModMs || itr == _spellCooldowns.end())
|
||||
return;
|
||||
|
||||
Clock::time_point now = Clock::now();
|
||||
Clock::duration offset = std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(cooldownModMs));
|
||||
if (itr->second.CooldownEnd + offset > now)
|
||||
itr->second.CooldownEnd += offset;
|
||||
else
|
||||
_spellCooldowns.erase(itr);
|
||||
|
||||
if (Player* playerOwner = GetPlayerOwner())
|
||||
{
|
||||
WorldPacket modifyCooldown(SMSG_MODIFY_COOLDOWN, 4 + 8 + 4);
|
||||
modifyCooldown << uint32(spellId);
|
||||
modifyCooldown << uint64(_owner->GetGUID());
|
||||
modifyCooldown << int32(cooldownModMs);
|
||||
playerOwner->SendDirectMessage(&modifyCooldown);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHistory::ResetCooldown(uint32 spellId, bool update /*= false*/)
|
||||
{
|
||||
auto itr = _spellCooldowns.find(spellId);
|
||||
if (itr == _spellCooldowns.end())
|
||||
return;
|
||||
|
||||
ResetCooldown(itr, update);
|
||||
}
|
||||
|
||||
void SpellHistory::ResetCooldown(CooldownStorageType::iterator& itr, bool update /*= false*/)
|
||||
{
|
||||
if (update)
|
||||
{
|
||||
if (Player* playerOwner = GetPlayerOwner())
|
||||
{
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, 4 + 8);
|
||||
data << uint32(itr->first);
|
||||
data << uint64(_owner->GetGUID());
|
||||
playerOwner->SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
itr = _spellCooldowns.erase(itr);
|
||||
}
|
||||
|
||||
void SpellHistory::ResetAllCooldowns()
|
||||
{
|
||||
if (GetPlayerOwner())
|
||||
{
|
||||
std::vector<int32> cooldowns;
|
||||
cooldowns.reserve(_spellCooldowns.size());
|
||||
for (auto const& p : _spellCooldowns)
|
||||
cooldowns.push_back(p.first);
|
||||
|
||||
SendClearCooldowns(cooldowns);
|
||||
}
|
||||
|
||||
_spellCooldowns.clear();
|
||||
}
|
||||
|
||||
bool SpellHistory::HasCooldown(uint32 spellId) const
|
||||
{
|
||||
return _spellCooldowns.count(spellId) != 0;
|
||||
}
|
||||
|
||||
uint32 SpellHistory::GetRemainingCooldown(uint32 spellId) const
|
||||
{
|
||||
auto itr = _spellCooldowns.find(spellId);
|
||||
if (itr == _spellCooldowns.end())
|
||||
return 0;
|
||||
|
||||
Clock::time_point now = Clock::now();
|
||||
if (itr->second.CooldownEnd < now)
|
||||
return 0;
|
||||
|
||||
Clock::duration remaining = itr->second.CooldownEnd - now;
|
||||
return uint32(std::chrono::duration_cast<std::chrono::milliseconds>(remaining).count());
|
||||
}
|
||||
|
||||
void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime)
|
||||
{
|
||||
Clock::time_point lockoutEnd = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(lockoutTime));
|
||||
for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
||||
if (SpellSchoolMask(1 << i) & schoolMask)
|
||||
_schoolLockouts[i] = lockoutEnd;
|
||||
|
||||
std::set<uint32> knownSpells;
|
||||
if (Player* plrOwner = _owner->ToPlayer())
|
||||
{
|
||||
for (auto const& p : plrOwner->GetSpellMap())
|
||||
if (p.second->state != PLAYERSPELL_REMOVED)
|
||||
knownSpells.insert(p.first);
|
||||
}
|
||||
else if (Pet* petOwner = _owner->ToPet())
|
||||
{
|
||||
for (auto const& p : petOwner->m_spells)
|
||||
if (p.second.state != PETSPELL_REMOVED)
|
||||
knownSpells.insert(p.first);
|
||||
}
|
||||
else
|
||||
{
|
||||
Creature* creatureOwner = _owner->ToCreature();
|
||||
for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
if (creatureOwner->m_spells[i])
|
||||
knownSpells.insert(creatureOwner->m_spells[i]);
|
||||
}
|
||||
|
||||
PacketCooldowns cooldowns;
|
||||
WorldPacket spellCooldowns;
|
||||
for (uint32 spellId : knownSpells)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(spellId);
|
||||
if (spellInfo->IsCooldownStartedOnEvent())
|
||||
continue;
|
||||
|
||||
if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
|
||||
continue;
|
||||
|
||||
if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellId) < lockoutTime)
|
||||
{
|
||||
cooldowns[spellId] = lockoutTime;
|
||||
AddCooldown(spellId, 0, lockoutEnd);
|
||||
}
|
||||
}
|
||||
|
||||
if (Player* player = GetPlayerOwner())
|
||||
{
|
||||
if (!cooldowns.empty())
|
||||
{
|
||||
BuildCooldownPacket(spellCooldowns, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
|
||||
player->SendDirectMessage(&spellCooldowns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SpellHistory::IsSchoolLocked(SpellSchoolMask schoolMask) const
|
||||
{
|
||||
Clock::time_point now = Clock::now();
|
||||
for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
||||
if (SpellSchoolMask(1 << i) & schoolMask)
|
||||
if (_schoolLockouts[i] > now)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpellHistory::HasGlobalCooldown(SpellInfo const* spellInfo) const
|
||||
{
|
||||
auto itr = _globalCooldowns.find(spellInfo->StartRecoveryCategory);
|
||||
return itr != _globalCooldowns.end() && itr->second > Clock::now();
|
||||
}
|
||||
|
||||
void SpellHistory::AddGlobalCooldown(SpellInfo const* spellInfo, uint32 duration)
|
||||
{
|
||||
_globalCooldowns[spellInfo->StartRecoveryCategory] = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(duration));
|
||||
}
|
||||
|
||||
void SpellHistory::CancelGlobalCooldown(SpellInfo const* spellInfo)
|
||||
{
|
||||
_globalCooldowns[spellInfo->StartRecoveryCategory] = Clock::time_point(Clock::duration(0));
|
||||
}
|
||||
|
||||
Player* SpellHistory::GetPlayerOwner() const
|
||||
{
|
||||
return _owner->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
}
|
||||
|
||||
void SpellHistory::SendClearCooldowns(std::vector<int32> const& cooldowns) const
|
||||
{
|
||||
if (Player* playerOwner = GetPlayerOwner())
|
||||
{
|
||||
for (int32 spell : cooldowns)
|
||||
{
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, 4 + 8);
|
||||
data << uint32(spell);
|
||||
data << uint64(_owner->GetGUID());
|
||||
playerOwner->SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const
|
||||
{
|
||||
data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4);
|
||||
data << uint64(_owner->GetGUID());
|
||||
data << uint8(flags);
|
||||
data << uint32(spellId);
|
||||
data << uint32(cooldown);
|
||||
}
|
||||
|
||||
void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const
|
||||
{
|
||||
data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + (4 + 4) * cooldowns.size());
|
||||
data << uint64(_owner->GetGUID());
|
||||
data << uint8(flags);
|
||||
for (auto const& cooldown : cooldowns)
|
||||
{
|
||||
data << cooldown.first;
|
||||
data << cooldown.second;
|
||||
}
|
||||
}
|
||||
|
||||
template void SpellHistory::LoadFromDB<Player>(PreparedQueryResult cooldownsResult);
|
||||
template void SpellHistory::LoadFromDB<Pet>(PreparedQueryResult cooldownsResult);
|
||||
template void SpellHistory::SaveToDB<Player>(SQLTransaction& trans);
|
||||
template void SpellHistory::SaveToDB<Pet>(SQLTransaction& trans);
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2015 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/>.
|
||||
*/
|
||||
|
||||
#ifndef SpellHistory_h__
|
||||
#define SpellHistory_h__
|
||||
|
||||
#include "SharedDefines.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Transaction.h"
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
|
||||
class Item;
|
||||
class Player;
|
||||
class Spell;
|
||||
class SpellInfo;
|
||||
class Unit;
|
||||
struct SpellCategoryEntry;
|
||||
|
||||
class SpellHistory
|
||||
{
|
||||
public:
|
||||
typedef std::chrono::system_clock Clock;
|
||||
|
||||
struct CooldownEntry
|
||||
{
|
||||
CooldownEntry() : ItemId(0), OnHold(false) { }
|
||||
CooldownEntry(Clock::time_point endTime, uint32 itemId) : CooldownEnd(endTime), ItemId(itemId), OnHold(false) { }
|
||||
|
||||
Clock::time_point CooldownEnd;
|
||||
uint32 ItemId;
|
||||
bool OnHold;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32 /*spellId*/, CooldownEntry> CooldownStorageType;
|
||||
typedef std::unordered_map<uint32 /*categoryId*/, Clock::time_point> GlobalCooldownStorageType;
|
||||
|
||||
explicit SpellHistory(Unit* owner) : _owner(owner), _schoolLockouts() { }
|
||||
|
||||
template<class OwnerType>
|
||||
void LoadFromDB(PreparedQueryResult cooldownsResult);
|
||||
|
||||
template<class OwnerType>
|
||||
void SaveToDB(SQLTransaction& trans);
|
||||
|
||||
void Update();
|
||||
|
||||
void HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell = nullptr);
|
||||
bool IsReady(SpellInfo const* spellInfo) const;
|
||||
template<class OwnerType>
|
||||
void WritePacket(WorldPacket& packet) const;
|
||||
|
||||
// Cooldowns
|
||||
static Clock::duration const InfinityCooldownDelay; // used for set "infinity cooldowns" for spells and check
|
||||
static Clock::duration const InfinityCooldownDelayCheck;
|
||||
|
||||
void StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = nullptr, bool onHold = false);
|
||||
void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = nullptr, bool startCooldown = true);
|
||||
|
||||
template<class Type, class Period>
|
||||
void AddCooldown(uint32 spellId, uint32 itemId, std::chrono::duration<Type, Period> cooldownDuration)
|
||||
{
|
||||
AddCooldown(spellId, itemId, Clock::now() + std::chrono::duration_cast<Clock::duration>(cooldownDuration));
|
||||
}
|
||||
|
||||
void AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold = false);
|
||||
void ModifyCooldown(uint32 spellId, int32 cooldownModMs);
|
||||
void ResetCooldown(uint32 spellId, bool update = false);
|
||||
void ResetCooldown(CooldownStorageType::iterator& itr, bool update = false);
|
||||
template<typename Predicate>
|
||||
void ResetCooldowns(Predicate predicate, bool update = false)
|
||||
{
|
||||
std::vector<int32> resetCooldowns;
|
||||
resetCooldowns.reserve(_spellCooldowns.size());
|
||||
for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
|
||||
{
|
||||
if (predicate(itr))
|
||||
{
|
||||
resetCooldowns.push_back(itr->first);
|
||||
ResetCooldown(itr, false);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
|
||||
if (update && !resetCooldowns.empty())
|
||||
SendClearCooldowns(resetCooldowns);
|
||||
}
|
||||
|
||||
void ResetAllCooldowns();
|
||||
bool HasCooldown(uint32 spellId) const;
|
||||
uint32 GetRemainingCooldown(uint32 spellId) const;
|
||||
|
||||
// School lockouts
|
||||
void LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime);
|
||||
bool IsSchoolLocked(SpellSchoolMask schoolMask) const;
|
||||
|
||||
// Global cooldown
|
||||
bool HasGlobalCooldown(SpellInfo const* spellInfo) const;
|
||||
void AddGlobalCooldown(SpellInfo const* spellInfo, uint32 duration);
|
||||
void CancelGlobalCooldown(SpellInfo const* spellInfo);
|
||||
|
||||
void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const;
|
||||
|
||||
CooldownStorageType::size_type GetCooldownsSizeForPacket() const { return _spellCooldowns.size(); }
|
||||
|
||||
private:
|
||||
Player* GetPlayerOwner() const;
|
||||
void SendClearCooldowns(std::vector<int32> const& cooldowns) const;
|
||||
|
||||
typedef std::unordered_map<uint32, uint32> PacketCooldowns;
|
||||
void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const;
|
||||
|
||||
Unit* _owner;
|
||||
CooldownStorageType _spellCooldowns;
|
||||
Clock::time_point _schoolLockouts[MAX_SPELL_SCHOOL];
|
||||
GlobalCooldownStorageType _globalCooldowns;
|
||||
|
||||
template<class T>
|
||||
struct PersistenceHelper { };
|
||||
};
|
||||
|
||||
#endif // SpellHistory_h__
|
||||
@@ -1790,7 +1790,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
|
||||
}
|
||||
|
||||
// not allow casting on flying player
|
||||
if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||
if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT) && !(AttributesCu & SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET))
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
/* TARGET_UNIT_MASTER gets blocked here for passengers, because the whole idea of this check is to
|
||||
|
||||
@@ -189,6 +189,7 @@ enum SpellCustomAttributes
|
||||
SPELL_ATTR0_CU_IGNORE_ARMOR = 0x00008000,
|
||||
SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000,
|
||||
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
|
||||
SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET = 0x00040000,
|
||||
|
||||
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2
|
||||
};
|
||||
|
||||
@@ -3033,6 +3033,10 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
|
||||
switch (spellInfo->Id)
|
||||
{
|
||||
case 63026: // Force Cast (HACK: Target shouldn't be changed)
|
||||
case 63137: // Force Cast (HACK: Target shouldn't be changed; summon position should be untied from spell destination)
|
||||
spellInfo->Effects[0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
|
||||
break;
|
||||
case 70743: // AoD Special
|
||||
case 70614: // AoD Special - Vegard
|
||||
case 42436: // Drink! (Brewfest)
|
||||
@@ -3187,6 +3191,7 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
case 57761: // Fireball!
|
||||
case 64823: // Item - Druid T8 Balance 4P Bonus
|
||||
case 88819: // Daybreak
|
||||
case 18820: // Insight
|
||||
spellInfo->ProcCharges = 1;
|
||||
break;
|
||||
case 44544: // Fingers of Frost
|
||||
|
||||
@@ -57,11 +57,7 @@ enum WardenCheckType
|
||||
MODULE_CHECK = 0xD9 // 217: uint Seed + byte[20] SHA1 (check to ensure module isn't injected)
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct WardenModuleUse
|
||||
{
|
||||
@@ -84,11 +80,7 @@ struct WardenHashRequest
|
||||
uint8 Seed[16];
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
struct ClientWardenModule
|
||||
{
|
||||
|
||||
@@ -25,11 +25,7 @@
|
||||
#include "ByteBuffer.h"
|
||||
#include "Warden.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct WardenInitModuleRequest
|
||||
{
|
||||
@@ -61,11 +57,7 @@ struct WardenInitModuleRequest
|
||||
uint8 Function3_set;
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
class WorldSession;
|
||||
class Warden;
|
||||
|
||||
@@ -1571,6 +1571,9 @@ void World::SetInitialWorldSettings()
|
||||
|
||||
TC_LOG_INFO("server.loading", "Loading Gameobject Data...");
|
||||
sObjectMgr->LoadGameobjects();
|
||||
|
||||
TC_LOG_INFO("server.loading", "Loading GameObject Addon Data...");
|
||||
sObjectMgr->LoadGameObjectAddons(); // must be after LoadGameObjectTemplate() and LoadGameobjects()
|
||||
|
||||
TC_LOG_INFO("server.loading", "Loading Creature Linked Respawn...");
|
||||
sObjectMgr->LoadLinkedRespawn(); // must be after LoadCreatures(), LoadGameObjects()
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "GroupMgr.h"
|
||||
#include "MMapFactory.h"
|
||||
#include "DisableMgr.h"
|
||||
#include "SpellHistory.h"
|
||||
|
||||
class misc_commandscript : public CommandScript
|
||||
{
|
||||
@@ -723,7 +724,7 @@ public:
|
||||
|
||||
if (!*args)
|
||||
{
|
||||
target->RemoveAllSpellCooldown();
|
||||
target->GetSpellHistory()->ResetAllCooldowns();
|
||||
handler->PSendSysMessage(LANG_REMOVEALL_COOLDOWN, nameLink.c_str());
|
||||
}
|
||||
else
|
||||
@@ -733,14 +734,15 @@ public:
|
||||
if (!spellIid)
|
||||
return false;
|
||||
|
||||
if (!sSpellMgr->GetSpellInfo(spellIid))
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellIid);
|
||||
if (!spellInfo)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_UNKNOWN_SPELL, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
target->RemoveSpellCooldown(spellIid, true);
|
||||
target->GetSpellHistory()->ResetCooldown(spellIid, true);
|
||||
handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, spellIid, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
|
||||
}
|
||||
return true;
|
||||
@@ -1453,7 +1455,7 @@ public:
|
||||
* Player %s %s (guid: %u) - I. LANG_PINFO_PLAYER
|
||||
* ** GM Mode active, Phase: -1 - II. LANG_PINFO_GM_ACTIVE (if GM)
|
||||
* ** Banned: (Type, Reason, Time, By) - III. LANG_PINFO_BANNED (if banned)
|
||||
* ** Muted: (Time, Reason, By) - IV. LANG_PINFO_MUTED (if muted)
|
||||
* ** Muted: (Reason, Time, By) - IV. LANG_PINFO_MUTED (if muted)
|
||||
* * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT
|
||||
* * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN
|
||||
* * Uses OS: %s - Latency: %u ms - VII. LANG_PINFO_ACC_OS
|
||||
@@ -1706,7 +1708,7 @@ public:
|
||||
|
||||
// Output IV. LANG_PINFO_MUTED if mute is applied
|
||||
if (muteTime > 0)
|
||||
handler->PSendSysMessage(LANG_PINFO_MUTED, secsToTimeString(muteTime - time(NULL), true).c_str(), muteReason.c_str(), muteBy.c_str());
|
||||
handler->PSendSysMessage(LANG_PINFO_MUTED, muteReason.c_str(), secsToTimeString(muteTime - time(nullptr), true).c_str(), muteBy.c_str());
|
||||
|
||||
// Output V. LANG_PINFO_ACC_ACCOUNT
|
||||
handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security);
|
||||
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
@@ -165,17 +165,6 @@ public:
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
// char* pmana = strtok((char*)args, " ");
|
||||
// if (!pmana)
|
||||
// return false;
|
||||
|
||||
// char* pmanaMax = strtok(NULL, " ");
|
||||
// if (!pmanaMax)
|
||||
// return false;
|
||||
|
||||
// int32 manam = atoi(pmanaMax);
|
||||
// int32 mana = atoi(pmana);
|
||||
|
||||
int32 energy = atoi((char*)args)*10;
|
||||
int32 energym = atoi((char*)args)*10;
|
||||
|
||||
@@ -186,7 +175,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
@@ -216,17 +205,6 @@ public:
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
// char* pmana = strtok((char*)args, " ");
|
||||
// if (!pmana)
|
||||
// return false;
|
||||
|
||||
// char* pmanaMax = strtok(NULL, " ");
|
||||
// if (!pmanaMax)
|
||||
// return false;
|
||||
|
||||
// int32 manam = atoi(pmanaMax);
|
||||
// int32 mana = atoi(pmana);
|
||||
|
||||
int32 rage = atoi((char*)args)*10;
|
||||
int32 ragem = atoi((char*)args)*10;
|
||||
|
||||
@@ -237,7 +215,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
@@ -275,7 +253,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
@@ -391,7 +369,7 @@ public:
|
||||
else
|
||||
mark = atoi(pmark);
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (target == NULL)
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
@@ -946,7 +924,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
@@ -987,7 +965,7 @@ public:
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
@@ -1112,7 +1090,7 @@ public:
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
|
||||
@@ -1142,7 +1120,7 @@ public:
|
||||
if (drunklevel > 100)
|
||||
drunklevel = 100;
|
||||
|
||||
if (Player* target = handler->getSelectedPlayer())
|
||||
if (Player* target = handler->getSelectedPlayerOrSelf())
|
||||
target->SetDrunkValue(drunklevel);
|
||||
|
||||
return true;
|
||||
@@ -1153,7 +1131,7 @@ public:
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
|
||||
@@ -1306,7 +1284,7 @@ public:
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
|
||||
if (!target)
|
||||
{
|
||||
|
||||
@@ -378,28 +378,13 @@ public:
|
||||
|
||||
uint32 lowGuid = atoi((char*)guidStr);
|
||||
|
||||
Creature* creature = NULL;
|
||||
|
||||
/* FIXME: impossible without entry
|
||||
if (lowguid)
|
||||
creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
|
||||
*/
|
||||
|
||||
// attempt check creature existence by DB data
|
||||
if (!creature)
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
|
||||
if (!data)
|
||||
{
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
|
||||
if (!data)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// obtain real GUID for DB operations
|
||||
lowGuid = creature->GetDBTableGUIDLow();
|
||||
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
int wait = waitStr ? atoi(waitStr) : 0;
|
||||
@@ -415,18 +400,6 @@ public:
|
||||
|
||||
WorldDatabase.Execute(stmt);
|
||||
|
||||
if (creature && creature->GetWaypointPath())
|
||||
{
|
||||
creature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
|
||||
creature->GetMotionMaster()->Initialize();
|
||||
if (creature->IsAlive()) // dead creature will reset movement generator at respawn
|
||||
{
|
||||
creature->setDeathState(JUST_DIED);
|
||||
creature->Respawn(true);
|
||||
}
|
||||
creature->SaveToDB();
|
||||
}
|
||||
|
||||
handler->SendSysMessage(LANG_WAYPOINT_ADDED);
|
||||
|
||||
return true;
|
||||
@@ -840,34 +813,22 @@ public:
|
||||
|
||||
lowguid = atoi(cId);
|
||||
|
||||
/* FIXME: impossible without entry
|
||||
if (lowguid)
|
||||
creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
|
||||
*/
|
||||
|
||||
// Attempting creature load from DB data
|
||||
if (!creature)
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
|
||||
if (!data)
|
||||
{
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
|
||||
if (!data)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 map_id = data->mapid;
|
||||
|
||||
if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
uint32 map_id = data->mapid;
|
||||
|
||||
if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
|
||||
{
|
||||
lowguid = creature->GetDBTableGUIDLow();
|
||||
handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Update(uint32 /*diff*/) // correct order goes form 1-6
|
||||
virtual void Update(uint32 /*diff*/) override // correct order goes form 1-6
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
|
||||
@@ -202,7 +202,7 @@ class boss_archaedas : public CreatureScript
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void JustDied (Unit* /*killer*/)
|
||||
void JustDied (Unit* /*killer*/) override
|
||||
{
|
||||
instance->SetData(DATA_ANCIENT_DOOR, DONE); // open the vault door
|
||||
instance->SetData(DATA_MINIONS, SPECIAL); // deactivate his minions
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
|
||||
me->SetDisplayId(me->GetCreatureTemplate()->Modelid1);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
/*####
|
||||
# npc_omen
|
||||
####*/
|
||||
|
||||
@@ -377,12 +377,12 @@ public:
|
||||
void DoSummonPriestess()
|
||||
{
|
||||
// Summon 2 Elune priestess and make each of them move to a different spot
|
||||
if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ, wingThicketLocations[0].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
|
||||
if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ, wingThicketLocations[0].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
|
||||
{
|
||||
priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[3].m_positionX, wingThicketLocations[3].m_positionY, wingThicketLocations[3].m_positionZ);
|
||||
_firstPriestessGUID = priestess->GetGUID();
|
||||
}
|
||||
if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ, wingThicketLocations[1].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
|
||||
if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ, wingThicketLocations[1].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
|
||||
{
|
||||
// Left priestess should have a distinct move point because she is the one who starts the dialogue at point reach
|
||||
priestess->GetMotionMaster()->MovePoint(1, wingThicketLocations[4].m_positionX, wingThicketLocations[4].m_positionY, wingThicketLocations[4].m_positionZ);
|
||||
@@ -480,7 +480,7 @@ public:
|
||||
break;
|
||||
case SAY_PRIESTESS_ALTAR_13:
|
||||
// summon the Guardian of Elune
|
||||
if (Creature* guard = me->SummonCreature(NPC_GUARDIAN_ELUNE, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ, wingThicketLocations[2].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
|
||||
if (Creature* guard = me->SummonCreature(NPC_GUARDIAN_ELUNE, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ, wingThicketLocations[2].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
|
||||
{
|
||||
guard->GetMotionMaster()->MovePoint(0, wingThicketLocations[5].m_positionX, wingThicketLocations[5].m_positionY, wingThicketLocations[5].m_positionZ);
|
||||
_guardEluneGUID = guard->GetGUID();
|
||||
|
||||
+1
-1
@@ -741,7 +741,7 @@ class boss_dreadscale : public CreatureScript
|
||||
switch (pointId)
|
||||
{
|
||||
case 0:
|
||||
instance->DoUseDoorOrButton(instance->GetGuidData(GO_MAIN_GATE_DOOR));
|
||||
instance->DoCloseDoorOrButton(instance->GetGuidData(GO_MAIN_GATE_DOOR));
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetInCombatWithZone();
|
||||
|
||||
+1
-1
@@ -196,7 +196,7 @@ class instance_halls_of_reflection : public InstanceMapScript
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override
|
||||
uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override
|
||||
{
|
||||
if (!_teamInInstance)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "PassiveAI.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "Transport.h"
|
||||
@@ -644,10 +645,10 @@ protected:
|
||||
{
|
||||
if (Instance->GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) == IN_PROGRESS &&
|
||||
!me->HasUnitState(UNIT_STATE_CASTING) && !me->HasReactState(REACT_PASSIVE) &&
|
||||
!me->HasSpellCooldown(BurningPitchId))
|
||||
!me->GetSpellHistory()->HasCooldown(BurningPitchId))
|
||||
{
|
||||
DoCastAOE(BurningPitchId, true);
|
||||
me->_AddCreatureSpellCooldown(BurningPitchId, time(NULL) + urand(3000, 4000) / IN_MILLISECONDS);
|
||||
me->GetSpellHistory()->AddCooldown(BurningPitchId, 0, std::chrono::milliseconds(urand(3000, 4000)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1469,7 +1470,7 @@ struct npc_gunship_boarding_addAI : public gunship_npc_AI
|
||||
DoCast(me, SPELL_BATTLE_EXPERIENCE, true);
|
||||
DoCast(me, SPELL_TELEPORT_TO_ENEMY_SHIP, true);
|
||||
DoCast(me, Instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE ? SPELL_MELEE_TARGETING_ON_ORGRIMS_HAMMER : SPELL_MELEE_TARGETING_ON_SKYBREAKER, true);
|
||||
me->_AddCreatureSpellCooldown(BurningPitchId, time(NULL) + 3);
|
||||
me->GetSpellHistory()->AddCooldown(BurningPitchId, 0, std::chrono::seconds(3));
|
||||
|
||||
std::list<Player*> players;
|
||||
Trinity::UnitAuraCheck check(true, Instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE ? SPELL_ON_ORGRIMS_HAMMER_DECK : SPELL_ON_SKYBREAKER_DECK);
|
||||
@@ -1698,11 +1699,11 @@ class npc_gunship_rocketeer : public CreatureScript
|
||||
return;
|
||||
|
||||
uint32 spellId = me->GetEntry() == NPC_SKYBREAKER_MORTAR_SOLDIER ? SPELL_ROCKET_ARTILLERY_A : SPELL_ROCKET_ARTILLERY_H;
|
||||
if (me->HasSpellCooldown(spellId))
|
||||
if (me->GetSpellHistory()->HasCooldown(spellId))
|
||||
return;
|
||||
|
||||
DoCastAOE(spellId, true);
|
||||
me->_AddCreatureSpellCooldown(spellId, time(NULL) + 9);
|
||||
me->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::seconds(9));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1060,8 +1060,8 @@ class spell_putricide_ooze_eruption_searcher : public SpellScriptLoader
|
||||
uint32 adhesiveId = sSpellMgr->GetSpellIdForDifficulty(SPELL_VOLATILE_OOZE_ADHESIVE, GetCaster());
|
||||
if (GetHitUnit()->HasAura(adhesiveId))
|
||||
{
|
||||
GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true);
|
||||
GetHitUnit()->RemoveAurasDueToSpell(adhesiveId, GetCaster()->GetGUID(), 0, AURA_REMOVE_BY_ENEMY_SPELL);
|
||||
GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ class boss_sindragosa : public CreatureScript
|
||||
events.ScheduleEvent(EVENT_AIR_MOVEMENT, 1);
|
||||
break;
|
||||
case POINT_AIR_PHASE:
|
||||
me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL);
|
||||
me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL, TRIGGERED_FULL_MASK);
|
||||
me->SetFacingTo(float(M_PI));
|
||||
events.ScheduleEvent(EVENT_AIR_MOVEMENT_FAR, 1);
|
||||
events.ScheduleEvent(EVENT_FROST_BOMB, 9000);
|
||||
@@ -491,7 +491,7 @@ class boss_sindragosa : public CreatureScript
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, FrostBeaconSelector(me)))
|
||||
{
|
||||
Talk(EMOTE_WARN_FROZEN_ORB, target);
|
||||
DoCast(target, SPELL_ICE_TOMB_DUMMY, true);
|
||||
me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, 1, nullptr, TRIGGERED_FULL_MASK);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_ICE_TOMB, urand(16000, 23000));
|
||||
break;
|
||||
@@ -1631,7 +1631,7 @@ void AddSC_boss_sindragosa()
|
||||
new spell_rimefang_icy_blast();
|
||||
new spell_frostwarden_handler_order_whelp();
|
||||
new spell_frostwarden_handler_focus_fire();
|
||||
new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY);
|
||||
new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY, TRIGGERED_IGNORE_SET_FACING);
|
||||
new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb_dummy", SPELL_FROST_BEACON);
|
||||
new at_sindragosa_lair();
|
||||
new achievement_all_you_can_eat();
|
||||
|
||||
@@ -524,14 +524,16 @@ enum AreaIds
|
||||
class spell_trigger_spell_from_caster : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId) : SpellScriptLoader(scriptName), _triggerId(triggerId) { }
|
||||
spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId, TriggerCastFlags triggerFlags = TRIGGERED_FULL_MASK)
|
||||
: SpellScriptLoader(scriptName), _triggerId(triggerId), _triggerFlags(triggerFlags) { }
|
||||
|
||||
class spell_trigger_spell_from_caster_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_trigger_spell_from_caster_SpellScript);
|
||||
|
||||
public:
|
||||
spell_trigger_spell_from_caster_SpellScript(uint32 triggerId) : SpellScript(), _triggerId(triggerId) { }
|
||||
spell_trigger_spell_from_caster_SpellScript(uint32 triggerId, TriggerCastFlags triggerFlags)
|
||||
: SpellScript(), _triggerId(triggerId), _triggerFlags(triggerFlags) { }
|
||||
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
@@ -542,7 +544,7 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader
|
||||
|
||||
void HandleTrigger()
|
||||
{
|
||||
GetCaster()->CastSpell(GetHitUnit(), _triggerId, true);
|
||||
GetCaster()->CastSpell(GetHitUnit(), _triggerId, _triggerFlags);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
@@ -551,15 +553,17 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader
|
||||
}
|
||||
|
||||
uint32 _triggerId;
|
||||
TriggerCastFlags _triggerFlags;
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_trigger_spell_from_caster_SpellScript(_triggerId);
|
||||
return new spell_trigger_spell_from_caster_SpellScript(_triggerId, _triggerFlags);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _triggerId;
|
||||
TriggerCastFlags _triggerFlags;
|
||||
};
|
||||
|
||||
template<class AI>
|
||||
|
||||
@@ -317,7 +317,7 @@ class instance_icecrown_citadel : public InstanceMapScript
|
||||
}
|
||||
|
||||
// Weekly quest spawn prevention
|
||||
uint32 GetCreatureEntry(uint32 /*guidLow*/, CreatureData const* data) override
|
||||
uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override
|
||||
{
|
||||
uint32 entry = data->id;
|
||||
switch (entry)
|
||||
@@ -372,7 +372,7 @@ class instance_icecrown_citadel : public InstanceMapScript
|
||||
return entry;
|
||||
}
|
||||
|
||||
uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override
|
||||
uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override
|
||||
{
|
||||
switch (entry)
|
||||
{
|
||||
|
||||
@@ -482,40 +482,47 @@ class boss_flame_leviathan : public CreatureScript
|
||||
if (action && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count
|
||||
{
|
||||
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4) && ActiveTowersCount == 4)
|
||||
{
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_4);
|
||||
--ActiveTowersCount;
|
||||
}
|
||||
|
||||
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3) && ActiveTowersCount == 3)
|
||||
{
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
|
||||
--ActiveTowersCount;
|
||||
}
|
||||
|
||||
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2) && ActiveTowersCount == 2)
|
||||
{
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
|
||||
--ActiveTowersCount;
|
||||
}
|
||||
|
||||
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1) && ActiveTowersCount == 1)
|
||||
{
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
|
||||
--ActiveTowersCount;
|
||||
}
|
||||
}
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_TOWER_OF_STORM_DESTROYED:
|
||||
towerOfStorms = false;
|
||||
if (towerOfStorms)
|
||||
{
|
||||
towerOfStorms = false;
|
||||
--ActiveTowersCount;
|
||||
}
|
||||
break;
|
||||
case ACTION_TOWER_OF_FROST_DESTROYED:
|
||||
towerOfFrost = false;
|
||||
if (towerOfFrost)
|
||||
{
|
||||
towerOfFrost = false;
|
||||
--ActiveTowersCount;
|
||||
}
|
||||
break;
|
||||
case ACTION_TOWER_OF_FLAMES_DESTROYED:
|
||||
towerOfFlames = false;
|
||||
if (towerOfFlames)
|
||||
{
|
||||
towerOfFlames = false;
|
||||
--ActiveTowersCount;
|
||||
}
|
||||
break;
|
||||
case ACTION_TOWER_OF_LIFE_DESTROYED:
|
||||
towerOfLife = false;
|
||||
if (towerOfLife)
|
||||
{
|
||||
towerOfLife = false;
|
||||
--ActiveTowersCount;
|
||||
}
|
||||
break;
|
||||
case ACTION_START_HARD_MODE: // Activate hard-mode enable all towers, apply buffs on leviathan
|
||||
ActiveTowers = true;
|
||||
|
||||
@@ -903,17 +903,15 @@ class boss_yogg_saron : public CreatureScript
|
||||
DoCast(me, SPELL_KNOCK_AWAY);
|
||||
|
||||
me->ResetLootMode();
|
||||
switch (_instance->GetData(DATA_KEEPERS_COUNT))
|
||||
{
|
||||
case 0:
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_4);
|
||||
case 1:
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_3);
|
||||
case 2:
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_2);
|
||||
case 3:
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_1);
|
||||
}
|
||||
uint32 keepersCount = _instance->GetData(DATA_KEEPERS_COUNT);
|
||||
if (keepersCount == 0)
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_4);
|
||||
if (keepersCount <= 1)
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_3);
|
||||
if (keepersCount <= 2)
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_2);
|
||||
if (keepersCount <= 3)
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_1);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
|
||||
@@ -174,7 +174,7 @@ class npc_commander_eligor_dawnbringer : public CreatureScript
|
||||
{
|
||||
if (id == 1)
|
||||
{
|
||||
me->SetFacingTo(PosTalkLocations[talkWing].m_orientation);
|
||||
me->SetFacingTo(PosTalkLocations[talkWing].GetOrientation());
|
||||
TurnAudience();
|
||||
|
||||
switch (talkWing)
|
||||
|
||||
@@ -24,53 +24,6 @@
|
||||
#include "TemporarySummon.h"
|
||||
#include "CombatAI.h"
|
||||
|
||||
/*######
|
||||
## npc_squire_david
|
||||
######*/
|
||||
|
||||
enum SquireDavid
|
||||
{
|
||||
QUEST_THE_ASPIRANT_S_CHALLENGE_H = 13680,
|
||||
QUEST_THE_ASPIRANT_S_CHALLENGE_A = 13679,
|
||||
|
||||
NPC_ARGENT_VALIANT = 33448,
|
||||
|
||||
GOSSIP_TEXTID_SQUIRE = 14407
|
||||
};
|
||||
|
||||
#define GOSSIP_SQUIRE_ITEM_1 "I am ready to fight!"
|
||||
#define GOSSIP_SQUIRE_ITEM_2 "How do the Argent Crusader raiders fight?"
|
||||
|
||||
class npc_squire_david : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_squire_david() : CreatureScript("npc_squire_david") { }
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_H) == QUEST_STATUS_INCOMPLETE ||
|
||||
player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_A) == QUEST_STATUS_INCOMPLETE)//We need more info about it.
|
||||
{
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
|
||||
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
|
||||
}
|
||||
|
||||
player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SQUIRE, creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
|
||||
{
|
||||
player->PlayerTalkClass->ClearMenus();
|
||||
if (action == GOSSIP_ACTION_INFO_DEF+1)
|
||||
{
|
||||
player->CLOSE_GOSSIP_MENU();
|
||||
creature->SummonCreature(NPC_ARGENT_VALIANT, 8575.451f, 952.472f, 547.554f, 0.38f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_argent_valiant
|
||||
######*/
|
||||
@@ -837,7 +790,6 @@ class npc_frostbrood_skytalon : public CreatureScript
|
||||
|
||||
void AddSC_icecrown()
|
||||
{
|
||||
new npc_squire_david;
|
||||
new npc_argent_valiant;
|
||||
new npc_guardian_pavilion;
|
||||
new npc_tournament_training_dummy;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "ScriptedEscortAI.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
@@ -261,13 +261,13 @@ class OPvPCapturePointNA : public OPvPCapturePoint
|
||||
public:
|
||||
OPvPCapturePointNA(OutdoorPvP* pvp);
|
||||
|
||||
bool Update(uint32 diff);
|
||||
bool Update(uint32 diff) override;
|
||||
|
||||
void ChangeState();
|
||||
void ChangeState() override;
|
||||
|
||||
void FillInitialWorldStates(WorldPacket & data);
|
||||
void FillInitialWorldStates(WorldPacket & data) override;
|
||||
|
||||
bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go);
|
||||
bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go) override;
|
||||
|
||||
int32 HandleOpenGo(Player* player, ObjectGuid guid) override;
|
||||
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ public:
|
||||
Map::PlayerList const &PlayerList = map->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
|
||||
if (Player* i_pl = i->GetSource())
|
||||
if (i_pl->IsAlive() && (dist = i_pl->IsWithinDist(me, 45)))
|
||||
if (i_pl->IsAlive() && (dist = i_pl->GetDistance(me)) < 45)
|
||||
{
|
||||
i_pl->RemoveAurasDueToSpell(SPELL_INHIBITMAGIC);
|
||||
me->AddAura(SPELL_INHIBITMAGIC, i_pl);
|
||||
|
||||
@@ -27,6 +27,7 @@ set(scripts_STAT_SRCS
|
||||
Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
|
||||
Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
|
||||
Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
|
||||
Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
|
||||
Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
|
||||
Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
|
||||
Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp
|
||||
|
||||
+3
-3
@@ -87,11 +87,11 @@ class boss_warchief_kargath_bladefist : public CreatureScript
|
||||
resetcheck_timer = 5000;
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (type == 1)
|
||||
if (action == ACTION_EXECUTIONER_TAUNT)
|
||||
{
|
||||
switch (data)
|
||||
switch (instance->GetData(DATA_TEAM_IN_INSTANCE))
|
||||
{
|
||||
case ALLIANCE:
|
||||
Talk(SAY_CALL_EXECUTIONER_A);
|
||||
|
||||
+33
-220
@@ -32,20 +32,11 @@ EndScriptData */
|
||||
#include "SpellAuras.h"
|
||||
#include "shattered_halls.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CLEAVE = 15284,
|
||||
|
||||
SPELL_EXECUTE_1 = 39288,
|
||||
SPELL_EXECUTE_2,
|
||||
SPELL_EXECUTE_3
|
||||
};
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_S },
|
||||
{GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_N },
|
||||
{0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE}
|
||||
{ GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
|
||||
{ GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
|
||||
{ 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }
|
||||
};
|
||||
|
||||
class instance_shattered_halls : public InstanceMapScript
|
||||
@@ -77,9 +68,7 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
if (!_team)
|
||||
_team = player->GetTeam();
|
||||
|
||||
player->RemoveAurasDueToSpell(SPELL_EXECUTE_1);
|
||||
player->RemoveAurasDueToSpell(SPELL_EXECUTE_2);
|
||||
player->RemoveAurasDueToSpell(SPELL_EXECUTE_3);
|
||||
player->CastSpell(player, SPELL_REMOVE_KARGATH_EXECUTIONER, true);
|
||||
|
||||
if (!executionTimer || executionerGUID.IsEmpty())
|
||||
return;
|
||||
@@ -87,13 +76,13 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
switch (executed)
|
||||
{
|
||||
case 0:
|
||||
ex = player->AddAura(SPELL_EXECUTE_1, player);
|
||||
ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_1, player);
|
||||
break;
|
||||
case 1:
|
||||
ex = player->AddAura(SPELL_EXECUTE_2, player);
|
||||
ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_2, player);
|
||||
break;
|
||||
case 2:
|
||||
ex = player->AddAura(SPELL_EXECUTE_3, player);
|
||||
ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_3, player);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -151,10 +140,22 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
break;
|
||||
case NPC_SHATTERED_EXECUTIONER:
|
||||
executionTimer = 55 * MINUTE * IN_MILLISECONDS;
|
||||
DoCastSpellOnPlayers(SPELL_EXECUTE_1);
|
||||
DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_1);
|
||||
executionerGUID = creature->GetGUID();
|
||||
SaveToDB();
|
||||
break;
|
||||
case NPC_CAPTAIN_ALINA:
|
||||
case NPC_CAPTAIN_BONESHATTER:
|
||||
victimsGUID[0] = creature->GetGUID();
|
||||
break;
|
||||
case NPC_ALLIANCE_VICTIM_1:
|
||||
case NPC_HORDE_VICTIM_1:
|
||||
victimsGUID[1] = creature->GetGUID();
|
||||
break;
|
||||
case NPC_ALLIANCE_VICTIM_2:
|
||||
case NPC_HORDE_VICTIM_2:
|
||||
victimsGUID[2] = creature->GetGUID();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,16 +169,14 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
case DATA_SHATTERED_EXECUTIONER:
|
||||
if (state == DONE)
|
||||
{
|
||||
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_1);
|
||||
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_2);
|
||||
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_3);
|
||||
DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER);
|
||||
executionTimer = 0;
|
||||
SaveToDB();
|
||||
}
|
||||
break;
|
||||
case DATA_KARGATH:
|
||||
if (Creature* executioner = instance->GetCreature(executionerGUID))
|
||||
executioner->AI()->Reset();
|
||||
executioner->AI()->Reset(); // trigger removal of IMMUNE_TO_PC flag
|
||||
break;
|
||||
case DATA_OMROGG:
|
||||
break;
|
||||
@@ -191,16 +190,16 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
{
|
||||
case NPC_GRAND_WARLOCK_NETHEKURSE:
|
||||
return nethekurseGUID;
|
||||
break;
|
||||
case NPC_KARGATH_BLADEFIST:
|
||||
return kargathGUID;
|
||||
break;
|
||||
case NPC_SHATTERED_EXECUTIONER:
|
||||
return executionerGUID;
|
||||
break;
|
||||
case DATA_FIRST_PRISONER:
|
||||
case DATA_SECOND_PRISONER:
|
||||
case DATA_THIRD_PRISONER:
|
||||
return victimsGUID[data - DATA_FIRST_PRISONER];
|
||||
default:
|
||||
return ObjectGuid::Empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,13 +252,10 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
{
|
||||
case DATA_PRISONERS_EXECUTED:
|
||||
return executed;
|
||||
break;
|
||||
case DATA_TEAM_IN_INSTANCE:
|
||||
return _team;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,27 +265,25 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
return;
|
||||
|
||||
if (executionTimer <= diff)
|
||||
{
|
||||
{
|
||||
DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER);
|
||||
switch (++executed)
|
||||
{
|
||||
case 1:
|
||||
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_1);
|
||||
DoCastSpellOnPlayers(SPELL_EXECUTE_2);
|
||||
DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_2);
|
||||
executionTimer = 10 * MINUTE * IN_MILLISECONDS;
|
||||
break;
|
||||
case 2:
|
||||
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_2);
|
||||
DoCastSpellOnPlayers(SPELL_EXECUTE_3);
|
||||
DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_3);
|
||||
executionTimer = 15 * MINUTE * IN_MILLISECONDS;
|
||||
break;
|
||||
default:
|
||||
DoRemoveAurasDueToSpellOnPlayers(SPELL_EXECUTE_3);
|
||||
executionTimer = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Creature* executioner = instance->GetCreature(executionerGUID))
|
||||
executioner->AI()->SetData(1, executed);
|
||||
executioner->AI()->SetData(DATA_PRISONERS_EXECUTED, executed);
|
||||
|
||||
SaveToDB();
|
||||
}
|
||||
@@ -297,10 +291,11 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
executionTimer -= diff;
|
||||
}
|
||||
|
||||
protected:
|
||||
private:
|
||||
ObjectGuid nethekurseGUID;
|
||||
ObjectGuid kargathGUID;
|
||||
ObjectGuid executionerGUID;
|
||||
ObjectGuid victimsGUID[3];
|
||||
|
||||
uint8 executed;
|
||||
uint32 executionTimer;
|
||||
@@ -308,189 +303,7 @@ class instance_shattered_halls : public InstanceMapScript
|
||||
};
|
||||
};
|
||||
|
||||
class at_nethekurse_exit : public AreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_nethekurse_exit() : AreaTriggerScript("at_nethekurse_exit") { };
|
||||
|
||||
bool OnTrigger(Player* player, AreaTriggerEntry const*) override
|
||||
{
|
||||
if (InstanceScript* is = player->GetInstanceScript())
|
||||
{
|
||||
if (is->instance->IsHeroic())
|
||||
{
|
||||
Creature* executioner = nullptr;
|
||||
|
||||
is->instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY());
|
||||
if (Creature* kargath = ObjectAccessor::GetCreature(*player, is->GetGuidData(NPC_KARGATH_BLADEFIST)))
|
||||
{
|
||||
if (is->GetGuidData(NPC_SHATTERED_EXECUTIONER).IsEmpty())
|
||||
{
|
||||
executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner);
|
||||
kargath->AI()->SetData(1, is->GetData(DATA_TEAM_IN_INSTANCE));
|
||||
}
|
||||
}
|
||||
|
||||
if (executioner)
|
||||
for (uint8 i = 0; i < VictimCount; ++i)
|
||||
executioner->SummonCreature(executionerVictims[i](is->GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class boss_shattered_executioner : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { }
|
||||
|
||||
struct boss_shattered_executionerAI : public BossAI
|
||||
{
|
||||
boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER)
|
||||
{
|
||||
Initialize();
|
||||
};
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
cleaveTimer = 500;
|
||||
me->ResetLootMode();
|
||||
switch (instance->GetData(DATA_PRISONERS_EXECUTED))
|
||||
{
|
||||
case 0:
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_3);
|
||||
case 1:
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_2);
|
||||
case 2:
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_1);
|
||||
}
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
if (instance->GetBossState(DATA_KARGATH) == DONE)
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
||||
else
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature*) override { }
|
||||
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
_JustDied();
|
||||
Map::PlayerList const &players = instance->instance->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
{
|
||||
Player* pl = itr->GetSource();
|
||||
uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
|
||||
if (pl->GetQuestStatus(qId) != QUEST_STATUS_NONE && pl->GetQuestStatus(qId) != QUEST_STATUS_FAILED)
|
||||
pl->CompleteQuest(qId);
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
{
|
||||
if (type == 1)
|
||||
{
|
||||
uint32 entry = executionerVictims[data - 1](instance->GetData(DATA_TEAM_IN_INSTANCE));
|
||||
if (Creature* victim = me->FindNearestCreature(entry, 30.0f, true))
|
||||
me->Kill(victim);
|
||||
|
||||
if (data == 1)
|
||||
{
|
||||
Map::PlayerList const &players = instance->instance->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
{
|
||||
Player* pl = itr->GetSource();
|
||||
uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
|
||||
if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
|
||||
pl->FailQuest(qId);
|
||||
}
|
||||
}
|
||||
|
||||
switch (data)
|
||||
{
|
||||
case 3:
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
|
||||
case 2:
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
|
||||
case 1:
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (cleaveTimer <= diff)
|
||||
{
|
||||
DoCast(SPELL_CLEAVE);
|
||||
cleaveTimer = urand(5000, 7000);
|
||||
}
|
||||
else
|
||||
cleaveTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
uint32 cleaveTimer;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetInstanceAI<boss_shattered_executionerAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_kargath_executioner : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { }
|
||||
|
||||
class spell_kargath_executioner_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_kargath_executioner_AuraScript);
|
||||
|
||||
bool AreaCheck(Unit* target)
|
||||
{
|
||||
if (target->GetMap()->GetId() != 540)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetTypeId() == TYPEID_PLAYER;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_kargath_executioner_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_shattered_halls()
|
||||
{
|
||||
new instance_shattered_halls();
|
||||
new at_nethekurse_exit();
|
||||
new boss_shattered_executioner();
|
||||
new spell_kargath_executioner();
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2015 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/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Player.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "shattered_halls.h"
|
||||
|
||||
class at_nethekurse_exit : public AreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_nethekurse_exit() : AreaTriggerScript("at_nethekurse_exit") { };
|
||||
|
||||
bool OnTrigger(Player* player, AreaTriggerEntry const*) override
|
||||
{
|
||||
if (InstanceScript* is = player->GetInstanceScript())
|
||||
{
|
||||
if (is->instance->IsHeroic())
|
||||
{
|
||||
Creature* executioner = nullptr;
|
||||
|
||||
is->instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY());
|
||||
if (Creature* kargath = ObjectAccessor::GetCreature(*player, is->GetGuidData(NPC_KARGATH_BLADEFIST)))
|
||||
{
|
||||
if (is->GetGuidData(NPC_SHATTERED_EXECUTIONER).IsEmpty())
|
||||
{
|
||||
executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner);
|
||||
kargath->AI()->DoAction(ACTION_EXECUTIONER_TAUNT);
|
||||
}
|
||||
}
|
||||
|
||||
if (executioner)
|
||||
for (uint8 i = 0; i < VictimCount; ++i)
|
||||
executioner->SummonCreature(executionerVictims[i](is->GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CLEAVE = 15284
|
||||
};
|
||||
|
||||
class boss_shattered_executioner : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { }
|
||||
|
||||
struct boss_shattered_executionerAI : public BossAI
|
||||
{
|
||||
boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER)
|
||||
{
|
||||
Initialize();
|
||||
};
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
cleaveTimer = 500;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
|
||||
// _Reset() resets the loot mode, so we add them again, if any
|
||||
uint32 prisonersExecuted = instance->GetData(DATA_PRISONERS_EXECUTED);
|
||||
if (prisonersExecuted == 0)
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_3);
|
||||
if (prisonersExecuted <= 1)
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_2);
|
||||
if (prisonersExecuted <= 2)
|
||||
me->AddLootMode(LOOT_MODE_HARD_MODE_1);
|
||||
|
||||
if (instance->GetBossState(DATA_KARGATH) == DONE)
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
||||
else
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature*) override { } // avoid despawn of prisoners on death/reset
|
||||
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
_JustDied();
|
||||
|
||||
if (instance->GetData(DATA_PRISONERS_EXECUTED) > 0)
|
||||
return;
|
||||
|
||||
Map::PlayerList const &players = instance->instance->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
{
|
||||
Player* pl = itr->GetSource();
|
||||
uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
|
||||
if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
|
||||
pl->CompleteQuest(qId);
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
{
|
||||
if (type == DATA_PRISONERS_EXECUTED && data <= 3)
|
||||
{
|
||||
if (Creature* victim = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FIRST_PRISONER + data - 1)))
|
||||
me->Kill(victim);
|
||||
|
||||
if (data == 1)
|
||||
{
|
||||
Map::PlayerList const &players = instance->instance->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
{
|
||||
Player* pl = itr->GetSource();
|
||||
uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
|
||||
if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
|
||||
pl->FailQuest(qId);
|
||||
}
|
||||
}
|
||||
|
||||
switch (data)
|
||||
{
|
||||
case 3:
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
|
||||
case 2:
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
|
||||
case 1:
|
||||
me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (cleaveTimer <= diff)
|
||||
{
|
||||
DoCast(SPELL_CLEAVE);
|
||||
cleaveTimer = urand(5000, 7000);
|
||||
}
|
||||
else
|
||||
cleaveTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
uint32 cleaveTimer;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetInstanceAI<boss_shattered_executionerAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_kargath_executioner : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { }
|
||||
|
||||
class spell_kargath_executioner_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_kargath_executioner_AuraScript);
|
||||
|
||||
bool AreaCheck(Unit* target)
|
||||
{
|
||||
if (target->GetMap()->GetId() != 540)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetTypeId() == TYPEID_PLAYER;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_kargath_executioner_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
class spell_remove_kargath_executioner : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_remove_kargath_executioner() : SpellScriptLoader("spell_remove_kargath_executioner") { }
|
||||
|
||||
class spell_remove_kargath_executioner_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_remove_kargath_executioner_SpellScript);
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Unit* target = GetCaster();
|
||||
|
||||
target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_1);
|
||||
target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_2);
|
||||
target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_3);
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetTypeId() == TYPEID_PLAYER;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_remove_kargath_executioner_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_remove_kargath_executioner_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_shattered_halls()
|
||||
{
|
||||
new at_nethekurse_exit();
|
||||
new boss_shattered_executioner();
|
||||
new spell_kargath_executioner();
|
||||
new spell_remove_kargath_executioner();
|
||||
}
|
||||
@@ -33,7 +33,11 @@ enum DataTypes
|
||||
DATA_SHATTERED_EXECUTIONER = 3,
|
||||
DATA_PRISONERS_EXECUTED = 4,
|
||||
|
||||
DATA_TEAM_IN_INSTANCE = 5
|
||||
DATA_TEAM_IN_INSTANCE = 5,
|
||||
|
||||
DATA_FIRST_PRISONER,
|
||||
DATA_SECOND_PRISONER,
|
||||
DATA_THIRD_PRISONER
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
@@ -70,6 +74,20 @@ enum QuestIds
|
||||
QUEST_IMPRISONED_H = 9525
|
||||
};
|
||||
|
||||
enum InstanceSpells
|
||||
{
|
||||
SPELL_KARGATH_EXECUTIONER_1 = 39288,
|
||||
SPELL_KARGATH_EXECUTIONER_2 = 39289,
|
||||
SPELL_KARGATH_EXECUTIONER_3 = 39290,
|
||||
|
||||
SPELL_REMOVE_KARGATH_EXECUTIONER = 39291
|
||||
};
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_EXECUTIONER_TAUNT = 1
|
||||
};
|
||||
|
||||
const Position Executioner = { 152.8524f, -83.63912f, 2.021005f, 0.06981317f };
|
||||
|
||||
struct FactionSpawnerHelper
|
||||
@@ -77,7 +95,7 @@ struct FactionSpawnerHelper
|
||||
FactionSpawnerHelper(uint32 allianceEntry, uint32 hordeEntry, const Position& pos) : _allianceNPC(allianceEntry), _hordeNPC(hordeEntry), _spawnPos(pos) { }
|
||||
|
||||
inline uint32 operator()(uint32 teamID) const { return teamID == ALLIANCE ? _allianceNPC : _hordeNPC; }
|
||||
inline const Position GetPos() const { return _spawnPos; }
|
||||
inline Position const& GetPos() const { return _spawnPos; }
|
||||
|
||||
private:
|
||||
const uint32 _allianceNPC;
|
||||
|
||||
@@ -420,10 +420,482 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum ExorcismSpells
|
||||
{
|
||||
SPELL_JULES_GOES_PRONE = 39283,
|
||||
SPELL_JULES_THREATENS_AURA = 39284,
|
||||
SPELL_JULES_GOES_UPRIGHT = 39294,
|
||||
SPELL_JULES_VOMITS_AURA = 39295,
|
||||
|
||||
SPELL_BARADAS_COMMAND = 39277,
|
||||
SPELL_BARADA_FALTERS = 39278,
|
||||
};
|
||||
|
||||
enum ExorcismTexts
|
||||
{
|
||||
SAY_BARADA_1 = 0,
|
||||
SAY_BARADA_2 = 1,
|
||||
SAY_BARADA_3 = 2,
|
||||
SAY_BARADA_4 = 3,
|
||||
SAY_BARADA_5 = 4,
|
||||
SAY_BARADA_6 = 5,
|
||||
SAY_BARADA_7 = 6,
|
||||
SAY_BARADA_8 = 7,
|
||||
|
||||
SAY_JULES_1 = 0,
|
||||
SAY_JULES_2 = 1,
|
||||
SAY_JULES_3 = 2,
|
||||
SAY_JULES_4 = 3,
|
||||
SAY_JULES_5 = 4,
|
||||
};
|
||||
|
||||
Position const exorcismPos[11] =
|
||||
{
|
||||
{ -707.123f, 2751.686f, 101.592f, 4.577416f }, //Barada Waypoint-1 0
|
||||
{ -710.731f, 2749.075f, 101.592f, 1.513286f }, //Barada Cast position 1
|
||||
{ -710.332f, 2754.394f, 102.948f, 3.207566f }, //Jules 2
|
||||
{ -714.261f, 2747.754f, 103.391f, 0.0f }, //Jules Waypoint-1 3
|
||||
{ -713.113f, 2750.194f, 103.391f, 0.0f }, //Jules Waypoint-2 4
|
||||
{ -710.385f, 2750.896f, 103.391f, 0.0f }, //Jules Waypoint-3 5
|
||||
{ -708.309f, 2750.062f, 103.391f, 0.0f }, //Jules Waypoint-4 6
|
||||
{ -707.401f, 2747.696f, 103.391f, 0.0f }, //Jules Waypoint-5 7
|
||||
{ -708.591f, 2745.266f, 103.391f, 0.0f }, //Jules Waypoint-6 8
|
||||
{ -710.597f, 2744.035f, 103.391f, 0.0f }, //Jules Waypoint-7 9
|
||||
{ -713.089f, 2745.302f, 103.391f, 0.0f }, //Jules Waypoint-8 10
|
||||
};
|
||||
|
||||
enum ExorcismMisc
|
||||
{
|
||||
NPC_DARKNESS_RELEASED = 22507,
|
||||
NPC_FOUL_PURGE = 22506,
|
||||
NPC_COLONEL_JULES = 22432,
|
||||
|
||||
BARADAS_GOSSIP_MESSAGE = 10683,
|
||||
|
||||
QUEST_THE_EXORCISM_OF_COLONEL_JULES = 10935,
|
||||
|
||||
ACTION_START_EVENT = 1,
|
||||
ACTION_JULES_HOVER = 2,
|
||||
ACTION_JULES_FLIGHT = 3,
|
||||
ACTION_JULES_MOVE_HOME = 4,
|
||||
};
|
||||
|
||||
enum ExorcismEvents
|
||||
{
|
||||
EVENT_BARADAS_TALK = 1,
|
||||
|
||||
//Colonel Jules
|
||||
EVENT_SUMMON_SKULL = 1,
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_barada
|
||||
######*/
|
||||
|
||||
class npc_barada : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_barada() : CreatureScript("npc_barada") { }
|
||||
|
||||
struct npc_baradaAI : public ScriptedAI
|
||||
{
|
||||
npc_baradaAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
step = 0;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
Initialize();
|
||||
|
||||
playerGUID.Clear();
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
|
||||
}
|
||||
|
||||
void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
|
||||
{
|
||||
player->PlayerTalkClass->ClearMenus();
|
||||
switch (gossipListId)
|
||||
{
|
||||
case 1:
|
||||
player->PlayerTalkClass->SendCloseGossip();
|
||||
me->AI()->Talk(SAY_BARADA_1);
|
||||
me->AI()->DoAction(ACTION_START_EVENT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_START_EVENT)
|
||||
{
|
||||
if (Creature* jules = me->FindNearestCreature(NPC_COLONEL_JULES, 20.0f, true))
|
||||
{
|
||||
julesGUID = jules->GetGUID();
|
||||
jules->AI()->Talk(SAY_JULES_1);
|
||||
}
|
||||
|
||||
me->GetMotionMaster()->MovePoint(0, exorcismPos[1]);
|
||||
Talk(SAY_BARADA_2);
|
||||
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (id == 0)
|
||||
me->GetMotionMaster()->MovePoint(1, exorcismPos[1]);
|
||||
|
||||
if (id == 1)
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 2000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
{
|
||||
jules->AI()->DoAction(ACTION_JULES_MOVE_HOME);
|
||||
jules->RemoveAllAuras();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BARADAS_TALK:
|
||||
switch (step)
|
||||
{
|
||||
case 0:
|
||||
me->SetFacingTo(1.513286f);
|
||||
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 3000);
|
||||
step++;
|
||||
break;
|
||||
case 1:
|
||||
DoCast(SPELL_BARADAS_COMMAND);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
|
||||
step++;
|
||||
break;
|
||||
case 2:
|
||||
Talk(SAY_BARADA_3);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 7000);
|
||||
step++;
|
||||
break;
|
||||
case 3:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->Talk(SAY_JULES_2);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 18000);
|
||||
step++;
|
||||
break;
|
||||
case 4:
|
||||
DoCast(SPELL_BARADA_FALTERS);
|
||||
me->HandleEmoteCommand(EMOTE_STAND_STATE_NONE);
|
||||
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->DoAction(ACTION_JULES_HOVER);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 11000);
|
||||
step++;
|
||||
break;
|
||||
case 5:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->Talk(SAY_JULES_3);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 13000);
|
||||
step++;
|
||||
break;
|
||||
case 6:
|
||||
Talk(SAY_BARADA_4);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
|
||||
step++;
|
||||
break;
|
||||
case 7:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->Talk(SAY_JULES_3);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 13000);
|
||||
step++;
|
||||
break;
|
||||
case 8:
|
||||
Talk(SAY_BARADA_4);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 12000);
|
||||
step++;
|
||||
break;
|
||||
case 9:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->Talk(SAY_JULES_4);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 12000);
|
||||
step++;
|
||||
break;
|
||||
case 10:
|
||||
Talk(SAY_BARADA_4);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
|
||||
step++;
|
||||
break;
|
||||
case 11:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->DoAction(ACTION_JULES_FLIGHT);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 12:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->Talk(SAY_JULES_4);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 8000);
|
||||
step++;
|
||||
break;
|
||||
case 13:
|
||||
Talk(SAY_BARADA_5);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 14:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->Talk(SAY_JULES_4);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 15:
|
||||
Talk(SAY_BARADA_6);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 16:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->Talk(SAY_JULES_5);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 17:
|
||||
Talk(SAY_BARADA_7);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 18:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->AI()->Talk(SAY_JULES_3);
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 19:
|
||||
Talk(SAY_BARADA_7);
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 20:
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
{
|
||||
jules->AI()->DoAction(ACTION_JULES_MOVE_HOME);
|
||||
jules->RemoveAura(SPELL_JULES_VOMITS_AURA);
|
||||
}
|
||||
|
||||
events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
|
||||
step++;
|
||||
break;
|
||||
case 21:
|
||||
//End
|
||||
if (Player* player = ObjectAccessor::FindPlayer(playerGUID))
|
||||
player->KilledMonsterCredit(NPC_COLONEL_JULES, ObjectGuid::Empty);
|
||||
|
||||
if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
|
||||
jules->RemoveAllAuras();
|
||||
|
||||
me->RemoveAura(SPELL_BARADAS_COMMAND);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
|
||||
|
||||
Talk(SAY_BARADA_8);
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
EnterEvadeMode();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
uint8 step;
|
||||
ObjectGuid julesGUID;
|
||||
ObjectGuid playerGUID;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_baradaAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_colonel_jules
|
||||
######*/
|
||||
|
||||
class npc_colonel_jules : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_colonel_jules() : CreatureScript("npc_colonel_jules") { }
|
||||
|
||||
struct npc_colonel_julesAI : public ScriptedAI
|
||||
{
|
||||
npc_colonel_julesAI(Creature* creature) : ScriptedAI(creature), summons(me)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
circleRounds = 0;
|
||||
point = 3;
|
||||
wpreached = false;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
|
||||
summons.DespawnAll();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_JULES_HOVER:
|
||||
me->AddAura(SPELL_JULES_GOES_PRONE, me);
|
||||
me->AddAura(SPELL_JULES_THREATENS_AURA, me);
|
||||
|
||||
me->SetCanFly(true);
|
||||
me->SetSpeed(MOVE_RUN, 0.2f);
|
||||
|
||||
me->SetFacingTo(3.207566f);
|
||||
me->GetMotionMaster()->MoveJump(exorcismPos[2], 2.0f, 2.0f);
|
||||
|
||||
events.ScheduleEvent(EVENT_SUMMON_SKULL, 10000);
|
||||
break;
|
||||
case ACTION_JULES_FLIGHT:
|
||||
circleRounds++;
|
||||
|
||||
me->RemoveAura(SPELL_JULES_GOES_PRONE);
|
||||
|
||||
me->AddAura(SPELL_JULES_GOES_UPRIGHT, me);
|
||||
me->AddAura(SPELL_JULES_VOMITS_AURA, me);
|
||||
|
||||
wpreached = true;
|
||||
me->GetMotionMaster()->MovePoint(point, exorcismPos[point]);
|
||||
break;
|
||||
case ACTION_JULES_MOVE_HOME:
|
||||
wpreached = false;
|
||||
me->SetSpeed(MOVE_RUN, 1.0f);
|
||||
me->GetMotionMaster()->MovePoint(11, exorcismPos[2]);
|
||||
|
||||
events.CancelEvent(EVENT_SUMMON_SKULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
summon->GetMotionMaster()->MoveRandom(10.0f);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (id < 10)
|
||||
wpreached = true;
|
||||
|
||||
if (id == 8)
|
||||
{
|
||||
for (uint8 i = 0; i < circleRounds; i++)
|
||||
DoSummon(NPC_FOUL_PURGE, exorcismPos[8]);
|
||||
}
|
||||
|
||||
if (id == 10)
|
||||
{
|
||||
wpreached = true;
|
||||
point = 3;
|
||||
circleRounds++;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (wpreached)
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(point, exorcismPos[point]);
|
||||
point++;
|
||||
wpreached = false;
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SUMMON_SKULL:
|
||||
uint8 summonCount = urand(1,3);
|
||||
|
||||
for (uint8 i = 0; i < summonCount; i++)
|
||||
me->SummonCreature(NPC_DARKNESS_RELEASED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 1.5f, 0, TEMPSUMMON_MANUAL_DESPAWN);
|
||||
|
||||
events.ScheduleEvent(EVENT_SUMMON_SKULL, urand(10000, 15000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
SummonList summons;
|
||||
|
||||
uint8 circleRounds;
|
||||
uint8 point;
|
||||
|
||||
bool wpreached;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_colonel_julesAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_hellfire_peninsula()
|
||||
{
|
||||
new npc_aeranas();
|
||||
new npc_ancestral_wolf();
|
||||
new npc_wounded_blood_elf();
|
||||
new npc_fel_guard_hound();
|
||||
new npc_barada();
|
||||
new npc_colonel_jules();
|
||||
}
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "Pet.h"
|
||||
#include "ReputationMgr.h"
|
||||
#include "SkillDiscovery.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "Vehicle.h"
|
||||
@@ -1310,8 +1311,8 @@ class spell_gen_divine_storm_cd_reset : public SpellScriptLoader
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Player* caster = GetCaster()->ToPlayer();
|
||||
if (caster->HasSpellCooldown(SPELL_DIVINE_STORM))
|
||||
caster->RemoveSpellCooldown(SPELL_DIVINE_STORM, true);
|
||||
if (caster->GetSpellHistory()->HasCooldown(SPELL_DIVINE_STORM))
|
||||
caster->GetSpellHistory()->ResetCooldown(SPELL_DIVINE_STORM, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
@@ -3318,7 +3319,7 @@ class spell_pvp_trinket_wotf_shared_cd : public SpellScriptLoader
|
||||
{
|
||||
// This is only needed because spells cast from spell_linked_spell are triggered by default
|
||||
// Spell::SendSpellCooldown() skips all spells with TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD
|
||||
GetCaster()->ToPlayer()->AddSpellAndCategoryCooldowns(GetSpellInfo(), GetCastItem() ? GetCastItem()->GetEntry() : 0, GetSpell());
|
||||
GetCaster()->GetSpellHistory()->StartCooldown(GetSpellInfo(), 0, GetSpell());
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
|
||||
@@ -713,24 +714,20 @@ class spell_hun_readiness : public SpellScriptLoader
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Player* caster = GetCaster()->ToPlayer();
|
||||
// immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath
|
||||
const SpellCooldowns& cm = caster->ToPlayer()->GetSpellCooldownMap();
|
||||
for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
|
||||
GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
|
||||
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
|
||||
|
||||
///! If spellId in cooldown map isn't valid, the above will return a null pointer.
|
||||
if (spellInfo &&
|
||||
spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
|
||||
if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
|
||||
spellInfo->Id != SPELL_HUNTER_READINESS &&
|
||||
spellInfo->Id != SPELL_HUNTER_BESTIAL_WRATH &&
|
||||
spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU &&
|
||||
spellInfo->GetRecoveryTime() > 0)
|
||||
caster->RemoveSpellCooldown((itr++)->first, true);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellHistory.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SkillDiscovery.h"
|
||||
@@ -1349,7 +1350,7 @@ class spell_item_red_rider_air_rifle : public SpellScriptLoader
|
||||
caster->CastSpell(caster, SPELL_AIR_RIFLE_HOLD_VISUAL, true);
|
||||
// needed because this spell shares GCD with its triggered spells (which must not be cast with triggered flag)
|
||||
if (Player* player = caster->ToPlayer())
|
||||
player->GetGlobalCooldownMgr().CancelGlobalCooldown(GetSpellInfo());
|
||||
player->GetSpellHistory()->CancelGlobalCooldown(GetSpellInfo());
|
||||
if (urand(0, 4))
|
||||
caster->CastSpell(target, SPELL_AIR_RIFLE_SHOOT, false);
|
||||
else
|
||||
@@ -2368,7 +2369,7 @@ class spell_item_rocket_boots : public SpellScriptLoader
|
||||
if (Battleground* bg = caster->GetBattleground())
|
||||
bg->EventPlayerDroppedFlag(caster);
|
||||
|
||||
caster->RemoveSpellCooldown(SPELL_ROCKET_BOOTS_PROC);
|
||||
caster->GetSpellHistory()->ResetCooldown(SPELL_ROCKET_BOOTS_PROC);
|
||||
caster->CastSpell(caster, SPELL_ROCKET_BOOTS_PROC, true, NULL);
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 119 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user