aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/Server/AuthSocket.cpp13
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp67
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h1
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp2
-rw-r--r--src/server/game/Accounts/RBAC.cpp4
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp96
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundIC.h2
-rw-r--r--src/server/game/Chat/Chat.cpp21
-rw-r--r--src/server/game/DataStores/DBCStores.cpp22
-rw-r--r--src/server/game/DataStores/DBCStructure.h22
-rw-r--r--src/server/game/DataStores/DBCfmt.h2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp65
-rw-r--r--src/server/game/Entities/Creature/Creature.h38
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp96
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h25
-rw-r--r--src/server/game/Entities/Object/Object.cpp23
-rw-r--r--src/server/game/Entities/Object/Object.h48
-rw-r--r--src/server/game/Entities/Player/Player.cpp33
-rw-r--r--src/server/game/Entities/Player/Player.h6
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp940
-rw-r--r--src/server/game/Entities/Transport/Transport.h114
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp92
-rw-r--r--src/server/game/Entities/Unit/Unit.h14
-rw-r--r--src/server/game/Globals/ObjectAccessor.cpp9
-rw-r--r--src/server/game/Globals/ObjectAccessor.h2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp12
-rw-r--r--src/server/game/Globals/ObjectMgr.h5
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.cpp29
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp30
-rw-r--r--src/server/game/Grids/ObjectGridLoader.h1
-rw-r--r--src/server/game/Guilds/Guild.cpp2
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp2
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp23
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp1
-rw-r--r--src/server/game/Maps/Map.cpp409
-rw-r--r--src/server/game/Maps/Map.h45
-rw-r--r--src/server/game/Maps/MapManager.cpp8
-rw-r--r--src/server/game/Maps/MapManager.h9
-rw-r--r--src/server/game/Maps/TransportMgr.cpp453
-rw-r--r--src/server/game/Maps/TransportMgr.h159
-rw-r--r--src/server/game/Miscellaneous/Language.h2
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h3
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp40
-rw-r--r--src/server/game/Scripting/MapScripts.cpp20
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp10
-rw-r--r--src/server/game/Scripting/ScriptMgr.h8
-rw-r--r--src/server/game/Server/WorldSession.cpp14
-rw-r--r--src/server/game/Spells/Spell.cpp20
-rw-r--r--src/server/game/Spells/SpellMgr.cpp2
-rw-r--r--src/server/game/World/World.cpp9
-rw-r--r--src/server/scripts/Commands/cs_account.cpp12
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp28
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp8
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp49
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp6
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp12
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp497
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp266
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h6
-rw-r--r--src/server/scripts/Northrend/zone_zuldrak.cpp4
-rw-r--r--src/server/shared/Database/Implementation/WorldDatabase.cpp2
-rw-r--r--src/server/shared/Database/Implementation/WorldDatabase.h2
-rw-r--r--src/tools/mesh_extractor/ContinentBuilder.cpp6
-rw-r--r--src/tools/mesh_extractor/Geometry.cpp4
-rw-r--r--src/tools/mesh_extractor/MPQ.h3
-rw-r--r--src/tools/mesh_extractor/MPQManager.cpp2
-rw-r--r--src/tools/mesh_extractor/MeshExtractor.cpp10
-rw-r--r--src/tools/mesh_extractor/TileBuilder.cpp31
-rw-r--r--src/tools/mesh_extractor/Utils.cpp22
70 files changed, 2529 insertions, 1516 deletions
diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp
index 1ab9ae6eb62..4a9d3ce7faf 100644
--- a/src/server/authserver/Server/AuthSocket.cpp
+++ b/src/server/authserver/Server/AuthSocket.cpp
@@ -222,12 +222,25 @@ void AuthSocket::OnClose(void)
// Read the packet from the client
void AuthSocket::OnRead()
{
+ #define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW 3
+ uint32 challengesInARow = 0;
uint8 _cmd;
while (1)
{
if (!socket().recv_soft((char *)&_cmd, 1))
return;
+ if (_cmd == AUTH_LOGON_CHALLENGE)
+ {
+ ++challengesInARow;
+ if (challengesInARow == MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW)
+ {
+ TC_LOG_WARN(LOG_FILTER_AUTHSERVER, "Got %u AUTH_LOGON_CHALLENGE in a row from '%s', possible ongoing DoS", challengesInARow, socket().getRemoteAddress().c_str());
+ socket().shutdown();
+ return;
+ }
+ }
+
size_t i;
// Circle through known commands and call the correct command handler
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 3823f7ba287..f01d0d1ab03 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -34,6 +34,7 @@
#include "SmartScript.h"
#include "SpellMgr.h"
#include "Vehicle.h"
+#include "MoveSplineInit.h"
#include "GameEventMgr.h"
class TrinityStringTextBuilder
@@ -507,18 +508,20 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
- if (IsUnit(*itr))
+ if (!IsUnit(*itr))
+ continue;
+
+ if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell))
{
if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
me->InterruptNonMeleeSpells(false);
- if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell))
- me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED) ? true : false);
- else
- TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "Spell %u not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*itr)->GetGUID(), (*itr)->GetEntry(), uint32((*itr)->GetTypeId()));
+ me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED) ? true : false);
TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_CAST:: Creature %u casts spell %u on target %u with castflags %u",
me->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags);
}
+ else
+ TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "Spell %u not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*itr)->GetGUID(), (*itr)->GetEntry(), uint32((*itr)->GetTypeId()));
}
delete targets;
@@ -536,19 +539,20 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
- if (IsUnit(*itr))
- {
- if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
- tempLastInvoker->InterruptNonMeleeSpells(false);
+ if (!IsUnit(*itr))
+ continue;
if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell))
+ {
+ if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
+ tempLastInvoker->InterruptNonMeleeSpells(false);
+
tempLastInvoker->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED) ? true : false);
+ TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker %u casts spell %u on target %u with castflags %u",
+ tempLastInvoker->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags);
+ }
else
TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "Spell %u not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*itr)->GetGUID(), (*itr)->GetEntry(), uint32((*itr)->GetTypeId()));
-
- TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker %u casts spell %u on target %u with castflags %u",
- tempLastInvoker->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags);
- }
}
delete targets;
@@ -1350,7 +1354,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
if (e.GetTargetType() == SMART_TARGET_SELF)
- me->SetFacingTo(me->GetHomePosition().GetOrientation());
+ me->SetFacingTo((me->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && me->GetTransGUID() ?
+ me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation());
else if (e.GetTargetType() == SMART_TARGET_POSITION)
me->SetFacingTo(e.target.o);
else if (ObjectList* targets = GetTargets(e, unit))
@@ -1403,7 +1408,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
if (!target)
- me->GetMotionMaster()->MovePoint(e.action.MoveToPos.pointId, e.target.x, e.target.y, e.target.z);
+ {
+ G3D::Vector3 dest(e.target.x, e.target.y, e.target.z);
+ if (e.action.MoveToPos.transport)
+ if (TransportBase* trans = me->GetDirectTransport())
+ trans->CalculatePassengerPosition(dest.x, dest.y, dest.z);
+
+ me->GetMotionMaster()->MovePoint(e.action.MoveToPos.pointId, dest.x, dest.y, dest.z);
+ }
else
me->GetMotionMaster()->MovePoint(e.action.MoveToPos.pointId, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
break;
@@ -1659,21 +1671,28 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
for (ObjectList::const_iterator itr = casters->begin(); itr != casters->end(); ++itr)
{
- if (IsUnit(*itr))
+ if (!IsUnit(*itr))
+ continue;
+
+ bool interruptedSpell = false;
+
+ for (ObjectList::const_iterator it = targets->begin(); it != targets->end(); ++it)
{
- if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
- (*itr)->ToUnit()->InterruptNonMeleeSpells(false);
+ if (!IsUnit(*it))
+ continue;
- for (ObjectList::const_iterator it = targets->begin(); it != targets->end(); ++it)
+ if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*it)->ToUnit()->HasAura(e.action.cast.spell))
{
- if (IsUnit(*it))
+ if (!interruptedSpell && e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
{
- if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*it)->ToUnit()->HasAura(e.action.cast.spell))
- (*itr)->ToUnit()->CastSpell((*it)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED) ? true : false);
- else
- TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "Spell %u not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*it)->GetGUID(), (*it)->GetEntry(), uint32((*it)->GetTypeId()));
+ (*itr)->ToUnit()->InterruptNonMeleeSpells(false);
+ interruptedSpell = true;
}
+
+ (*itr)->ToUnit()->CastSpell((*it)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED) ? true : false);
}
+ else
+ TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "Spell %u not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*it)->GetGUID(), (*it)->GetEntry(), uint32((*it)->GetTypeId()));
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 56fa7ed1275..f12f2ab69c0 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -907,6 +907,7 @@ struct SmartAction
struct
{
uint32 pointId;
+ uint32 transport;
} MoveToPos;
struct
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index 6d79c6c77a1..1cff80ba10d 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -466,7 +466,7 @@ void AccountMgr::LoadRBAC()
secId = newId;
permissions = &_defaultPermissions[secId];
}
-
+
permissions->insert(field[1].GetUInt32());
++count3;
}
diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp
index 8cd70721976..f7c9444cdb0 100644
--- a/src/server/game/Accounts/RBAC.cpp
+++ b/src/server/game/Accounts/RBAC.cpp
@@ -231,13 +231,13 @@ void RBACData::ExpandPermissions(RBACPermissionContainer& permissions)
{
RBACPermissionContainer toCheck = permissions;
permissions.clear();
-
+
while (!toCheck.empty())
{
// remove the permission from original list
uint32 permissionId = *toCheck.begin();
toCheck.erase(toCheck.begin());
-
+
RBACPermission const* permission = sAccountMgr->GetRBACPermission(permissionId);
if (!permission)
continue;
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index e12e6835cb8..bcc4122ea5b 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -303,7 +303,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_GOBJECT_SET_STATE = 397,
RBAC_PERM_COMMAND_GOBJECT_TARGET = 398,
RBAC_PERM_COMMAND_GOBJECT_TURN = 399,
- // 400 - reuse
+ RBAC_PERM_COMMAND_DEBUG_TRANSPORT = 400,
RBAC_PERM_COMMAND_GUILD = 401,
RBAC_PERM_COMMAND_GUILD_CREATE = 402,
RBAC_PERM_COMMAND_GUILD_DELETE = 403,
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
index 29d4e4124c0..82d7de0d9bf 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
@@ -58,8 +58,17 @@ BattlegroundIC::BattlegroundIC()
BattlegroundIC::~BattlegroundIC()
{
- delete gunshipHorde;
- delete gunshipAlliance;
+ if (gunshipHorde)
+ {
+ gunshipHorde->RemoveFromWorld();
+ delete gunshipHorde;
+ }
+
+ if (gunshipAlliance)
+ {
+ gunshipAlliance->RemoveFromWorld();
+ delete gunshipAlliance;
+ }
}
void BattlegroundIC::HandlePlayerResurrect(Player* player)
@@ -71,22 +80,6 @@ void BattlegroundIC::HandlePlayerResurrect(Player* player)
player->CastSpell(player, SPELL_OIL_REFINERY, true);
}
-void BattlegroundIC::SendTransportInit(Player* player)
-{
- if (!gunshipAlliance || !gunshipHorde)
- return;
-
- UpdateData transData;
-
- gunshipAlliance->BuildCreateUpdateBlockForPlayer(&transData, player);
- gunshipHorde->BuildCreateUpdateBlockForPlayer(&transData, player);
-
- WorldPacket packet;
-
- transData.BuildPacket(&packet);
- player->SendDirectMessage(&packet);
-}
-
void BattlegroundIC::DoAction(uint32 action, uint64 var)
{
if (action != ACTION_TELEPORT_PLAYER_TO_TRANSPORT)
@@ -300,8 +293,6 @@ void BattlegroundIC::AddPlayer(Player* player)
if (nodePoint[NODE_TYPE_REFINERY].nodeState == (player->GetTeamId() == TEAM_ALLIANCE ? NODE_STATE_CONTROLLED_A : NODE_STATE_CONTROLLED_H))
player->CastSpell(player, SPELL_OIL_REFINERY, true);
-
- SendTransportInit(player);
}
void BattlegroundIC::RemovePlayer(Player* player, uint64 /*guid*/, uint32 /*team*/)
@@ -409,8 +400,8 @@ bool BattlegroundIC::SetupBattleground()
return false;
}
- gunshipHorde = CreateTransport(GO_HORDE_GUNSHIP, TRANSPORT_PERIOD_TIME);
- gunshipAlliance = CreateTransport(GO_ALLIANCE_GUNSHIP, TRANSPORT_PERIOD_TIME);
+ gunshipHorde = sTransportMgr->CreateTransport(GO_HORDE_GUNSHIP, 0, GetBgMap());
+ gunshipAlliance = sTransportMgr->CreateTransport(GO_ALLIANCE_GUNSHIP, 0, GetBgMap());
if (!gunshipAlliance || !gunshipHorde)
{
@@ -420,10 +411,8 @@ bool BattlegroundIC::SetupBattleground()
//Send transport init packet to all player in map
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- {
if (Player* player = ObjectAccessor::FindPlayer(itr->first))
- SendTransportInit(player);
- }
+ GetBgMap()->SendInitTransports(player);
// setting correct factions for Keep Cannons
for (uint8 i = BG_IC_NPC_KEEP_CANNON_1; i < BG_IC_NPC_KEEP_CANNON_12; ++i)
@@ -616,8 +605,8 @@ void BattlegroundIC::HandleContestedNodes(ICNodePoint* nodePoint)
{
if (nodePoint->nodeType == NODE_TYPE_HANGAR)
{
- if (gunshipAlliance && gunshipHorde)
- (nodePoint->faction == TEAM_ALLIANCE ? gunshipHorde : gunshipAlliance)->BuildStopMovePacket(GetBgMap());
+ if (gunshipAlliance && gunshipHorde)
+ (nodePoint->faction == TEAM_ALLIANCE ? gunshipHorde : gunshipAlliance)->EnableMovement(false);
for (uint8 u = BG_IC_GO_HANGAR_TELEPORTER_1; u < BG_IC_GO_HANGAR_TELEPORTER_3; ++u)
DelObject(u);
@@ -656,8 +645,8 @@ void BattlegroundIC::HandleCapturedNodes(ICNodePoint* nodePoint, bool recapture)
//TC_LOG_ERROR(LOG_FILTER_BATTLEGROUND, "BG_IC_GO_HANGAR_BANNER CAPTURED Faction: %u", nodePoint->faction);
- (nodePoint->faction == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->BuildStartMovePacket(GetBgMap());
- (nodePoint->faction == TEAM_ALLIANCE ? gunshipHorde : gunshipAlliance)->BuildStopMovePacket(GetBgMap());
+ (nodePoint->faction == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->EnableMovement(true);
+ (nodePoint->faction == TEAM_ALLIANCE ? gunshipHorde : gunshipAlliance)->EnableMovement(false);
// we should spawn teleporters
break;
case BG_IC_GO_QUARRY_BANNER:
@@ -865,7 +854,6 @@ void BattlegroundIC::DestroyGate(Player* player, GameObject* go)
void BattlegroundIC::EventPlayerDamagedGO(Player* /*player*/, GameObject* /*go*/, uint32 /*eventType*/)
{
-
}
WorldSafeLocsEntry const* BattlegroundIC::GetClosestGraveYard(Player* player)
@@ -907,52 +895,6 @@ WorldSafeLocsEntry const* BattlegroundIC::GetClosestGraveYard(Player* player)
return good_entry;
}
-Transport* BattlegroundIC::CreateTransport(uint32 goEntry, uint32 period)
-{
- Transport* t = new Transport(period, 0);
-
- GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(goEntry);
-
- if (!goinfo)
- {
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport ID: %u will not be loaded, gameobject_template missing", goEntry);
- delete t;
- return NULL;
- }
-
- std::set<uint32> mapsUsed;
-
- if (!t->GenerateWaypoints(goinfo->moTransport.taxiPathId, mapsUsed))
- // skip transports with empty waypoints list
- {
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport (path id %u) path size = 0. Transport ignored, check DBC files or transport GO data0 field.", goinfo->moTransport.taxiPathId);
- delete t;
- return NULL;
- }
-
- uint32 mapid = t->m_WayPoints[0].mapid;
-
- float x = t->m_WayPoints[0].x;
- float y = t->m_WayPoints[0].y;
- float z = t->m_WayPoints[0].z;
- float o = 1;
-
- // creates the Gameobject
- if (!t->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_MO_TRANSPORT), goEntry, mapid, x, y, z, o, 255, 0))
- {
- delete t;
- return NULL;
- }
-
- //If we someday decide to use the grid to track transports, here:
- t->SetMap(GetBgMap());
-
- for (uint8 i = 0; i < 5; ++i)
- t->AddNPCPassenger(0, (goEntry == GO_HORDE_GUNSHIP ? NPC_HORDE_GUNSHIP_CANNON : NPC_ALLIANCE_GUNSHIP_CANNON), (goEntry == GO_HORDE_GUNSHIP ? hordeGunshipPassengers[i].GetPositionX() : allianceGunshipPassengers[i].GetPositionX()), (goEntry == GO_HORDE_GUNSHIP ? hordeGunshipPassengers[i].GetPositionY() : allianceGunshipPassengers[i].GetPositionY()), (goEntry == GO_HORDE_GUNSHIP ? hordeGunshipPassengers[i].GetPositionZ() : allianceGunshipPassengers[i].GetPositionZ()), (goEntry == GO_HORDE_GUNSHIP ? hordeGunshipPassengers[i].GetOrientation() : allianceGunshipPassengers[i].GetOrientation()));
-
- return t;
-}
-
bool BattlegroundIC::IsAllNodesControlledByTeam(uint32 team) const
{
uint32 count = 0;
@@ -983,4 +925,4 @@ bool BattlegroundIC::IsSpellAllowed(uint32 spellId, Player const* player) const
}
return true;
-} \ No newline at end of file
+}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h
index 6fdc97f25c5..acb5046444c 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h
@@ -956,8 +956,6 @@ class BattlegroundIC : public Battleground
void UpdateNodeWorldState(ICNodePoint* nodePoint);
void HandleCapturedNodes(ICNodePoint* nodePoint, bool recapture);
void HandleContestedNodes(ICNodePoint* nodePoint);
- Transport* CreateTransport(uint32 goEntry, uint32 period);
- void SendTransportInit(Player* player);
};
#endif
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index aaa630ce4b8..6d806336315 100644
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -344,7 +344,7 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, st
Player* player = m_session->GetPlayer();
if (!AccountMgr::IsPlayerAccount(m_session->GetSecurity()))
{
- uint64 guid = player->GetSelection();
+ uint64 guid = player->GetTarget();
uint32 areaId = player->GetAreaId();
std::string areaName = "Unknown";
std::string zoneName = "Unknown";
@@ -713,12 +713,11 @@ Player* ChatHandler::getSelectedPlayer()
if (!m_session)
return NULL;
- uint64 guid = m_session->GetPlayer()->GetSelection();
-
- if (guid == 0)
+ uint64 selected = m_session->GetPlayer()->GetTarget();
+ if (!selected)
return m_session->GetPlayer();
- return ObjectAccessor::FindPlayer(guid);
+ return ObjectAccessor::FindPlayer(selected);
}
Unit* ChatHandler::getSelectedUnit()
@@ -726,12 +725,10 @@ Unit* ChatHandler::getSelectedUnit()
if (!m_session)
return NULL;
- uint64 guid = m_session->GetPlayer()->GetSelection();
-
- if (guid == 0)
- return m_session->GetPlayer();
+ if (Unit* selected = m_session->GetPlayer()->GetSelectedUnit())
+ return selected;
- return ObjectAccessor::GetUnit(*m_session->GetPlayer(), guid);
+ return m_session->GetPlayer();
}
WorldObject* ChatHandler::getSelectedObject()
@@ -739,7 +736,7 @@ WorldObject* ChatHandler::getSelectedObject()
if (!m_session)
return NULL;
- uint64 guid = m_session->GetPlayer()->GetSelection();
+ uint64 guid = m_session->GetPlayer()->GetTarget();
if (guid == 0)
return GetNearbyGameObject();
@@ -752,7 +749,7 @@ Creature* ChatHandler::getSelectedCreature()
if (!m_session)
return NULL;
- return ObjectAccessor::GetCreatureOrPetOrVehicle(*m_session->GetPlayer(), m_session->GetPlayer()->GetSelection());
+ return ObjectAccessor::GetCreatureOrPetOrVehicle(*m_session->GetPlayer(), m_session->GetPlayer()->GetTarget());
}
char* ChatHandler::extractKeyFromLink(char* text, char const* linkType, char** something1)
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 71fbf1c62b2..95592cd87d9 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -20,6 +20,7 @@
#include "Log.h"
#include "SharedDefines.h"
#include "SpellMgr.h"
+#include "TransportMgr.h"
#include "DBCfmt.h"
#include "Timer.h"
#include "ObjectDefines.h"
@@ -190,6 +191,8 @@ static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
DBCStorage <TeamContributionPointsEntry> sTeamContributionPointsStore(TeamContributionPointsfmt);
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
+DBCStorage <TransportAnimationEntry> sTransportAnimationStore(TransportAnimationfmt);
+DBCStorage <TransportRotationEntry> sTransportRotationStore(TransportRotationfmt);
DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt);
DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt);
DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore(WMOAreaTableEntryfmt);
@@ -604,6 +607,25 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sTeamContributionPointsStore, dbcPath, "TeamContributionPoints.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sTotemCategoryStore, dbcPath, "TotemCategory.dbc");
+ LoadDBC(availableDbcLocales, bad_dbc_files, sTransportAnimationStore, dbcPath, "TransportAnimation.dbc");
+ for (uint32 i = 0; i < sTransportAnimationStore.GetNumRows(); ++i)
+ {
+ TransportAnimationEntry const* anim = sTransportAnimationStore.LookupEntry(i);
+ if (!anim)
+ continue;
+
+ sTransportMgr->AddPathNodeToTransport(anim->TransportEntry, anim->TimeSeg, anim);
+ }
+
+ LoadDBC(availableDbcLocales, bad_dbc_files, sTransportRotationStore, dbcPath, "TransportRotation.dbc");
+ for (uint32 i = 0; i < sTransportRotationStore.GetNumRows(); ++i)
+ {
+ TransportRotationEntry const* rot = sTransportRotationStore.LookupEntry(i);
+ if (!rot)
+ continue;
+
+ sTransportMgr->AddPathRotationToTransport(rot->TransportEntry, rot->TimeSeg, rot);
+ }
LoadDBC(availableDbcLocales, bad_dbc_files, sVehicleStore, dbcPath, "Vehicle.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sVehicleSeatStore, dbcPath, "VehicleSeat.dbc");
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index e12f70baa41..aff54f75a40 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1875,6 +1875,28 @@ struct TotemCategoryEntry
uint32 categoryMask; // 19 (compatibility mask for same type: different for totems, compatible from high to low for rods)
};
+struct TransportAnimationEntry
+{
+ //uint32 Id;
+ uint32 TransportEntry;
+ uint32 TimeSeg;
+ float X;
+ float Y;
+ float Z;
+ //uint32 MovementId;
+};
+
+struct TransportRotationEntry
+{
+ //uint32 Id;
+ uint32 TransportEntry;
+ uint32 TimeSeg;
+ float X;
+ float Y;
+ float Z;
+ float W;
+};
+
#define MAX_VEHICLE_SEATS 8
struct VehicleEntry
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index a81eec51338..5326ab70fa3 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -120,6 +120,8 @@ char const TaxiPathEntryfmt[] = "niii";
char const TaxiPathNodeEntryfmt[] = "diiifffiiii";
char const TeamContributionPointsfmt[] = "df";
char const TotemCategoryEntryfmt[] = "nxxxxxxxxxxxxxxxxxii";
+char const TransportAnimationfmt[] = "diifffx";
+char const TransportRotationfmt[] = "diiffff";
char const VehicleEntryfmt[] = "niffffiiiiiiiifffffffffffffffssssfifiixx";
char const VehicleSeatEntryfmt[] = "niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx";
char const WMOAreaTableEntryfmt[] = "niiixxxxxiixxxxxxxxxxxxxxxxx";
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 06f88f0f37f..f68d87de2f4 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -52,7 +52,7 @@
#include "World.h"
#include "WorldPacket.h"
-// apply implementation of the singletons
+#include "Transport.h"
TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
{
@@ -141,7 +141,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
return true;
}
-Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapCreature(),
+Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0),
m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0),
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
@@ -165,6 +165,7 @@ m_creatureInfo(NULL), m_creatureData(NULL), m_path_id(0), m_formation(NULL)
ResetLootMode(); // restore default loot mode
TriggerJustRespawned = false;
m_isTempWorldObject = false;
+ _focusSpell = NULL;
}
Creature::~Creature()
@@ -933,7 +934,8 @@ void Creature::SaveToDB()
return;
}
- SaveToDB(GetMapId(), data->spawnMask, GetPhaseMask());
+ uint32 mapId = GetTransport() ? GetTransport()->GetGOInfo()->moTransport.mapID : GetMapId();
+ SaveToDB(mapId, data->spawnMask, GetPhaseMask());
}
void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
@@ -972,10 +974,21 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
data.phaseMask = phaseMask;
data.displayid = displayId;
data.equipmentId = GetCurrentEquipmentId();
- data.posX = GetPositionX();
- data.posY = GetPositionY();
- data.posZ = GetPositionZMinusOffset();
- data.orientation = GetOrientation();
+ if (!GetTransport())
+ {
+ data.posX = GetPositionX();
+ data.posY = GetPositionY();
+ data.posZ = GetPositionZMinusOffset();
+ data.orientation = GetOrientation();
+ }
+ else
+ {
+ data.posX = GetTransOffsetX();
+ data.posY = GetTransOffsetY();
+ data.posZ = GetTransOffsetZ();
+ data.orientation = GetTransOffsetO();
+ }
+
data.spawntimesecs = m_respawnDelay;
// prevent add data integrity problems
data.spawndist = GetDefaultMovementType() == IDLE_MOTION_TYPE ? 0.0f : m_respawnradius;
@@ -2640,3 +2653,41 @@ void Creature::SetDisplayId(uint32 modelId)
SetFloatValue(UNIT_FIELD_COMBATREACH, minfo->combat_reach * GetObjectScale());
}
}
+
+void Creature::SetTarget(uint64 guid)
+{
+ if (!_focusSpell)
+ SetUInt64Value(UNIT_FIELD_TARGET, guid);
+}
+
+void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target)
+{
+ // already focused
+ if (_focusSpell)
+ return;
+
+ _focusSpell = focusSpell;
+ SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID());
+ if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
+ AddUnitState(UNIT_STATE_ROTATING);
+
+ // Set serverside orientation if needed (needs to be after attribute check)
+ SetInFront(target);
+}
+
+void Creature::ReleaseFocus(Spell const* focusSpell)
+{
+ // focused to something else
+ if (focusSpell != _focusSpell)
+ return;
+
+ _focusSpell = NULL;
+ if (Unit* victim = GetVictim())
+ SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
+ else
+ SetUInt64Value(UNIT_FIELD_TARGET, 0);
+
+ if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
+ ClearUnitState(UNIT_STATE_ROTATING);
+}
+
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index bb9cc40ace1..a555469da63 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -415,36 +415,7 @@ typedef std::map<uint32, time_t> CreatureSpellCooldowns;
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
-enum CreatureCellMoveState
-{
- CREATURE_CELL_MOVE_NONE, // not in move list
- CREATURE_CELL_MOVE_ACTIVE, // in move list
- CREATURE_CELL_MOVE_INACTIVE // in move list but should not move
-};
-
-class MapCreature
-{
- friend class Map; // map for moving creatures
- friend class ObjectGridLoader; // grid loader for loading creatures
-
-protected:
- MapCreature() : _moveState(CREATURE_CELL_MOVE_NONE) {}
-
-private:
- Cell _currentCell;
- Cell const& GetCurrentCell() const { return _currentCell; }
- void SetCurrentCell(Cell const& cell) { _currentCell = cell; }
-
- CreatureCellMoveState _moveState;
- Position _newPosition;
- void SetNewCellPosition(float x, float y, float z, float o)
- {
- _moveState = CREATURE_CELL_MOVE_ACTIVE;
- _newPosition.Relocate(x, y, z, o);
- }
-};
-
-class Creature : public Unit, public GridObject<Creature>, public MapCreature
+class Creature : public Unit, public GridObject<Creature>, public MapObject
{
public:
@@ -703,6 +674,11 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
bool m_isTempWorldObject; //true when possessed
+ // Handling caster facing during spellcast
+ void SetTarget(uint64 guid);
+ void FocusTarget(Spell const* focusSpell, WorldObject const* target);
+ void ReleaseFocus(Spell const* focusSpell);
+
protected:
bool CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint32 team, const CreatureData* data = NULL);
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
@@ -762,6 +738,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
//Formation var
CreatureGroup* m_formation;
bool TriggerJustRespawned;
+
+ Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
};
class AssistDelayEvent : public BasicEvent
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 15e7eb436e1..af92f0e9df4 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -16,6 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <G3D/Quat.h>
#include "GameObjectAI.h"
#include "Battleground.h"
#include "CellImpl.h"
@@ -32,8 +33,10 @@
#include "SpellMgr.h"
#include "UpdateFieldFlags.h"
#include "World.h"
+#include "Transport.h"
-GameObject::GameObject(): WorldObject(false), m_model(NULL), m_goValue(), m_AI(NULL)
+GameObject::GameObject() : WorldObject(false), MapObject(),
+ m_model(NULL), m_goValue(), m_AI(NULL)
{
m_objectType |= TYPEMASK_GAMEOBJECT;
m_objectTypeId = TYPEID_GAMEOBJECT;
@@ -100,6 +103,9 @@ void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
if (m_uint32Values) // field array can be not exist if GameOBject not loaded
RemoveFromOwner();
+
+ if (GetTransport() && !ToTransport())
+ GetTransport()->RemovePassenger(this);
}
void GameObject::RemoveFromOwner()
@@ -169,6 +175,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
SetMap(map);
Relocate(x, y, z, ang);
+ m_stationaryPosition.Relocate(x, y, z, ang);
if (!IsPositionValid())
{
TC_LOG_ERROR(LOG_FILTER_GENERAL, "Gameobject (GUID: %u Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, name_id, x, y);
@@ -192,6 +199,9 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
return false;
}
+ if (goinfo->type == GAMEOBJECT_TYPE_TRANSPORT)
+ m_updateFlag = (m_updateFlag | UPDATEFLAG_TRANSPORT) & ~UPDATEFLAG_POSITION;
+
Object::_Create(guidlow, goinfo->entry, HIGHGUID_GAMEOBJECT);
m_goInfo = goinfo;
@@ -238,9 +248,11 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
break;
case GAMEOBJECT_TYPE_TRANSPORT:
SetUInt32Value(GAMEOBJECT_LEVEL, goinfo->transport.pause);
- if (goinfo->transport.startOpen)
- SetGoState(GO_STATE_ACTIVE);
+ SetGoState(goinfo->transport.startOpen ? GO_STATE_ACTIVE : GO_STATE_READY);
SetGoAnimProgress(animprogress);
+ m_goValue.Transport.PathProgress = 0;
+ m_goValue.Transport.AnimationInfo = sTransportMgr->GetTransportAnimInfo(goinfo->entry);
+ m_goValue.Transport.CurrentSeg = 0;
break;
case GAMEOBJECT_TYPE_FISHINGNODE:
SetGoAnimProgress(0);
@@ -274,18 +286,10 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
void GameObject::Update(uint32 diff)
{
- if (!AI())
- {
- if (!AIM_Initialize())
- TC_LOG_ERROR(LOG_FILTER_GENERAL, "Could not initialize GameObjectAI");
- } else
+ if (AI())
AI()->UpdateAI(diff);
-
- if (IS_MO_TRANSPORT_GUID(GetGUID()))
- {
- //((Transport*)this)->Update(p_time);
- return;
- }
+ else if (!AIM_Initialize())
+ TC_LOG_ERROR(LOG_FILTER_GENERAL, "Could not initialize GameObjectAI");
switch (m_lootState)
{
@@ -308,6 +312,38 @@ void GameObject::Update(uint32 diff)
m_lootState = GO_READY;
break;
}
+ /* TODO: Fix movement in unloaded grid - currently GO will just disappear
+ case GAMEOBJECT_TYPE_TRANSPORT:
+ {
+ if (!m_goValue.Transport.AnimationInfo)
+ break;
+
+ if (GetGoState() == GO_STATE_READY)
+ {
+ m_goValue.Transport.PathProgress += diff;
+ uint32 timer = m_goValue.Transport.PathProgress % m_goValue.Transport.AnimationInfo->TotalTime;
+ TransportAnimationEntry const* node = m_goValue.Transport.AnimationInfo->GetAnimNode(timer);
+ if (node && m_goValue.Transport.CurrentSeg != node->TimeSeg)
+ {
+ m_goValue.Transport.CurrentSeg = node->TimeSeg;
+
+ G3D::Quat rotation = m_goValue.Transport.AnimationInfo->GetAnimRotation(timer);
+ G3D::Vector3 pos = rotation.toRotationMatrix()
+ * G3D::Matrix3::fromEulerAnglesZYX(GetOrientation(), 0.0f, 0.0f)
+ * G3D::Vector3(node->X, node->Y, node->Z);
+
+ pos += G3D::Vector3(GetStationaryX(), GetStationaryY(), GetStationaryZ());
+
+ G3D::Vector3 src(GetPositionX(), GetPositionY(), GetPositionZ());
+
+ sLog->outInfo(LOG_FILTER_GENERAL, "Src: %s Dest: %s", src.toString().c_str(), pos.toString().c_str());
+
+ GetMap()->GameObjectRelocation(this, pos.x, pos.y, pos.z, GetOrientation());
+ }
+ }
+ break;
+ }
+ */
case GAMEOBJECT_TYPE_FISHINGNODE:
{
// fishing code (bobber ready)
@@ -1182,10 +1218,12 @@ void GameObject::Use(Unit* user)
if (itr->second)
{
if (Player* ChairUser = ObjectAccessor::FindPlayer(itr->second))
+ {
if (ChairUser->IsSitState() && ChairUser->getStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f)
continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->getStandState() != UNIT_STAND_STATE_SIT check is required.
else
itr->second = 0; // This seat is unoccupied.
+ }
else
itr->second = 0; // The seat may of had an occupant, but they're offline.
}
@@ -1508,7 +1546,7 @@ void GameObject::Use(Unit* user)
Player* player = user->ToPlayer();
- Player* targetPlayer = ObjectAccessor::FindPlayer(player->GetSelection());
+ Player* targetPlayer = ObjectAccessor::FindPlayer(player->GetTarget());
// accept only use by player from same raid as caster, except caster itself
if (!targetPlayer || targetPlayer == player || !targetPlayer->IsInSameRaidWith(player))
@@ -2102,6 +2140,7 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
if (index == GAMEOBJECT_DYNAMIC)
{
uint16 dynFlags = 0;
+ int16 pathProgress = -1;
switch (GetGoType())
{
case GAMEOBJECT_TYPE_CHEST:
@@ -2115,12 +2154,15 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
if (ActivateToQuest(target))
dynFlags |= GO_DYNFLAG_LO_SPARKLE;
break;
+ case GAMEOBJECT_TYPE_MO_TRANSPORT:
+ pathProgress = int16(float(m_goValue.Transport.PathProgress) / float(GetUInt32Value(GAMEOBJECT_LEVEL)) * 65535.0f);
+ break;
default:
break;
}
fieldBuffer << uint16(dynFlags);
- fieldBuffer << uint16(-1);
+ fieldBuffer << int16(pathProgress);
}
else if (index == GAMEOBJECT_FLAGS)
{
@@ -2140,3 +2182,25 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
updateMask.AppendToPacket(data);
data->append(fieldBuffer);
}
+
+void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = NULL*/) const
+{
+ if (m_DBTableGuid)
+ {
+ if (GameObjectData const* data = sObjectMgr->GetGOData(GetDBTableGUIDLow()))
+ {
+ x = data->posX;
+ y = data->posY;
+ z = data->posZ;
+ if (ori)
+ *ori = data->orientation;
+ return;
+ }
+ }
+
+ x = GetPositionX();
+ y = GetPositionY();
+ z = GetPositionZ();
+ if (ori)
+ *ori = GetOrientation();
+}
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 3bddac81ee9..de92257893b 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -28,6 +28,7 @@
class GameObjectAI;
class Group;
+class Transport;
#define MAX_GAMEOBJECT_QUEST_ITEMS 6
@@ -229,6 +230,7 @@ struct GameObjectTemplate
uint32 transportPhysics; //5
uint32 mapID; //6
uint32 worldState1; //7
+ uint32 canBeStopped; //8
} moTransport;
//16 GAMEOBJECT_TYPE_DUELFLAG - empty
//17 GAMEOBJECT_TYPE_FISHINGNODE - empty
@@ -539,9 +541,17 @@ struct GameObjectTemplate
typedef UNORDERED_MAP<uint32, GameObjectTemplate> GameObjectTemplateContainer;
class OPvPCapturePoint;
+struct TransportAnimation;
union GameObjectValue
{
+ //11 GAMEOBJECT_TYPE_TRANSPORT
+ struct
+ {
+ uint32 PathProgress;
+ TransportAnimation const* AnimationInfo;
+ uint32 CurrentSeg;
+ } Transport;
//25 GAMEOBJECT_TYPE_FISHINGHOLE
struct
{
@@ -617,7 +627,7 @@ class GameObjectModel;
// 5 sec for bobber catch
#define FISHING_BOBBER_READY_TIME 5
-class GameObject : public WorldObject, public GridObject<GameObject>
+class GameObject : public WorldObject, public GridObject<GameObject>, public MapObject
{
public:
explicit GameObject();
@@ -811,8 +821,19 @@ class GameObject : public WorldObject, public GridObject<GameObject>
uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
GameObjectModel* m_model;
+ void GetRespawnPosition(float &x, float &y, float &z, float* ori = NULL) const;
+
+ Transport* ToTransport() { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<Transport*>(this); else return NULL; }
+ Transport const* ToTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<Transport const*>(this); else return NULL; }
+
+ float GetStationaryX() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionX(); return GetPositionX(); }
+ float GetStationaryY() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionY(); return GetPositionY(); }
+ float GetStationaryZ() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); }
+ float GetStationaryO() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); }
+
protected:
bool AIM_Initialize();
+ void UpdateModel(); // updates model in case displayId were changed
uint32 m_spellId;
time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),
uint32 m_respawnDelayTime; // (secs) if 0 then current GO state no dependent from timer
@@ -835,6 +856,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>
GameObjectValue m_goValue;
uint64 m_rotation;
+ Position m_stationaryPosition;
uint64 m_lootRecipient;
uint32 m_lootRecipientGroup;
@@ -842,7 +864,6 @@ class GameObject : public WorldObject, public GridObject<GameObject>
private:
void RemoveFromOwner();
void SwitchDoorOrButton(bool activate, bool alternative = false);
- void UpdateModel(); // updates model in case displayId were changed
//! Object distance/size - overridden from Object::_IsWithinDist. Needs to take in account proper GO size.
bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool /*is3D*/) const
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 9d77e144c0b..1471e966045 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -219,9 +219,6 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
case GAMEOBJECT_TYPE_FLAGDROP:
updateType = UPDATETYPE_CREATE_OBJECT2;
break;
- case GAMEOBJECT_TYPE_TRANSPORT:
- flags |= UPDATEFLAG_TRANSPORT;
- break;
default:
break;
}
@@ -414,13 +411,10 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
// 0x40
if (flags & UPDATEFLAG_STATIONARY_POSITION)
{
- *data << object->GetPositionX();
- *data << object->GetPositionY();
- if (isType(TYPEMASK_UNIT))
- *data << unit->GetPositionZMinusOffset();
- else
- *data << object->GetPositionZ();
- *data << object->GetOrientation();
+ *data << object->GetStationaryX();
+ *data << object->GetStationaryY();
+ *data << object->GetStationaryZ();
+ *data << object->GetStationaryO();
}
}
}
@@ -473,7 +467,11 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
// 0x2
if (flags & UPDATEFLAG_TRANSPORT)
{
- *data << uint32(getMSTime()); // Unknown - getMSTime is wrong.
+ GameObject const* go = ToGameObject();
+ if (go && go->IsTransport())
+ *data << uint32(go->GetGOValue()->Transport.PathProgress);
+ else
+ *data << uint32(getMSTime());
}
// 0x80
@@ -2675,7 +2673,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle)
// Prevent invalid coordinates here, position is unchanged
if (!Trinity::IsValidMapCoord(destx, desty, pos.m_positionZ))
{
- TC_LOG_FATAL(LOG_FILTER_GENERAL, "WorldObject::MovePosition invalid coordinates X: %f and Y: %f were passed!", destx, desty);
+ TC_LOG_FATAL(LOG_FILTER_GENERAL, "WorldObject::MovePosition: Object (TypeId: %u Entry: %u GUID: %u) has invalid coordinates X: %f and Y: %f were passed!",
+ GetTypeId(), GetEntry(), GetGUIDLow(), destx, desty);
return;
}
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 66b3a737e0c..3e010fa98a2 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -523,6 +523,35 @@ class FlaggedValuesArray32
T_FLAGS m_flags;
};
+enum MapObjectCellMoveState
+{
+ MAP_OBJECT_CELL_MOVE_NONE, //not in move list
+ MAP_OBJECT_CELL_MOVE_ACTIVE, //in move list
+ MAP_OBJECT_CELL_MOVE_INACTIVE, //in move list but should not move
+};
+
+class MapObject
+{
+ friend class Map; //map for moving creatures
+ friend class ObjectGridLoader; //grid loader for loading creatures
+
+ protected:
+ MapObject() : _moveState(MAP_OBJECT_CELL_MOVE_NONE) {}
+
+ private:
+ Cell _currentCell;
+ Cell const& GetCurrentCell() const { return _currentCell; }
+ void SetCurrentCell(Cell const& cell) { _currentCell = cell; }
+
+ MapObjectCellMoveState _moveState;
+ Position _newPosition;
+ void SetNewCellPosition(float x, float y, float z, float o)
+ {
+ _moveState = MAP_OBJECT_CELL_MOVE_ACTIVE;
+ _newPosition.Relocate(x, y, z, o);
+ }
+};
+
class WorldObject : public Object, public WorldLocation
{
protected:
@@ -700,16 +729,22 @@ class WorldObject : public Object, public WorldLocation
// Transports
Transport* GetTransport() const { return m_transport; }
- virtual float GetTransOffsetX() const { return 0; }
- virtual float GetTransOffsetY() const { return 0; }
- virtual float GetTransOffsetZ() const { return 0; }
- virtual float GetTransOffsetO() const { return 0; }
- virtual uint32 GetTransTime() const { return 0; }
- virtual int8 GetTransSeat() const { return -1; }
+ float GetTransOffsetX() const { return m_movementInfo.transport.pos.GetPositionX(); }
+ float GetTransOffsetY() const { return m_movementInfo.transport.pos.GetPositionY(); }
+ float GetTransOffsetZ() const { return m_movementInfo.transport.pos.GetPositionZ(); }
+ float GetTransOffsetO() const { return m_movementInfo.transport.pos.GetOrientation(); }
+ uint32 GetTransTime() const { return m_movementInfo.transport.time; }
+ int8 GetTransSeat() const { return m_movementInfo.transport.seat; }
virtual uint64 GetTransGUID() const;
void SetTransport(Transport* t) { m_transport = t; }
MovementInfo m_movementInfo;
+
+ virtual float GetStationaryX() const { return GetPositionX(); }
+ virtual float GetStationaryY() const { return GetPositionY(); }
+ virtual float GetStationaryZ() const { return GetPositionZ(); }
+ virtual float GetStationaryO() const { return GetOrientation(); }
+
protected:
std::string m_name;
bool m_isActive;
@@ -739,7 +774,6 @@ class WorldObject : public Object, public WorldLocation
uint16 m_notifyflags;
uint16 m_executed_notifies;
-
virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const;
bool CanNeverSee(WorldObject const* obj) const;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 09ae919618a..40dbe6c2fe7 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -673,7 +673,6 @@ Player::Player(WorldSession* session): Unit(true)
if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS))
SetAcceptWhispers(true);
- m_curSelection = 0;
m_lootGuid = 0;
m_comboTarget = 0;
@@ -17183,17 +17182,15 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
}
else
{
- for (MapManager::TransportSet::iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter)
+ if (GameObject* go = HashMapHolder<GameObject>::Find(m_movementInfo.transport.guid))
+ m_transport = go->ToTransport();
+
+ if (m_transport)
{
- if ((*iter)->GetGUIDLow() == transGUID)
- {
- m_transport = *iter;
- m_transport->AddPassenger(this);
- mapId = (m_transport->GetMapId());
- break;
- }
+ m_transport->AddPassenger(this);
+ mapId = m_transport->GetMapId();
}
- if (!m_transport)
+ else
{
TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player (guidlow %d) have problems with transport guid (%u). Teleport to bind location.",
guid, transGUID);
@@ -22166,7 +22163,7 @@ inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, T* target, std::set
template<>
inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, GameObject* target, std::set<Unit*>& /*v*/)
{
- // Don't update only GAMEOBJECT_TYPE_TRANSPORT (or all transports and destructible buildings?)
+ // @HACK: This is to prevent objects like deeprun tram from disappearing when player moves far from its spawn point while riding it
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
s64.insert(target->GetGUID());
}
@@ -22218,9 +22215,6 @@ void Player::UpdateVisibilityOf(WorldObject* target)
{
if (CanSeeOrDetect(target, false, true))
{
- //if (target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle)
- // UpdateVisibilityOf(((Unit*)target)->m_Vehicle);
-
target->SendUpdateToPlayer(this);
m_clientGUIDs.insert(target->GetGUID());
@@ -22309,9 +22303,6 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& vi
{
if (CanSeeOrDetect(target, false, true))
{
- //if (target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle)
- // UpdateVisibilityOf(((Unit*)target)->m_Vehicle, data, visibleNow);
-
target->BuildCreateUpdateBlockForPlayer(&data, this);
UpdateVisibilityOf_helper(m_clientGUIDs, target, visibleNow);
@@ -22397,15 +22388,15 @@ bool Player::IsQuestRewarded(uint32 quest_id) const
Unit* Player::GetSelectedUnit() const
{
- if (m_curSelection)
- return ObjectAccessor::GetUnit(*this, m_curSelection);
+ if (uint64 selectionGUID = GetUInt64Value(UNIT_FIELD_TARGET))
+ return ObjectAccessor::GetUnit(*this, selectionGUID);
return NULL;
}
Player* Player::GetSelectedPlayer() const
{
- if (m_curSelection)
- return ObjectAccessor::GetPlayer(*this, m_curSelection);
+ if (uint64 selectionGUID = GetUInt64Value(UNIT_FIELD_TARGET))
+ return ObjectAccessor::GetPlayer(*this, selectionGUID);
return NULL;
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index bac794422be..fee542a752e 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1506,10 +1506,11 @@ class Player : public Unit, public GridObject<Player>
size_t GetRewardedQuestCount() const { return m_RewardedQuests.size(); }
bool IsQuestRewarded(uint32 quest_id) const;
- uint64 GetSelection() const { return m_curSelection; }
Unit* GetSelectedUnit() const;
Player* GetSelectedPlayer() const;
- void SetSelection(uint64 guid) { m_curSelection = guid; SetUInt64Value(UNIT_FIELD_TARGET, guid); }
+
+ void SetTarget(uint64 /*guid*/) OVERRIDE { } /// Used for serverside target changes, does not apply to players
+ void SetSelection(uint64 guid) { SetUInt64Value(UNIT_FIELD_TARGET, guid); }
uint8 GetComboPoints() const { return m_comboPoints; }
uint64 GetComboTarget() const { return m_comboTarget; }
@@ -2424,7 +2425,6 @@ class Player : public Unit, public GridObject<Player>
bool m_itemUpdateQueueBlocked;
uint32 m_ExtraFlags;
- uint64 m_curSelection;
uint64 m_comboTarget;
int8 m_comboPoints;
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index 23197b40ad0..06af4244246 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -26,166 +26,26 @@
#include "DBCStores.h"
#include "World.h"
#include "GameObjectAI.h"
+#include "Vehicle.h"
+#include "MapReference.h"
#include "Player.h"
+#include "Cell.h"
+#include "CellImpl.h"
-void MapManager::LoadTransports()
+Transport::Transport() : GameObject(),
+ _transportInfo(NULL), _isMoving(true), _pendingStop(false)
{
- uint32 oldMSTime = getMSTime();
-
- QueryResult result = WorldDatabase.Query("SELECT guid, entry, name, period, ScriptName FROM transports");
-
- if (!result)
- {
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 transports. DB table `transports` is empty!");
- return;
- }
-
- uint32 count = 0;
-
- do
- {
-
- Field* fields = result->Fetch();
- uint32 lowguid = fields[0].GetUInt32();
- uint32 entry = fields[1].GetUInt32();
- std::string name = fields[2].GetString();
- uint32 period = fields[3].GetUInt32();
- uint32 scriptId = sObjectMgr->GetScriptId(fields[4].GetCString());
-
- GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
-
- if (!goinfo)
- {
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport ID:%u, Name: %s, will not be loaded, gameobject_template missing", entry, name.c_str());
- continue;
- }
-
- if (goinfo->type != GAMEOBJECT_TYPE_MO_TRANSPORT)
- {
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport ID:%u, Name: %s, will not be loaded, gameobject_template type wrong", entry, name.c_str());
- continue;
- }
-
- // TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, "Loading transport %d between %s, %s", entry, name.c_str(), goinfo->name);
-
- std::set<uint32> mapsUsed;
-
- Transport* t = new Transport(period, scriptId);
- if (!t->GenerateWaypoints(goinfo->moTransport.taxiPathId, mapsUsed))
- // skip transports with empty waypoints list
- {
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport (path id %u) path size = 0. Transport ignored, check DBC files or transport GO data0 field.", goinfo->moTransport.taxiPathId);
- delete t;
- continue;
- }
-
- float x = t->m_WayPoints[0].x;
- float y = t->m_WayPoints[0].y;
- float z = t->m_WayPoints[0].z;
- uint32 mapid = t->m_WayPoints[0].mapid;
- float o = 1.0f;
-
- // creates the Gameobject
- if (!t->Create(lowguid, entry, mapid, x, y, z, o, 255, 0))
- {
- delete t;
- continue;
- }
-
- m_Transports.insert(t);
-
- for (std::set<uint32>::const_iterator i = mapsUsed.begin(); i != mapsUsed.end(); ++i)
- m_TransportsByMap[*i].insert(t);
-
- //If we someday decide to use the grid to track transports, here:
- t->SetMap(sMapMgr->CreateBaseMap(mapid));
- t->AddToWorld();
-
- ++count;
- }
- while (result->NextRow());
-
- // check transport data DB integrity
- result = WorldDatabase.Query("SELECT gameobject.guid, gameobject.id, transports.name FROM gameobject, transports WHERE gameobject.id = transports.entry");
- if (result) // wrong data found
- {
- do
- {
- Field* fields = result->Fetch();
-
- uint32 guid = fields[0].GetUInt32();
- uint32 entry = fields[1].GetUInt32();
- std::string name = fields[2].GetString();
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport %u '%s' have record (GUID: %u) in `gameobject`. Transports must not have any records in `gameobject` or its behavior will be unpredictable/bugged.", entry, name.c_str(), guid);
- }
- while (result->NextRow());
- }
-
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded %u transports in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-}
-
-void MapManager::LoadTransportNPCs()
-{
- uint32 oldMSTime = getMSTime();
-
- // 0 1 2 3 4 5 6 7
- QueryResult result = WorldDatabase.Query("SELECT guid, npc_entry, transport_entry, TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO, emote FROM creature_transport");
-
- if (!result)
- {
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 transport NPCs. DB table `creature_transport` is empty!");
- return;
- }
-
- uint32 count = 0;
-
- do
- {
- Field* fields = result->Fetch();
- uint32 guid = fields[0].GetInt32();
- uint32 entry = fields[1].GetInt32();
- uint32 transportEntry = fields[2].GetInt32();
- float tX = fields[3].GetFloat();
- float tY = fields[4].GetFloat();
- float tZ = fields[5].GetFloat();
- float tO = fields[6].GetFloat();
- uint32 anim = fields[7].GetInt32();
-
- for (MapManager::TransportSet::iterator itr = m_Transports.begin(); itr != m_Transports.end(); ++itr)
- {
- if ((*itr)->GetEntry() == transportEntry)
- {
- (*itr)->AddNPCPassenger(guid, entry, tX, tY, tZ, tO, anim);
- break;
- }
- }
-
- ++count;
- }
- while (result->NextRow());
-
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded %u transport npcs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-}
-
-Transport::Transport(uint32 period, uint32 script) : GameObject(), m_pathTime(0), m_timer(0),
-currenttguid(0), m_period(period), ScriptId(script), m_nextNodeTime(0)
-{
- m_updateFlag = (UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION);
+ m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
}
Transport::~Transport()
{
- for (CreatureSet::iterator itr = m_NPCPassengerSet.begin(); itr != m_NPCPassengerSet.end(); ++itr)
- {
- (*itr)->SetTransport(NULL);
- GetMap()->AddObjectToRemoveList(*itr);
- }
+ UnloadStaticPassengers();
}
-bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags)
+bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress)
{
Relocate(x, y, z, ang);
- // instance id and phaseMask isn't set to values different from std.
if (!IsPositionValid())
{
@@ -206,520 +66,516 @@ bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, floa
m_goInfo = goinfo;
- SetObjectScale(goinfo->size);
+ TransportTemplate const* tInfo = sTransportMgr->GetTransportTemplate(entry);
+ if (!tInfo)
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Transport %u (name: %s) will not be created, missing `transport_template` entry.", entry, goinfo->name.c_str());
+ return false;
+ }
+
+ _transportInfo = tInfo;
+ // initialize waypoints
+ _nextFrame = tInfo->keyFrames.begin();
+ _currentFrame = _nextFrame++;
+ _triggeredArrivalEvent = false;
+ _triggeredDepartureEvent = false;
+
+ m_goValue.Transport.PathProgress = 0;
+ SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size);
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
- SetUInt32Value(GAMEOBJECT_LEVEL, m_period);
+ SetPeriod(tInfo->pathTime);
SetEntry(goinfo->entry);
-
SetDisplayId(goinfo->displayId);
-
SetGoState(GO_STATE_READY);
- SetGoType(GameobjectTypes(goinfo->type));
-
+ _pendingStop = goinfo->moTransport.canBeStopped != 0;
+ SetGoType(GAMEOBJECT_TYPE_MO_TRANSPORT);
SetGoAnimProgress(animprogress);
- if (dynflags)
- SetUInt32Value(GAMEOBJECT_DYNAMIC, MAKE_PAIR32(0, dynflags));
-
SetName(goinfo->name);
-
- SetZoneScript();
-
+ UpdateRotationFields(0.0f, 1.0f);
return true;
}
-struct keyFrame
+void Transport::Update(uint32 diff)
{
- explicit keyFrame(TaxiPathNodeEntry const& _node) : node(&_node),
- distSinceStop(-1.0f), distUntilStop(-1.0f), distFromPrev(-1.0f), tFrom(0.0f), tTo(0.0f)
- {
- }
+ uint32 const positionUpdateDelay = 200;
- TaxiPathNodeEntry const* node;
+ if (AI())
+ AI()->UpdateAI(diff);
+ else if (!AIM_Initialize())
+ TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Could not initialize GameObjectAI for Transport");
- float distSinceStop;
- float distUntilStop;
- float distFromPrev;
- float tFrom, tTo;
-};
+ if (GetKeyFrames().size() <= 1)
+ return;
-bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
-{
- if (pathid >= sTaxiPathNodesByPath.size())
- return false;
+ m_goValue.Transport.PathProgress += diff;
- TaxiPathNodeList const& path = sTaxiPathNodesByPath[pathid];
+ uint32 timer = m_goValue.Transport.PathProgress % GetPeriod();
- std::vector<keyFrame> keyFrames;
- int mapChange = 0;
- mapids.clear();
- for (size_t i = 1; i < path.size() - 1; ++i)
+ // Set current waypoint
+ // Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime
+ // ... arrive | ... delay ... | departure
+ // event / event /
+ for (;;)
{
- if (mapChange == 0)
+ if (timer >= _currentFrame->ArriveTime)
{
- TaxiPathNodeEntry const& node_i = path[i];
- if (node_i.mapid == path[i+1].mapid)
+ if (!_triggeredArrivalEvent)
{
- keyFrame k(node_i);
- keyFrames.push_back(k);
- mapids.insert(k.node->mapid);
+ DoEventIfAny(*_currentFrame, false);
+ _triggeredArrivalEvent = true;
}
- else
+
+ if (timer < _currentFrame->DepartureTime)
{
- mapChange = 1;
+ SetMoving(false);
+ if (_pendingStop)
+ SetGoState(GO_STATE_READY);
+ break; // its a stop frame and we are waiting
}
}
- else
- {
- --mapChange;
- }
- }
-
- int lastStop = -1;
- int firstStop = -1;
- // first cell is arrived at by teleportation :S
- keyFrames[0].distFromPrev = 0;
- if (keyFrames[0].node->actionFlag == 2)
- {
- lastStop = 0;
- }
-
- // find the rest of the distances between key points
- for (size_t i = 1; i < keyFrames.size(); ++i)
- {
- if ((keyFrames[i].node->actionFlag == 1) || (keyFrames[i].node->mapid != keyFrames[i-1].node->mapid))
+ if (_pendingStop && timer >= _currentFrame->DepartureTime && GetGoState() == GO_STATE_READY)
{
- keyFrames[i].distFromPrev = 0;
+ m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetPeriod());
+ m_goValue.Transport.PathProgress *= GetPeriod();
+ m_goValue.Transport.PathProgress += _currentFrame->ArriveTime;
+ break;
}
- else
- {
- keyFrames[i].distFromPrev =
- sqrt(pow(keyFrames[i].node->x - keyFrames[i - 1].node->x, 2) +
- pow(keyFrames[i].node->y - keyFrames[i - 1].node->y, 2) +
- pow(keyFrames[i].node->z - keyFrames[i - 1].node->z, 2));
- }
- if (keyFrames[i].node->actionFlag == 2)
+
+ if (timer >= _currentFrame->DepartureTime && !_triggeredDepartureEvent)
{
- // remember first stop frame
- if (firstStop == -1)
- firstStop = i;
- lastStop = i;
+ DoEventIfAny(*_currentFrame, true); // departure event
+ _triggeredDepartureEvent = true;
}
- }
-
- float tmpDist = 0;
- for (size_t i = 0; i < keyFrames.size(); ++i)
- {
- int j = (i + lastStop) % keyFrames.size();
- if (keyFrames[j].node->actionFlag == 2)
- tmpDist = 0;
- else
- tmpDist += keyFrames[j].distFromPrev;
- keyFrames[j].distSinceStop = tmpDist;
- }
- for (int i = int(keyFrames.size()) - 1; i >= 0; i--)
- {
- int j = (i + (firstStop+1)) % keyFrames.size();
- tmpDist += keyFrames[(j + 1) % keyFrames.size()].distFromPrev;
- keyFrames[j].distUntilStop = tmpDist;
- if (keyFrames[j].node->actionFlag == 2)
- tmpDist = 0;
- }
+ if (timer >= _currentFrame->DepartureTime && timer < _currentFrame->NextArriveTime)
+ break; // found current waypoint
- for (size_t i = 0; i < keyFrames.size(); ++i)
- {
- if (keyFrames[i].distSinceStop < (30 * 30 * 0.5f))
- keyFrames[i].tFrom = sqrt(2 * keyFrames[i].distSinceStop);
- else
- keyFrames[i].tFrom = ((keyFrames[i].distSinceStop - (30 * 30 * 0.5f)) / 30) + 30;
+ MoveToNextWaypoint();
- if (keyFrames[i].distUntilStop < (30 * 30 * 0.5f))
- keyFrames[i].tTo = sqrt(2 * keyFrames[i].distUntilStop);
- else
- keyFrames[i].tTo = ((keyFrames[i].distUntilStop - (30 * 30 * 0.5f)) / 30) + 30;
+ // not waiting anymore
+ SetMoving(true);
- keyFrames[i].tFrom *= 1000;
- keyFrames[i].tTo *= 1000;
- }
-
- // for (int i = 0; i < keyFrames.size(); ++i) {
- // TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "%f, %f, %f, %f, %f, %f, %f", keyFrames[i].x, keyFrames[i].y, keyFrames[i].distUntilStop, keyFrames[i].distSinceStop, keyFrames[i].distFromPrev, keyFrames[i].tFrom, keyFrames[i].tTo);
- // }
+ // Enable movement
+ if (GetGOInfo()->moTransport.canBeStopped)
+ SetGoState(GO_STATE_ACTIVE);
- // Now we're completely set up; we can move along the length of each waypoint at 100 ms intervals
- // speed = max(30, t) (remember x = 0.5s^2, and when accelerating, a = 1 unit/s^2
- int t = 0;
- bool teleport = false;
- if (keyFrames[keyFrames.size() - 1].node->mapid != keyFrames[0].node->mapid)
- teleport = true;
+ // Departure event
+ if (_currentFrame->IsTeleportFrame())
+ TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z);
- m_WayPoints[0] = WayPoint(keyFrames[0].node->mapid, keyFrames[0].node->x, keyFrames[0].node->y, keyFrames[0].node->z, teleport, 0,
- keyFrames[0].node->arrivalEventID, keyFrames[0].node->departureEventID);
+ sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
- t += keyFrames[0].node->delay * 1000;
+ TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "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);
+ }
- uint32 cM = keyFrames[0].node->mapid;
- for (size_t i = 0; i < keyFrames.size() - 1; ++i)
+ // Set position
+ _positionChangeTimer.Update(diff);
+ if (_positionChangeTimer.Passed())
{
- float d = 0;
- float tFrom = keyFrames[i].tFrom;
- float tTo = keyFrames[i].tTo;
-
- // keep the generation of all these points; we use only a few now, but may need the others later
- if (((d < keyFrames[i + 1].distFromPrev) && (tTo > 0)))
+ _positionChangeTimer.Reset(positionUpdateDelay);
+ if (IsMoving())
{
- while ((d < keyFrames[i + 1].distFromPrev) && (tTo > 0))
- {
- tFrom += 100;
- tTo -= 100;
-
- if (d > 0)
- {
- float newX = keyFrames[i].node->x + (keyFrames[i + 1].node->x - keyFrames[i].node->x) * d / keyFrames[i + 1].distFromPrev;
- float newY = keyFrames[i].node->y + (keyFrames[i + 1].node->y - keyFrames[i].node->y) * d / keyFrames[i + 1].distFromPrev;
- float newZ = keyFrames[i].node->z + (keyFrames[i + 1].node->z - keyFrames[i].node->z) * d / keyFrames[i + 1].distFromPrev;
-
- teleport = false;
- if (keyFrames[i].node->mapid != cM)
- {
- teleport = true;
- cM = keyFrames[i].node->mapid;
- }
-
- // TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ);
- if (teleport)
- m_WayPoints[t] = WayPoint(keyFrames[i].node->mapid, newX, newY, newZ, teleport, 0);
- }
-
- if (tFrom < tTo) // caught in tFrom dock's "gravitational pull"
- {
- if (tFrom <= 30000)
- {
- d = 0.5f * (tFrom / 1000) * (tFrom / 1000);
- }
- else
- {
- d = 0.5f * 30 * 30 + 30 * ((tFrom - 30000) / 1000);
- }
- d = d - keyFrames[i].distSinceStop;
- }
- else
- {
- if (tTo <= 30000)
- {
- d = 0.5f * (tTo / 1000) * (tTo / 1000);
- }
- else
- {
- d = 0.5f * 30 * 30 + 30 * ((tTo - 30000) / 1000);
- }
- d = keyFrames[i].distUntilStop - d;
- }
- t += 100;
- }
- t -= 100;
+ float t = CalculateSegmentPos(float(timer) * 0.001f);
+ G3D::Vector3 pos, dir;
+ _currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos);
+ //_currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir);
+ UpdatePosition(pos.x, pos.y, pos.z, 0.0f/*atan2(dir.x, dir.y)*/);
}
-
- if (keyFrames[i + 1].tFrom > keyFrames[i + 1].tTo)
- t += 100 - ((long)keyFrames[i + 1].tTo % 100);
- else
- t += (long)keyFrames[i + 1].tTo % 100;
-
- teleport = false;
- if ((keyFrames[i + 1].node->actionFlag == 1) || (keyFrames[i + 1].node->mapid != keyFrames[i].node->mapid))
- {
- teleport = true;
- cM = keyFrames[i + 1].node->mapid;
- }
-
- m_WayPoints[t] = WayPoint(keyFrames[i + 1].node->mapid, keyFrames[i + 1].node->x, keyFrames[i + 1].node->y, keyFrames[i + 1].node->z, teleport,
- 0, keyFrames[i + 1].node->arrivalEventID, keyFrames[i + 1].node->departureEventID);
- // TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport);
-
- t += keyFrames[i + 1].node->delay * 1000;
}
- uint32 timer = t;
-
- // TC_LOG_INFO(LOG_FILTER_TRANSPORTS, " Generated %lu waypoints, total time %u.", (unsigned long)m_WayPoints.size(), timer);
-
- m_curr = m_WayPoints.begin();
- m_next = GetNextWayPoint();
- m_pathTime = timer;
+ sScriptMgr->OnTransportUpdate(this, diff);
+}
- m_nextNodeTime = m_curr->first;
+void Transport::AddPassenger(WorldObject* passenger)
+{
+ if (_passengers.insert(passenger).second)
+ TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "Object %s boarded transport %s.", passenger->GetName().c_str(), GetName().c_str());
- return true;
+ if (Player* plr = passenger->ToPlayer())
+ sScriptMgr->OnAddPassenger(this, plr);
}
-Transport::WayPointMap::const_iterator Transport::GetNextWayPoint()
+void Transport::RemovePassenger(WorldObject* passenger)
{
- WayPointMap::const_iterator iter = m_curr;
- ++iter;
- if (iter == m_WayPoints.end())
- iter = m_WayPoints.begin();
- return iter;
+ if (_passengers.erase(passenger) || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload
+ TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "Object %s removed from transport %s.", passenger->GetName().c_str(), GetName().c_str());
+
+
+ if (Player* plr = passenger->ToPlayer())
+ sScriptMgr->OnRemovePassenger(this, plr);
}
-void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
+Creature* Transport::CreateNPCPassenger(uint32 guid, CreatureData const* data)
{
- Map const* oldMap = GetMap();
- Relocate(x, y, z);
+ Map* map = GetMap();
+ Creature* creature = new Creature();
- for (PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();)
+ if (!creature->LoadCreatureFromDB(guid, map, false))
{
- Player* player = *itr;
- ++itr;
-
- if (player->isDead() && !player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
- player->ResurrectPlayer(1.0f);
-
- player->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT);
+ delete creature;
+ return NULL;
}
- //we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference...
- //player far teleport would try to create same instance, but we need it NOW for transport...
+ float x = data->posX;
+ float y = data->posY;
+ float z = data->posZ;
+ float o = data->orientation;
- RemoveFromWorld();
- ResetMap();
- Map* newMap = sMapMgr->CreateBaseMap(newMapid);
- SetMap(newMap);
- ASSERT(GetMap());
- AddToWorld();
+ creature->SetTransport(this);
+ creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ creature->m_movementInfo.transport.guid = GetGUID();
+ creature->m_movementInfo.transport.pos.Relocate(x, y, z, o);
+ CalculatePassengerPosition(x, y, z, &o);
+ creature->Relocate(x, y, z, o);
+ creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
+ creature->SetTransportHomePosition(creature->m_movementInfo.transport.pos);
- if (oldMap != newMap)
+ if (!creature->IsPositionValid())
{
- UpdateForMap(oldMap);
- UpdateForMap(newMap);
+ TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Creature (guidlow %d, entry %d) not created. Suggested coordinates aren't valid (X: %f Y: %f)",creature->GetGUIDLow(),creature->GetEntry(),creature->GetPositionX(),creature->GetPositionY());
+ delete creature;
+ return NULL;
}
- for (CreatureSet::iterator itr = m_NPCPassengerSet.begin(); itr != m_NPCPassengerSet.end(); ++itr)
- (*itr)->FarTeleportTo(newMap, x, y, z, (*itr)->GetOrientation());
-}
-
-bool Transport::AddPassenger(Player* passenger)
-{
- if (m_passengers.insert(passenger).second)
- TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "Player %s boarded transport %s.", passenger->GetName().c_str(), GetName().c_str());
+ map->AddToMap(creature);
+ _staticPassengers.insert(creature);
- sScriptMgr->OnAddPassenger(this, passenger);
- return true;
+ sScriptMgr->OnAddCreaturePassenger(this, creature);
+ return creature;
}
-bool Transport::RemovePassenger(Player* passenger)
+GameObject* Transport::CreateGOPassenger(uint32 guid, GameObjectData const* data)
{
- if (m_passengers.erase(passenger))
- TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "Player %s removed from transport %s.", passenger->GetName().c_str(), GetName().c_str());
-
- sScriptMgr->OnRemovePassenger(this, passenger);
- return true;
-}
+ Map* map = GetMap();
+ GameObject* go = new GameObject();
-void Transport::Update(uint32 p_diff)
-{
- if (!AI())
+ if (!go->LoadGameObjectFromDB(guid, map, false))
{
- if (!AIM_Initialize())
- TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Could not initialize GameObjectAI for Transport");
- } else
- AI()->UpdateAI(p_diff);
+ delete go;
+ return NULL;
+ }
- if (m_WayPoints.size() <= 1)
- return;
+ float x = data->posX;
+ float y = data->posY;
+ float z = data->posZ;
+ float o = data->orientation;
- m_timer = getMSTime() % m_period;
- while (((m_timer - m_curr->first) % m_pathTime) > ((m_next->first - m_curr->first) % m_pathTime))
- {
- DoEventIfAny(*m_curr, true);
+ go->SetTransport(this);
+ go->m_movementInfo.transport.guid = GetGUID();
+ go->m_movementInfo.transport.pos.Relocate(x, y, z, o);
+ CalculatePassengerPosition(x, y, z, &o);
+ go->Relocate(x, y, z, o);
- m_curr = GetNextWayPoint();
- m_next = GetNextWayPoint();
+ if (!go->IsPositionValid())
+ {
+ TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "GameObject (guidlow %d, entry %d) not created. Suggested coordinates aren't valid (X: %f Y: %f)", go->GetGUIDLow(), go->GetEntry(), go->GetPositionX(), go->GetPositionY());
+ delete go;
+ return NULL;
+ }
- DoEventIfAny(*m_curr, false);
+ map->AddToMap(go);
+ _staticPassengers.insert(go);
- // first check help in case client-server transport coordinates de-synchronization
- if (m_curr->second.mapid != GetMapId() || m_curr->second.teleport)
- {
- TeleportTransport(m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z);
- }
- else
- {
- Relocate(m_curr->second.x, m_curr->second.y, m_curr->second.z, GetAngle(m_next->second.x, m_next->second.y) + float(M_PI));
- UpdatePassengerPositions(); // COME BACK MARKER
- }
-
- sScriptMgr->OnRelocate(this, m_curr->first, m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z);
+ //sScriptMgr->OnAddCreaturePassenger(this, go);
+ return go;
+}
- m_nextNodeTime = m_curr->first;
+void Transport::CalculatePassengerPosition(float& x, float& y, float& z, float* o /*= NULL*/) const
+{
+ float inx = x, iny = y, inz = z;
+ if (o)
+ *o = Position::NormalizeOrientation(GetOrientation() + *o);
- if (m_curr == m_WayPoints.begin())
- TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, " ************ BEGIN ************** %s", m_name.c_str());
+ x = GetPositionX() + inx * std::cos(GetOrientation()) - iny * std::sin(GetOrientation());
+ y = GetPositionY() + iny * std::cos(GetOrientation()) + inx * std::sin(GetOrientation());
+ z = GetPositionZ() + inz;
+}
- TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "%s moved to %d %f %f %f %d", m_name.c_str(), m_curr->second.id, m_curr->second.x, m_curr->second.y, m_curr->second.z, m_curr->second.mapid);
- }
+void Transport::CalculatePassengerOffset(float& x, float& y, float& z, float* o /*= NULL*/) const
+{
+ if (o)
+ *o = Position::NormalizeOrientation(*o - GetOrientation());
- sScriptMgr->OnTransportUpdate(this, p_diff);
+ z -= GetPositionZ();
+ y -= GetPositionY(); // y = searchedY * std::cos(o) + searchedX * std::sin(o)
+ x -= GetPositionX(); // x = searchedX * std::cos(o) + searchedY * std::sin(o + pi)
+ float inx = x, iny = y;
+ y = (iny - inx * std::tan(GetOrientation())) / (std::cos(GetOrientation()) + std::sin(GetOrientation()) * std::tan(GetOrientation()));
+ x = (inx + iny * std::tan(GetOrientation())) / (std::cos(GetOrientation()) + std::sin(GetOrientation()) * std::tan(GetOrientation()));
}
-void Transport::UpdateForMap(Map const* targetMap)
+void Transport::UpdatePosition(float x, float y, float z, float o)
{
- Map::PlayerList const& player = targetMap->GetPlayers();
- if (player.isEmpty())
- return;
+ bool newActive = GetMap()->IsGridLoaded(x, y);
+
+ Relocate(x, y, z, o);
+
+ UpdatePassengerPositions(_passengers);
+
+ /* There are four possible scenarios that trigger loading/unloading passengers:
+ 1. transport moves from inactive to active grid
+ 2. the grid that transport is currently in becomes active
+ 3. transport moves from active to inactive grid
+ 4. the grid that transport is currently in unloads
+ */
+ if (_staticPassengers.empty() && newActive) // 1. and 2.
+ LoadStaticPassengers();
+ else if (!_staticPassengers.empty() && !newActive && Cell(x, y).DiffGrid(Cell(GetPositionX(), GetPositionY()))) // 3.
+ UnloadStaticPassengers();
+ else
+ UpdatePassengerPositions(_staticPassengers);
+ // 4. is handed by grid unload
+}
- if (GetMapId() == targetMap->GetId())
+void Transport::LoadStaticPassengers()
+{
+ if (uint32 mapId = GetGOInfo()->moTransport.mapID)
{
- for (Map::PlayerList::const_iterator itr = player.begin(); itr != player.end(); ++itr)
+ CellObjectGuidsMap const& cells = sObjectMgr->GetMapObjectGuids(mapId, GetMap()->GetSpawnMode());
+ CellGuidSet::const_iterator guidEnd;
+ for (CellObjectGuidsMap::const_iterator cellItr = cells.begin(); cellItr != cells.end(); ++cellItr)
{
- if (this != itr->GetSource()->GetTransport())
- {
- UpdateData transData;
- BuildCreateUpdateBlockForPlayer(&transData, itr->GetSource());
- WorldPacket packet;
- transData.BuildPacket(&packet);
- itr->GetSource()->SendDirectMessage(&packet);
- }
+ // Creatures on transport
+ guidEnd = cellItr->second.creatures.end();
+ for (CellGuidSet::const_iterator guidItr = cellItr->second.creatures.begin(); guidItr != guidEnd; ++guidItr)
+ CreateNPCPassenger(*guidItr, sObjectMgr->GetCreatureData(*guidItr));
+
+ // GameObjects on transport
+ guidEnd = cellItr->second.gameobjects.end();
+ for (CellGuidSet::const_iterator guidItr = cellItr->second.gameobjects.begin(); guidItr != guidEnd; ++guidItr)
+ CreateGOPassenger(*guidItr, sObjectMgr->GetGOData(*guidItr));
}
}
- else
- {
- UpdateData transData;
- BuildOutOfRangeUpdateBlock(&transData);
- WorldPacket out_packet;
- transData.BuildPacket(&out_packet);
-
- for (Map::PlayerList::const_iterator itr = player.begin(); itr != player.end(); ++itr)
- if (this != itr->GetSource()->GetTransport())
- itr->GetSource()->SendDirectMessage(&out_packet);
- }
}
-void Transport::DoEventIfAny(WayPointMap::value_type const& node, bool departure)
+void Transport::UnloadStaticPassengers()
{
- if (uint32 eventid = departure ? node.second.departureEventID : node.second.arrivalEventID)
+ while (!_staticPassengers.empty())
{
- TC_LOG_DEBUG(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.first, GetName().c_str());
- GetMap()->ScriptsStart(sEventScripts, eventid, this, this);
- EventInform(eventid);
+ WorldObject* obj = *_staticPassengers.begin();
+ obj->AddObjectToRemoveList(); // also removes from _staticPassengers
}
}
-void Transport::BuildStartMovePacket(Map const* targetMap)
+void Transport::EnableMovement(bool enabled)
{
- SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
- SetGoState(GO_STATE_ACTIVE);
- UpdateForMap(targetMap);
+ if (!GetGOInfo()->moTransport.canBeStopped)
+ return;
+
+ _pendingStop = !enabled;
}
-void Transport::BuildStopMovePacket(Map const* targetMap)
+void Transport::MoveToNextWaypoint()
{
- RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
- SetGoState(GO_STATE_READY);
- UpdateForMap(targetMap);
+ // Clear events flagging
+ _triggeredArrivalEvent = false;
+ _triggeredDepartureEvent = false;
+
+ // Set frames
+ _currentFrame = _nextFrame++;
+ if (_nextFrame == GetKeyFrames().end())
+ _nextFrame = GetKeyFrames().begin();
}
-uint32 Transport::AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y, float z, float o, uint32 anim)
+float Transport::CalculateSegmentPos(float now)
{
- Map* map = GetMap();
- //make it world object so it will not be unloaded with grid
- Creature* creature = new Creature(true);
-
- if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, GetPhaseMask(), entry, 0, GetGOInfo()->faction, 0, 0, 0, 0))
+ KeyFrame const& frame = *_currentFrame;
+ const float speed = float(m_goInfo->moTransport.moveSpeed);
+ const float accel = float(m_goInfo->moTransport.accelRate);
+ float timeSinceStop = frame.TimeFrom + (now - (1.0f/IN_MILLISECONDS) * frame.DepartureTime);
+ float timeUntilStop = frame.TimeTo - (now - (1.0f/IN_MILLISECONDS) * frame.DepartureTime);
+ float segmentPos, dist;
+ float accelTime = _transportInfo->accelTime;
+ float accelDist = _transportInfo->accelDist;
+ // calculate from nearest stop, less confusing calculation...
+ if (timeSinceStop < timeUntilStop)
{
- delete creature;
- return 0;
+ if (timeSinceStop < accelTime)
+ dist = 0.5f * accel * timeSinceStop * timeSinceStop;
+ else
+ dist = accelDist + (timeSinceStop - accelTime) * speed;
+ segmentPos = dist - frame.DistSinceStop;
+ }
+ else
+ {
+ if (timeUntilStop < _transportInfo->accelTime)
+ dist = 0.5f * accel * timeUntilStop * timeUntilStop;
+ else
+ dist = accelDist + (timeUntilStop - accelTime) * speed;
+ segmentPos = frame.DistUntilStop - dist;
}
- creature->SetTransport(this);
- creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
- creature->m_movementInfo.guid = GetGUID();
- creature->m_movementInfo.transport.pos.Relocate(x, y, z, o);
+ return segmentPos / frame.NextDistFromPrev;
+}
- if (anim)
- creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, anim);
+void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
+{
+ Map const* oldMap = GetMap();
- creature->Relocate(
- GetPositionX() + (x * std::cos(GetOrientation()) + y * std::sin(GetOrientation() + float(M_PI))),
- GetPositionY() + (y * std::cos(GetOrientation()) + x * std::sin(GetOrientation())),
- z + GetPositionZ(),
- o + GetOrientation());
+ if (oldMap->GetId() != newMapid)
+ {
+ Map* newMap = sMapMgr->CreateBaseMap(newMapid);
+ Map::PlayerList const& oldPlayers = GetMap()->GetPlayers();
+ if (!oldPlayers.isEmpty())
+ {
+ UpdateData data;
+ BuildOutOfRangeUpdateBlock(&data);
+ WorldPacket packet;
+ data.BuildPacket(&packet);
+ for (Map::PlayerList::const_iterator itr = oldPlayers.begin(); itr != oldPlayers.end(); ++itr)
+ if (itr->GetSource()->GetTransport() != this)
+ itr->GetSource()->SendDirectMessage(&packet);
+ }
- creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
- creature->SetTransportHomePosition(creature->m_movementInfo.transport.pos);
+ UnloadStaticPassengers();
+ GetMap()->RemoveFromMap<Transport>(this, false);
+ SetMap(newMap);
- if (!creature->IsPositionValid())
- {
- TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)", creature->GetGUIDLow(), creature->GetEntry(), creature->GetPositionX(), creature->GetPositionY());
- delete creature;
- return 0;
- }
+ Map::PlayerList const& newPlayers = GetMap()->GetPlayers();
+ if (!newPlayers.isEmpty())
+ {
+ for (Map::PlayerList::const_iterator itr = newPlayers.begin(); itr != newPlayers.end(); ++itr)
+ {
+ if (itr->GetSource()->GetTransport() != this)
+ {
+ UpdateData data;
+ BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
+ WorldPacket packet;
+ data.BuildPacket(&packet);
+ itr->GetSource()->SendDirectMessage(&packet);
+ }
+ }
+ }
- map->AddToMap(creature);
- m_NPCPassengerSet.insert(creature);
+ // Teleport passengers after everyone on destination map are sent create packet
+ // but before transport itself is registered there and begins updating
+ for (std::set<WorldObject*>::iterator itr = _staticPassengers.begin(); itr != _staticPassengers.end(); ++itr)
+ {
+ switch ((*itr)->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ (*itr)->ToCreature()->FarTeleportTo(newMap, x, y, z, (*itr)->GetOrientation());
+ break;
+ case TYPEID_GAMEOBJECT:
+ {
+ GameObject* go = (*itr)->ToGameObject();
+ go->GetMap()->RemoveFromMap(go, false);
+ Relocate(x, y, z, go->GetOrientation());
+ SetMap(newMap);
+ newMap->AddToMap(go);
+ break;
+ }
+ default:
+ break;
+ }
+ }
- if (tguid == 0)
- {
- ++currenttguid;
- tguid = currenttguid;
+ for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
+ {
+ switch ((*itr)->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ if (!IS_PLAYER_GUID((*itr)->ToUnit()->GetOwnerGUID())) // pets should be teleported with player
+ (*itr)->ToCreature()->FarTeleportTo(newMap, x, y, z, (*itr)->GetOrientation());
+ break;
+ case TYPEID_GAMEOBJECT:
+ {
+ GameObject* go = (*itr)->ToGameObject();
+ go->GetMap()->RemoveFromMap(go, false);
+ Relocate(x, y, z, go->GetOrientation());
+ SetMap(newMap);
+ newMap->AddToMap(go);
+ break;
+ }
+ case TYPEID_PLAYER:
+ (*itr)->ToPlayer()->TeleportTo(newMapid, x, y, z, (*itr)->GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT);
+ break;
+ default:
+ break;
+ }
+ }
+
+ GetMap()->AddToMap<Transport>(this);
}
else
- currenttguid = std::max(tguid, currenttguid);
-
- creature->SetGUIDTransport(tguid);
- sScriptMgr->OnAddCreaturePassenger(this, creature);
- return tguid;
-}
-
-void Transport::UpdatePosition(MovementInfo* mi)
-{
- float transport_o = mi->pos.GetOrientation() - mi->transport.pos.GetOrientation();
- float transport_x = mi->pos.m_positionX - (mi->transport.pos.m_positionX * std::cos(transport_o) - mi->transport.pos.m_positionY * std::sin(transport_o));
- float transport_y = mi->pos.m_positionY - (mi->transport.pos.m_positionY * std::cos(transport_o) + mi->transport.pos.m_positionX * std::sin(transport_o));
- float transport_z = mi->pos.m_positionZ - mi->transport.pos.m_positionZ;
+ {
+ // Teleport players, they need to know it
+ for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
+ if ((*itr)->GetTypeId() == TYPEID_PLAYER)
+ (*itr)->ToUnit()->NearTeleportTo(x, y, z, GetOrientation());
+ }
- Relocate(transport_x, transport_y, transport_z, transport_o);
- UpdatePassengerPositions();
+ UpdatePosition(x, y, z, GetOrientation());
}
-void Transport::UpdatePassengerPositions()
+void Transport::UpdatePassengerPositions(std::set<WorldObject*>& passengers)
{
- for (CreatureSet::iterator itr = m_NPCPassengerSet.begin(); itr != m_NPCPassengerSet.end(); ++itr)
+ for (std::set<WorldObject*>::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
{
- Creature* npc = *itr;
+ WorldObject* passenger = *itr;
+ // transport teleported but passenger not yet (can happen for players)
+ if (passenger->GetMap() != GetMap())
+ continue;
+
+ // if passenger is on vehicle we have to assume the vehicle is also on transport
+ // and its the vehicle that will be updating its passengers
+ if (Unit* unit = passenger->ToUnit())
+ if (unit->GetVehicle())
+ continue;
+ // Do not use Unit::UpdatePosition here, we don't want to remove auras
+ // as if regular movement occurred
float x, y, z, o;
- npc->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
+ passenger->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
CalculatePassengerPosition(x, y, z, &o);
- GetMap()->CreatureRelocation(npc, x, y, z, o, false);
- npc->GetTransportHomePosition(x, y, z, o);
- CalculatePassengerPosition(x, y, z, &o);
- npc->SetHomePosition(x, y, z, o);
+ switch (passenger->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ {
+ Creature* creature = passenger->ToCreature();
+ GetMap()->CreatureRelocation(creature, x, y, z, o, false);
+ creature->GetTransportHomePosition(x, y, z, o);
+ CalculatePassengerPosition(x, y, z, &o);
+ creature->SetHomePosition(x, y, z, o);
+ break;
+ }
+ case TYPEID_PLAYER:
+ GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o);
+ break;
+ case TYPEID_GAMEOBJECT:
+ GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o, false);
+ break;
+ default:
+ break;
+ }
+
+ if (Unit* unit = passenger->ToUnit())
+ if (Vehicle* vehicle = unit->GetVehicleKit())
+ vehicle->RelocatePassengers();
}
}
-void Transport::CalculatePassengerPosition(float& x, float& y, float& z, float* o /*= NULL*/) const
+void Transport::DoEventIfAny(KeyFrame const& node, bool departure)
{
- float inx = x, iny = y, inz = z;
- if (o)
- *o = Position::NormalizeOrientation(GetOrientation() + *o);
-
- x = GetPositionX() + inx * std::cos(GetOrientation()) - iny * std::sin(GetOrientation());
- y = GetPositionY() + iny * std::cos(GetOrientation()) + inx * std::sin(GetOrientation());
- z = GetPositionZ() + inz;
+ if (uint32 eventid = departure ? node.Node->departureEventID : node.Node->arrivalEventID)
+ {
+ TC_LOG_DEBUG(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->index, GetName().c_str());
+ GetMap()->ScriptsStart(sEventScripts, eventid, this, this);
+ EventInform(eventid);
+ }
}
-void Transport::CalculatePassengerOffset(float& x, float& y, float& z, float* o /*= NULL*/) const
+void Transport::BuildUpdate(UpdateDataMapType& data_map)
{
- if (o)
- *o = Position::NormalizeOrientation(*o - GetOrientation());
+ Map::PlayerList const& players = GetMap()->GetPlayers();
+ if (players.isEmpty())
+ return;
- z -= GetPositionZ();
- y -= GetPositionY(); // y = searchedY * std::cos(o) + searchedX * std::sin(o)
- x -= GetPositionX(); // x = searchedX * std::cos(o) + searchedY * std::sin(o + pi)
- float inx = x, iny = y;
- y = (iny - inx * std::tan(GetOrientation())) / (std::cos(GetOrientation()) + std::sin(GetOrientation()) * std::tan(GetOrientation()));
- x = (inx + iny * std::tan(GetOrientation())) / (std::cos(GetOrientation()) + std::sin(GetOrientation()) * std::tan(GetOrientation()));
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ BuildFieldsUpdate(itr->GetSource(), data_map);
+
+ ClearUpdateMask(true);
}
diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h
index 445bec456fd..0d020fe2c34 100644
--- a/src/server/game/Entities/Transport/Transport.h
+++ b/src/server/game/Entities/Transport/Transport.h
@@ -20,34 +20,30 @@
#define TRANSPORTS_H
#include "GameObject.h"
+#include "TransportMgr.h"
#include "VehicleDefines.h"
-#include <map>
-#include <set>
-#include <string>
+struct CreatureData;
class Transport : public GameObject, public TransportBase
{
+ friend Transport* TransportMgr::CreateTransport(uint32, uint32, Map*);
+
+ Transport();
public:
- Transport(uint32 period, uint32 script);
~Transport();
- bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags);
- bool GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids);
- void Update(uint32 p_time);
- bool AddPassenger(Player* passenger);
- bool RemovePassenger(Player* passenger);
+ bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress);
+ void Update(uint32 diff);
- void RemovePassenger(Creature* passenger) { m_NPCPassengerSet.erase(passenger); }
+ void BuildUpdate(UpdateDataMapType& data_map);
- typedef std::set<Player*> PlayerSet;
- PlayerSet const& GetPassengers() const { return m_passengers; }
+ void AddPassenger(WorldObject* passenger);
+ void RemovePassenger(WorldObject* passenger);
+ std::set<WorldObject*> const& GetPassengers() const { return _passengers; }
- typedef std::set<Creature*> CreatureSet;
- CreatureSet m_NPCPassengerSet;
- uint32 AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y, float z, float o, uint32 anim=0);
- void UpdatePosition(MovementInfo* mi);
- void UpdatePassengerPositions();
+ Creature* CreateNPCPassenger(uint32 guid, CreatureData const* data);
+ GameObject* CreateGOPassenger(uint32 guid, GameObjectData const* data);
/// This method transforms supplied transport offsets into global coordinates
void CalculatePassengerPosition(float& x, float& y, float& z, float* o = NULL) const;
@@ -55,50 +51,50 @@ class Transport : public GameObject, public TransportBase
/// This method transforms supplied global coordinates into local offsets
void CalculatePassengerOffset(float& x, float& y, float& z, float* o = NULL) const;
- void BuildStartMovePacket(Map const* targetMap);
- void BuildStopMovePacket(Map const* targetMap);
- uint32 GetScriptId() const { return ScriptId; }
- private:
- struct WayPoint
- {
- WayPoint() : mapid(0), x(0), y(0), z(0), teleport(false), id(0) {}
- WayPoint(uint32 _mapid, float _x, float _y, float _z, bool _teleport, uint32 _id = 0,
- uint32 _arrivalEventID = 0, uint32 _departureEventID = 0)
- : mapid(_mapid), x(_x), y(_y), z(_z), teleport(_teleport), id(_id),
- arrivalEventID(_arrivalEventID), departureEventID(_departureEventID)
- {
- }
- uint32 mapid;
- float x;
- float y;
- float z;
- bool teleport;
- uint32 id;
- uint32 arrivalEventID;
- uint32 departureEventID;
- };
-
- typedef std::map<uint32, WayPoint> WayPointMap;
-
- WayPointMap::const_iterator m_curr;
- WayPointMap::const_iterator m_next;
- uint32 m_pathTime;
- uint32 m_timer;
-
- PlayerSet m_passengers;
-
- uint32 currenttguid;
- uint32 m_period;
- uint32 ScriptId;
- public:
- WayPointMap m_WayPoints;
- uint32 m_nextNodeTime;
+ uint32 GetPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
+ void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
+ uint32 GetTimer() const { return GetGOValue()->Transport.PathProgress; }
+
+ KeyFrameVec const& GetKeyFrames() const { return _transportInfo->keyFrames; }
+
+ void UpdatePosition(float x, float y, float z, float o);
+
+ //! Needed when transport moves from inactive to active grid
+ void LoadStaticPassengers();
+
+ //! Needed when transport enters inactive grid
+ void UnloadStaticPassengers();
+
+ void EnableMovement(bool enabled);
+
+ TransportTemplate const* GetTransportTemplate() const { return _transportInfo; }
private:
+ void MoveToNextWaypoint();
+ float CalculateSegmentPos(float perc);
void TeleportTransport(uint32 newMapid, float x, float y, float z);
- void UpdateForMap(Map const* map);
- void DoEventIfAny(WayPointMap::value_type const& node, bool departure);
- WayPointMap::const_iterator GetNextWayPoint();
+ void UpdatePassengerPositions(std::set<WorldObject*>& passengers);
+ void DoEventIfAny(KeyFrame const& node, bool departure);
+
+ //! Helpers to know if stop frame was reached
+ bool IsMoving() const { return _isMoving; }
+ void SetMoving(bool val) { _isMoving = val; }
+
+ TransportTemplate const* _transportInfo;
+
+ KeyFrameVec::const_iterator _currentFrame;
+ KeyFrameVec::const_iterator _nextFrame;
+ uint32 _moveTimer;
+ TimeTrackerSmall _positionChangeTimer;
+ bool _isMoving;
+ bool _pendingStop;
+
+ //! These are needed to properly control events triggering only once for each frame
+ bool _triggeredArrivalEvent;
+ bool _triggeredDepartureEvent;
+
+ std::set<WorldObject*> _passengers;
+ std::set<WorldObject*> _staticPassengers;
};
-#endif
+#endif
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index c34768c9851..2fd1c500305 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -259,7 +259,6 @@ Unit::Unit(bool isWorldObject) :
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
- _focusSpell = NULL;
_lastLiquid = NULL;
_isWalkingBeforeCharm = false;
}
@@ -568,6 +567,9 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
if (IsAIEnabled)
GetAI()->DamageDealt(victim, damage, damagetype);
+ // Hook for OnDamage Event
+ sScriptMgr->OnDamage(this, victim, damage);
+
if (victim->GetTypeId() == TYPEID_PLAYER && this != victim)
{
// Signal to pets that their owner was attacked
@@ -2483,7 +2485,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo)
{
// Can`t miss on dead target (on skinning for example)
- if (!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER)
+ if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
return SPELL_MISS_NONE;
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
@@ -2508,19 +2510,15 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
// Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects
- if (!(spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
- {
- // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
- modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
- // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
- if (spellInfo->IsTargetingArea())
- modHitChance -= victim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
+ // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
+ modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
+ // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
+ if (spellInfo->IsTargetingArea())
+ modHitChance -= victim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
- // Decrease hit chance from victim rating bonus
- if (victim->GetTypeId() == TYPEID_PLAYER)
- modHitChance -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL));
- }
+ // Decrease hit chance from victim rating bonus
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ modHitChance -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL));
int32 HitChance = modHitChance * 100;
// Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
@@ -2535,11 +2533,6 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
if (rand < tmp)
return SPELL_MISS_MISS;
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
- // resist and deflect chances
- if (spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
- return SPELL_MISS_NONE;
-
// Chance resist mechanic (select max value from every mechanic spell effect)
int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
tmp += resist_chance;
@@ -2564,7 +2557,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
}
}
- // Roll chance
+ // Roll chance
if (rand < tmp)
return SPELL_MISS_RESIST;
@@ -5258,18 +5251,19 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
// cast 45429 Arcane Bolt if Exalted by Scryers
case 45481:
{
- if (GetTypeId() != TYPEID_PLAYER)
+ Player* player = ToPlayer();
+ if (!player)
return false;
// Get Aldor reputation rank
- if (ToPlayer()->GetReputationRank(932) == REP_EXALTED)
+ if (player->GetReputationRank(932) == REP_EXALTED)
{
target = this;
triggered_spell_id = 45479;
break;
}
// Get Scryers reputation rank
- if (ToPlayer()->GetReputationRank(934) == REP_EXALTED)
+ if (player->GetReputationRank(934) == REP_EXALTED)
{
// triggered at positive/self casts also, current attack target used then
if (target && IsFriendlyTo(target))
@@ -5277,8 +5271,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
target = GetVictim();
if (!target)
{
- uint64 selected_guid = ToPlayer()->GetSelection();
- target = ObjectAccessor::GetUnit(*this, selected_guid);
+ target = player->GetSelectedUnit();
if (!target)
return false;
}
@@ -9588,6 +9581,9 @@ int32 Unit::DealHeal(Unit* victim, uint32 addhealth)
if (addhealth)
gain = victim->ModifyHealth(int32(addhealth));
+ // Hook for OnHeal Event
+ sScriptMgr->OnHeal(this, victim, (uint32&)gain);
+
Unit* unit = this;
if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTotem())
@@ -16904,7 +16900,7 @@ void Unit::_ExitVehicle(Position const* exitPosition)
if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT)
if (((Minion*)vehicle->GetBase())->GetOwner() == this)
- vehicle->GetBase()->ToCreature()->DespawnOrUnsummon();
+ vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(1);
if (HasUnitTypeMask(UNIT_MASK_ACCESSORY))
{
@@ -17333,6 +17329,8 @@ void Unit::SetFacingTo(float ori)
{
Movement::MoveSplineInit init(this);
init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset(), false);
+ if (HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && GetTransGUID())
+ init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
init.SetFacing(ori);
init.Launch();
}
@@ -17344,7 +17342,10 @@ void Unit::SetFacingToObject(WorldObject* object)
return;
/// @todo figure out under what conditions creature will move towards object instead of facing it where it currently is.
- SetFacingTo(GetAngle(object));
+ Movement::MoveSplineInit init(this);
+ init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
+ init.SetFacing(GetAngle(object)); // when on transport, GetAngle will still return global coordinates (and angle) that needs transforming
+ init.Launch();
}
bool Unit::SetWalk(bool enable)
@@ -17471,43 +17472,6 @@ bool Unit::SetHover(bool enable, bool /*packetOnly = false*/)
return true;
}
-void Unit::SetTarget(uint64 guid)
-{
- if (!_focusSpell)
- SetUInt64Value(UNIT_FIELD_TARGET, guid);
-}
-
-void Unit::FocusTarget(Spell const* focusSpell, WorldObject const* target)
-{
- // already focused
- if (_focusSpell)
- return;
-
- _focusSpell = focusSpell;
- SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID());
- if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
- AddUnitState(UNIT_STATE_ROTATING);
-
- // Set serverside orientation if needed (needs to be after attribute check)
- SetInFront(target);
-}
-
-void Unit::ReleaseFocus(Spell const* focusSpell)
-{
- // focused to something else
- if (focusSpell != _focusSpell)
- return;
-
- _focusSpell = NULL;
- if (Unit* victim = GetVictim())
- SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
- else
- SetUInt64Value(UNIT_FIELD_TARGET, 0);
-
- if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
- ClearUnitState(UNIT_STATE_ROTATING);
-}
-
void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
{
if (!target)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 119a1dd1966..25352a924ef 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -2078,12 +2078,6 @@ class Unit : public WorldObject
bool IsOnVehicle(const Unit* vehicle) const;
Unit* GetVehicleBase() const;
Creature* GetVehicleCreatureBase() const;
- float GetTransOffsetX() const { return m_movementInfo.transport.pos.GetPositionX(); }
- float GetTransOffsetY() const { return m_movementInfo.transport.pos.GetPositionY(); }
- float GetTransOffsetZ() const { return m_movementInfo.transport.pos.GetPositionZ(); }
- float GetTransOffsetO() const { return m_movementInfo.transport.pos.GetOrientation(); }
- uint32 GetTransTime() const { return m_movementInfo.transport.time; }
- int8 GetTransSeat() const { return m_movementInfo.transport.seat; }
uint64 GetTransGUID() const;
/// Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
TransportBase* GetDirectTransport() const;
@@ -2124,11 +2118,8 @@ class Unit : public WorldObject
TempSummon* ToTempSummon() { if (IsSummon()) return reinterpret_cast<TempSummon*>(this); else return NULL; }
TempSummon const* ToTempSummon() const { if (IsSummon()) return reinterpret_cast<TempSummon const*>(this); else return NULL; }
- void SetTarget(uint64 guid);
-
- // Handling caster facing during spellcast
- void FocusTarget(Spell const* focusSpell, WorldObject const* target);
- void ReleaseFocus(Spell const* focusSpell);
+ uint64 GetTarget() const { return GetUInt64Value(UNIT_FIELD_TARGET); }
+ virtual void SetTarget(uint64 /*guid*/) = 0;
// Movement info
Movement::MoveSpline * movespline;
@@ -2253,7 +2244,6 @@ class Unit : public WorldObject
bool m_cleanupDone; // lock made to not add stuff after cleanup before delete
bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world
- Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
bool _isWalkingBeforeCharm; // Are we walking before we were charmed?
time_t _lastDamagedTime; // Part of Evade mechanics
diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp
index afc27b74ecc..67474c1dca0 100644
--- a/src/server/game/Globals/ObjectAccessor.cpp
+++ b/src/server/game/Globals/ObjectAccessor.cpp
@@ -147,6 +147,15 @@ GameObject* ObjectAccessor::GetGameObject(WorldObject const& u, uint64 guid)
return GetObjectInMap(guid, u.GetMap(), (GameObject*)NULL);
}
+Transport* ObjectAccessor::GetTransport(WorldObject const& u, uint64 guid)
+{
+ if (GUID_HIPART(guid) != HIGHGUID_MO_TRANSPORT)
+ return NULL;
+
+ GameObject* go = GetGameObject(u, guid);
+ return go ? go->ToTransport() : NULL;
+}
+
DynamicObject* ObjectAccessor::GetDynamicObject(WorldObject const& u, uint64 guid)
{
return GetObjectInMap(guid, u.GetMap(), (DynamicObject*)NULL);
diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h
index 1abe3550729..a2707920c63 100644
--- a/src/server/game/Globals/ObjectAccessor.h
+++ b/src/server/game/Globals/ObjectAccessor.h
@@ -40,6 +40,7 @@ class WorldObject;
class Vehicle;
class Map;
class WorldRunnable;
+class Transport;
template <class T>
class HashMapHolder
@@ -145,6 +146,7 @@ class ObjectAccessor
static Object* GetObjectByTypeMask(WorldObject const&, uint64, uint32 typemask);
static Corpse* GetCorpse(WorldObject const& u, uint64 guid);
static GameObject* GetGameObject(WorldObject const& u, uint64 guid);
+ static Transport* GetTransport(WorldObject const& u, uint64 guid);
static DynamicObject* GetDynamicObject(WorldObject const& u, uint64 guid);
static Unit* GetUnit(WorldObject const&, uint64 guid);
static Creature* GetCreature(WorldObject const& u, uint64 guid);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 2f309c07cce..86e6963b1de 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -804,6 +804,18 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
TC_LOG_ERROR(LOG_FILTER_SQL, "Creature (Entry: %u) has wrong trainer type %u.", cInfo->Entry, cInfo->trainer_type);
+ if (cInfo->speed_walk == 0.0f)
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Creature (Entry: %u) has wrong value (%f) in speed_walk, set to 1.", cInfo->Entry, cInfo->speed_walk);
+ const_cast<CreatureTemplate*>(cInfo)->speed_walk = 1.0f;
+ }
+
+ if (cInfo->speed_run == 0.0f)
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Creature (Entry: %u) has wrong value (%f) in speed_run, set to 1.14286.", cInfo->Entry, cInfo->speed_run);
+ const_cast<CreatureTemplate*>(cInfo)->speed_run = 1.14286f;
+ }
+
if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
{
TC_LOG_ERROR(LOG_FILTER_SQL, "Creature (Entry: %u) has invalid creature type (%u) in `type`.", cInfo->Entry, cInfo->type);
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index e44333c4a7a..752cc3b56ab 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -1019,6 +1019,11 @@ class ObjectMgr
return _mapObjectGuidsStore[MAKE_PAIR32(mapid, spawnMode)][cell_id];
}
+ CellObjectGuidsMap const& GetMapObjectGuids(uint16 mapid, uint8 spawnMode)
+ {
+ return _mapObjectGuidsStore[MAKE_PAIR32(mapid, spawnMode)];
+ }
+
/**
* Gets temp summon data for all creatures of specified group.
*
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index b8ab75f213b..00b1e82a0ea 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -35,16 +35,28 @@ void VisibleNotifier::SendToSelf()
// at this moment i_clientGUIDs have guids that not iterate at grid level checks
// but exist one case when this possible and object not out of range: transports
if (Transport* transport = i_player.GetTransport())
- for (Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin();itr != transport->GetPassengers().end();++itr)
+ for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end();++itr)
{
if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end())
{
vis_guids.erase((*itr)->GetGUID());
- i_player.UpdateVisibilityOf((*itr), i_data, i_visibleNow);
-
- if (!(*itr)->isNeedNotify(NOTIFY_VISIBILITY_CHANGED))
- (*itr)->UpdateVisibilityOf(&i_player);
+ switch ((*itr)->GetTypeId())
+ {
+ case TYPEID_GAMEOBJECT:
+ i_player.UpdateVisibilityOf((*itr)->ToGameObject(), i_data, i_visibleNow);
+ break;
+ case TYPEID_PLAYER:
+ i_player.UpdateVisibilityOf((*itr)->ToPlayer(), i_data, i_visibleNow);
+ if (!(*itr)->isNeedNotify(NOTIFY_VISIBILITY_CHANGED))
+ (*itr)->ToPlayer()->UpdateVisibilityOf(&i_player);
+ break;
+ case TYPEID_UNIT:
+ i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow);
+ break;
+ default:
+ break;
+ }
}
}
@@ -324,10 +336,8 @@ template<class T>
void ObjectUpdater::Visit(GridRefManager<T> &m)
{
for (typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
- {
if (iter->GetSource()->IsInWorld())
iter->GetSource()->Update(i_timeDiff);
- }
}
bool AnyDeadUnitObjectInRangeCheck::operator()(Player* u)
@@ -360,5 +370,6 @@ bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u)
return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
}
-template void ObjectUpdater::Visit<GameObject>(GameObjectMapType &);
-template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType &);
+template void ObjectUpdater::Visit<Creature>(CreatureMapType&);
+template void ObjectUpdater::Visit<GameObject>(GameObjectMapType&);
+template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType&);
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index 58a5bbbff06..05dff6823be 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -43,6 +43,20 @@ void ObjectGridEvacuator::Visit(CreatureMapType &m)
}
}
+void ObjectGridEvacuator::Visit(GameObjectMapType &m)
+{
+ // gameobject in unloading grid can have respawn point in another grid
+ // if it will be unloaded then it will not respawn in original grid until unload/load original grid
+ // move to respawn point to prevent this case. For player view in respawn grid this will be normal respawn.
+ for (GameObjectMapType::iterator iter = m.begin(); iter != m.end();)
+ {
+ GameObject* go = iter->GetSource();
+ ++iter;
+
+ go->GetMap()->GameObjectRespawnRelocation(go, true);
+ }
+}
+
// for loading world object at grid loading (Corpses)
/// @todo to implement npc on transport, also need to load npcs at grid loading
class ObjectWorldLoader
@@ -70,12 +84,26 @@ template<class T> void ObjectGridLoader::SetObjectCell(T* /*obj*/, CellCoord con
template<> void ObjectGridLoader::SetObjectCell(Creature* obj, CellCoord const& cellCoord)
{
Cell cell(cellCoord);
+ obj->SetCurrentCell(cell);
+}
+template<> void ObjectGridLoader::SetObjectCell(GameObject* obj, CellCoord const& cellCoord)
+{
+ Cell cell(cellCoord);
obj->SetCurrentCell(cell);
}
template <class T>
-void AddObjectHelper(CellCoord &cell, GridRefManager<T> &m, uint32 &count, Map* map, T *obj)
+void AddObjectHelper(CellCoord &cell, GridRefManager<T> &m, uint32 &count, Map* /*map*/, T *obj)
+{
+ obj->AddToGrid(m);
+ ObjectGridLoader::SetObjectCell(obj, cell);
+ obj->AddToWorld();
+ ++count;
+}
+
+template <>
+void AddObjectHelper(CellCoord &cell, CreatureMapType &m, uint32 &count, Map* map, Creature *obj)
{
obj->AddToGrid(m);
ObjectGridLoader::SetObjectCell(obj, cell);
diff --git a/src/server/game/Grids/ObjectGridLoader.h b/src/server/game/Grids/ObjectGridLoader.h
index 11f91670a5f..b858b92da32 100644
--- a/src/server/game/Grids/ObjectGridLoader.h
+++ b/src/server/game/Grids/ObjectGridLoader.h
@@ -67,6 +67,7 @@ class ObjectGridEvacuator
{
public:
void Visit(CreatureMapType &m);
+ void Visit(GameObjectMapType &m);
template<class T> void Visit(GridRefManager<T> &) {}
};
diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp
index 031febc3806..1a3e48c8217 100644
--- a/src/server/game/Guilds/Guild.cpp
+++ b/src/server/game/Guilds/Guild.cpp
@@ -1764,7 +1764,7 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool
{
//clamp amount to MAX_MONEY_AMOUNT, Players can't hold more than that anyway
amount = std::min(amount, uint32(MAX_MONEY_AMOUNT));
-
+
if (m_bankMoney < amount) // Not enough money in bank
return false;
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index f65641eaa76..71453581ed0 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -1167,8 +1167,6 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData)
TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_INSPECT");
- _player->SetSelection(guid);
-
Player* player = ObjectAccessor::FindPlayer(guid);
if (!player)
{
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 1faa68b6ea4..36d1e1cb1ea 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -303,30 +303,21 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
{
if (!plrMover->GetTransport())
{
- // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just dismount if the guid can be found in the transport list
- for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter)
+ if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
{
- if ((*iter)->GetGUID() == movementInfo.transport.guid)
- {
- plrMover->m_transport = *iter;
- (*iter)->AddPassenger(plrMover);
- break;
- }
+ plrMover->m_transport = transport;
+ transport->AddPassenger(plrMover);
}
}
else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid)
{
bool foundNewTransport = false;
plrMover->m_transport->RemovePassenger(plrMover);
- for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter)
+ if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
{
- if ((*iter)->GetGUID() == movementInfo.transport.guid)
- {
- foundNewTransport = true;
- plrMover->m_transport = *iter;
- (*iter)->AddPassenger(plrMover);
- break;
- }
+ foundNewTransport = true;
+ plrMover->m_transport = transport;
+ transport->AddPassenger(plrMover);
}
if (!foundNewTransport)
diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index 5a94d5b391b..4638e05ee3d 100644
--- a/src/server/game/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
@@ -267,7 +267,6 @@ void WorldSession::HandleNpcTextQueryOpcode(WorldPacket& recvData)
TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID);
recvData >> guid;
- GetPlayer()->SetSelection(guid);
GossipText const* pGossip = sObjectMgr->GetGossipText(textID);
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 4660489004d..9abb78187a9 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -63,6 +63,17 @@ Map::~Map()
obj->ResetMap();
}
+ for (TransportsContainer::iterator itr = _transports.begin(); itr != _transports.end(); ++itr)
+ {
+ Transport* transport = *itr;
+ // Destroy local transports
+ if (transport->GetTransportTemplate()->inInstance)
+ {
+ transport->RemoveFromWorld();
+ delete transport;
+ }
+ }
+
if (!m_scriptSchedule.empty())
sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size());
@@ -217,10 +228,12 @@ void Map::DeleteStateMachine()
}
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent):
-_creatureToMoveLock(false), i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
+_creatureToMoveLock(false), _gameObjectsToMoveLock(false),
+i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE),
m_VisibilityNotifyPeriod(DEFAULT_VISIBILITY_NOTIFY_PERIOD),
-m_activeNonPlayersIter(m_activeNonPlayers.end()), i_gridExpiry(expiry),
+m_activeNonPlayersIter(m_activeNonPlayers.end()), _transportsUpdateIter(_transports.end()),
+i_gridExpiry(expiry),
i_scriptLock(false)
{
m_parentMap = (_parent ? _parent : this);
@@ -270,6 +283,21 @@ void Map::AddToGrid(Creature* obj, Cell const& cell)
obj->SetCurrentCell(cell);
}
+template<>
+void Map::AddToGrid(GameObject* obj, Cell const& cell)
+{
+ NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
+ grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
+
+ obj->SetCurrentCell(cell);
+}
+
+template<class T>
+void Map::SwitchGridContainers(T* /*obj*/, bool /*on*/)
+{
+}
+
+template<>
void Map::SwitchGridContainers(Creature* obj, bool on)
{
ASSERT(!obj->IsPermanentWorldObject());
@@ -291,6 +319,7 @@ void Map::SwitchGridContainers(Creature* obj, bool on)
GridType &grid = ngrid->GetGridType(cell.CellX(), cell.CellY());
obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add
+
if (on)
{
grid.AddWorldObject(obj);
@@ -301,9 +330,45 @@ void Map::SwitchGridContainers(Creature* obj, bool on)
grid.AddGridObject(obj);
RemoveWorldObject(obj);
}
+
obj->m_isTempWorldObject = on;
}
+template<>
+void Map::SwitchGridContainers(GameObject* obj, bool on)
+{
+ ASSERT(!obj->IsPermanentWorldObject());
+ CellCoord p = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY());
+ if (!p.IsCoordValid())
+ {
+ TC_LOG_ERROR(LOG_FILTER_MAPS, "Map::SwitchGridContainers: Object " UI64FMTD " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord);
+ return;
+ }
+
+ Cell cell(p);
+ if (!IsGridLoaded(GridCoord(cell.data.Part.grid_x, cell.data.Part.grid_y)))
+ return;
+
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "Switch object " UI64FMTD " from grid[%u, %u] %u", obj->GetGUID(), cell.data.Part.grid_x, cell.data.Part.grid_y, on);
+ NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY());
+ ASSERT(ngrid != NULL);
+
+ GridType &grid = ngrid->GetGridType(cell.CellX(), cell.CellY());
+
+ obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add
+
+ if (on)
+ {
+ grid.AddWorldObject(obj);
+ AddWorldObject(obj);
+ }
+ else
+ {
+ grid.AddGridObject(obj);
+ RemoveWorldObject(obj);
+ }
+}
+
template<class T>
void Map::DeleteFromWorld(T* obj)
{
@@ -432,11 +497,17 @@ void Map::InitializeObject(T* /*obj*/)
template<>
void Map::InitializeObject(Creature* obj)
{
- obj->_moveState = CREATURE_CELL_MOVE_NONE;
+ obj->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
+}
+
+template<>
+void Map::InitializeObject(GameObject* obj)
+{
+ obj->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
}
template<class T>
-bool Map::AddToMap(T *obj)
+bool Map::AddToMap(T* obj)
{
/// @todo Needs clean up. An object should not be added to map twice.
if (obj->IsInWorld())
@@ -480,6 +551,26 @@ bool Map::AddToMap(T *obj)
return true;
}
+template<>
+bool Map::AddToMap(Transport* obj)
+{
+ //TODO: Needs clean up. An object should not be added to map twice.
+ if (obj->IsInWorld())
+ return true;
+
+ CellCoord cellCoord = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY());
+ if (!cellCoord.IsCoordValid())
+ {
+ TC_LOG_ERROR(LOG_FILTER_MAPS, "Map::Add: Object " UI64FMTD " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), cellCoord.x_coord, cellCoord.y_coord);
+ return false; //Should delete object
+ }
+
+ obj->AddToWorld();
+ _transports.insert(obj);
+
+ return true;
+}
+
bool Map::IsGridLoaded(const GridCoord &p) const
{
return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord));
@@ -565,6 +656,17 @@ void Map::Update(const uint32 t_diff)
VisitNearbyCellsOf(obj, grid_object_update, world_object_update);
}
+ for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
+ {
+ WorldObject* obj = *_transportsUpdateIter;
+ ++_transportsUpdateIter;
+
+ if (!obj->IsInWorld())
+ continue;
+
+ obj->Update(t_diff);
+ }
+
///- Process necessary scripts
if (!m_scriptSchedule.empty())
{
@@ -574,6 +676,7 @@ void Map::Update(const uint32 t_diff)
}
MoveAllCreaturesInMoveList();
+ MoveAllGameObjectsInMoveList();
if (!m_mapRefManager.isEmpty() || !m_activeNonPlayers.empty())
ProcessRelocationNotifies(t_diff);
@@ -708,6 +811,34 @@ void Map::RemoveFromMap(T *obj, bool remove)
}
}
+template<>
+void Map::RemoveFromMap(Transport* obj, bool remove)
+{
+ obj->RemoveFromWorld();
+
+ if (_transportsUpdateIter != _transports.end())
+ {
+ TransportsContainer::iterator itr = _transports.find(obj);
+ if (itr == _transports.end())
+ return;
+ if (itr == _transportsUpdateIter)
+ ++_transportsUpdateIter;
+ _transports.erase(itr);
+ }
+ else
+ _transports.erase(obj);
+
+ obj->ResetMap();
+
+ if (remove)
+ {
+ // if option set then object already saved at this moment
+ if (!sWorld->getBoolConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY))
+ obj->SaveRespawnTime();
+ DeleteFromWorld(obj);
+ }
+}
+
void Map::PlayerRelocation(Player* player, float x, float y, float z, float orientation)
{
ASSERT(player);
@@ -777,12 +908,44 @@ void Map::CreatureRelocation(Creature* creature, float x, float y, float z, floa
ASSERT(CheckGridIntegrity(creature, true));
}
+void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float orientation, bool respawnRelocationOnFail)
+{
+ Cell integrity_check(go->GetPositionX(), go->GetPositionY());
+ Cell old_cell = go->GetCurrentCell();
+
+ ASSERT(integrity_check == old_cell);
+ Cell new_cell(x, y);
+
+ if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY()))
+ return;
+
+ // delay creature move for grid/cell to grid/cell moves
+ if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
+ {
+#ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) added to moving list from grid[%u, %u]cell[%u, %u] to grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
+#endif
+ AddGameObjectToMoveList(go, x, y, z, orientation);
+ // in diffcell/diffgrid case notifiers called at finishing move go in Map::MoveAllGameObjectsInMoveList
+ }
+ else
+ {
+ go->Relocate(x, y, z, orientation);
+ go->UpdateObjectVisibility(false);
+ RemoveGameObjectFromMoveList(go);
+ }
+
+ old_cell = go->GetCurrentCell();
+ integrity_check = Cell(go->GetPositionX(), go->GetPositionY());
+ ASSERT(integrity_check == old_cell);
+}
+
void Map::AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang)
{
if (_creatureToMoveLock) //can this happen?
return;
- if (c->_moveState == CREATURE_CELL_MOVE_NONE)
+ if (c->_moveState == MAP_OBJECT_CELL_MOVE_NONE)
_creaturesToMove.push_back(c);
c->SetNewCellPosition(x, y, z, ang);
}
@@ -792,8 +955,27 @@ void Map::RemoveCreatureFromMoveList(Creature* c)
if (_creatureToMoveLock) //can this happen?
return;
- if (c->_moveState == CREATURE_CELL_MOVE_ACTIVE)
- c->_moveState = CREATURE_CELL_MOVE_INACTIVE;
+ if (c->_moveState == MAP_OBJECT_CELL_MOVE_ACTIVE)
+ c->_moveState = MAP_OBJECT_CELL_MOVE_INACTIVE;
+}
+
+void Map::AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang)
+{
+ if (_gameObjectsToMoveLock) //can this happen?
+ return;
+
+ if (go->_moveState == MAP_OBJECT_CELL_MOVE_NONE)
+ _gameObjectsToMove.push_back(go);
+ go->SetNewCellPosition(x, y, z, ang);
+}
+
+void Map::RemoveGameObjectFromMoveList(GameObject* go)
+{
+ if (_gameObjectsToMoveLock) //can this happen?
+ return;
+
+ if (go->_moveState == MAP_OBJECT_CELL_MOVE_ACTIVE)
+ go->_moveState = MAP_OBJECT_CELL_MOVE_INACTIVE;
}
void Map::MoveAllCreaturesInMoveList()
@@ -805,13 +987,13 @@ void Map::MoveAllCreaturesInMoveList()
if (c->FindMap() != this) //pet is teleported to another map
continue;
- if (c->_moveState != CREATURE_CELL_MOVE_ACTIVE)
+ if (c->_moveState != MAP_OBJECT_CELL_MOVE_ACTIVE)
{
- c->_moveState = CREATURE_CELL_MOVE_NONE;
+ c->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
continue;
}
- c->_moveState = CREATURE_CELL_MOVE_NONE;
+ c->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
if (!c->IsInWorld())
continue;
@@ -852,6 +1034,50 @@ void Map::MoveAllCreaturesInMoveList()
_creatureToMoveLock = false;
}
+void Map::MoveAllGameObjectsInMoveList()
+{
+ _gameObjectsToMoveLock = true;
+ for (std::vector<GameObject*>::iterator itr = _gameObjectsToMove.begin(); itr != _gameObjectsToMove.end(); ++itr)
+ {
+ GameObject* go = *itr;
+ if (go->FindMap() != this) //transport is teleported to another map
+ continue;
+
+ if (go->_moveState != MAP_OBJECT_CELL_MOVE_ACTIVE)
+ {
+ go->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
+ continue;
+ }
+
+ go->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
+ if (!go->IsInWorld())
+ continue;
+
+ // do move or do move to respawn or remove creature if previous all fail
+ if (GameObjectCellRelocation(go, Cell(go->_newPosition.m_positionX, go->_newPosition.m_positionY)))
+ {
+ // update pos
+ go->Relocate(go->_newPosition);
+ go->UpdateObjectVisibility(false);
+ }
+ else
+ {
+ // if GameObject can't be move in new cell/grid (not loaded) move it to repawn cell/grid
+ // GameObject coordinates will be updated and notifiers send
+ if (!GameObjectRespawnRelocation(go, false))
+ {
+ // ... or unload (if respawn grid also not loaded)
+#ifdef TRINITY_DEBUG
+ sLog->outDebug(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) cannot be move to unloaded respawn grid.", go->GetGUIDLow(), go->GetEntry());
+#endif
+ AddObjectToRemoveList(go);
+ }
+ }
+ }
+ _gameObjectsToMove.clear();
+ _gameObjectsToMoveLock = false;
+}
+
bool Map::CreatureCellRelocation(Creature* c, Cell new_cell)
{
Cell const& old_cell = c->GetCurrentCell();
@@ -913,6 +1139,67 @@ bool Map::CreatureCellRelocation(Creature* c, Cell new_cell)
return false;
}
+bool Map::GameObjectCellRelocation(GameObject* go, Cell new_cell)
+{
+ Cell const& old_cell = go->GetCurrentCell();
+ if (!old_cell.DiffGrid(new_cell)) // in same grid
+ {
+ // if in same cell then none do
+ if (old_cell.DiffCell(new_cell))
+ {
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) moved in grid[%u, %u] from cell[%u, %u] to cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY());
+ #endif
+
+ go->RemoveFromGrid();
+ AddToGrid(go, new_cell);
+ }
+ else
+ {
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) moved in same grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY());
+ #endif
+ }
+
+ return true;
+ }
+
+ // in diff. grids but active GameObject
+ if (go->isActiveObject())
+ {
+ EnsureGridLoadedForActiveObject(new_cell, go);
+
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "Active GameObject (GUID: %u Entry: %u) moved from grid[%u, %u]cell[%u, %u] to grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
+ #endif
+
+ go->RemoveFromGrid();
+ AddToGrid(go, new_cell);
+
+ return true;
+ }
+
+ // in diff. loaded grid normal GameObject
+ if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY())))
+ {
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) moved from grid[%u, %u]cell[%u, %u] to grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
+ #endif
+
+ go->RemoveFromGrid();
+ EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY()));
+ AddToGrid(go, new_cell);
+
+ return true;
+ }
+
+ // fail to move: normal GameObject attempt move to unloaded grid
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) attempted to move from grid[%u, %u]cell[%u, %u] to unloaded grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
+ #endif
+ return false;
+}
+
bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly)
{
float resp_x, resp_y, resp_z, resp_o;
@@ -943,6 +1230,31 @@ bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly)
return false;
}
+bool Map::GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly)
+{
+ float resp_x, resp_y, resp_z, resp_o;
+ go->GetRespawnPosition(resp_x, resp_y, resp_z, &resp_o);
+ Cell resp_cell(resp_x, resp_y);
+
+ //GameObject will be unloaded with grid
+ if (diffGridOnly && !go->GetCurrentCell().DiffGrid(resp_cell))
+ return true;
+
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) moved from grid[%u, %u]cell[%u, %u] to respawn grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), go->GetCurrentCell().GridX(), go->GetCurrentCell().GridY(), go->GetCurrentCell().CellX(), go->GetCurrentCell().CellY(), resp_cell.GridX(), resp_cell.GridY(), resp_cell.CellX(), resp_cell.CellY());
+ #endif
+
+ // teleport it to respawn point (like normal respawn if player see)
+ if (GameObjectCellRelocation(go, resp_cell))
+ {
+ go->Relocate(resp_x, resp_y, resp_z, resp_o);
+ go->UpdateObjectVisibility(false);
+ return true;
+ }
+
+ return false;
+}
+
bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
{
const uint32 x = ngrid.getX();
@@ -966,6 +1278,7 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
// Finish creature moves, remove and delete all creatures with delayed remove before moving to respawn grids
// Must know real mob position before move
MoveAllCreaturesInMoveList();
+ MoveAllGameObjectsInMoveList();
// move creatures to respawn grids if this is diff.grid or to remove list
ObjectGridEvacuator worker;
@@ -974,6 +1287,7 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
// Finish creature moves, remove and delete all creatures with delayed remove before unload
MoveAllCreaturesInMoveList();
+ MoveAllGameObjectsInMoveList();
}
{
@@ -1041,6 +1355,7 @@ void Map::UnloadAll()
{
// clear all delayed moves, useless anyway do this moves before map unload.
_creaturesToMove.clear();
+ _gameObjectsToMove.clear();
for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end();)
{
@@ -2008,7 +2323,7 @@ void Map::SendInitSelf(Player* player)
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
if (Transport* transport = player->GetTransport())
{
- for (Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
+ for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
{
if (player != (*itr) && player->HaveAtClient(*itr))
{
@@ -2025,24 +2340,10 @@ void Map::SendInitSelf(Player* player)
void Map::SendInitTransports(Player* player)
{
// Hack to send out transports
- MapManager::TransportMap& tmap = sMapMgr->m_TransportsByMap;
-
- // no transports at map
- if (tmap.find(player->GetMapId()) == tmap.end())
- return;
-
UpdateData transData;
-
- MapManager::TransportSet& tset = tmap[player->GetMapId()];
-
- for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
- {
- // send data for current transport in other place
- if ((*i) != player->GetTransport() && (*i)->GetMapId() == GetId())
- {
+ for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
+ if (*i != player->GetTransport())
(*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
- }
- }
WorldPacket packet;
transData.BuildPacket(&packet);
@@ -2052,19 +2353,9 @@ void Map::SendInitTransports(Player* player)
void Map::SendRemoveTransports(Player* player)
{
// Hack to send out transports
- MapManager::TransportMap& tmap = sMapMgr->m_TransportsByMap;
-
- // no transports at map
- if (tmap.find(player->GetMapId()) == tmap.end())
- return;
-
UpdateData transData;
-
- MapManager::TransportSet& tset = tmap[player->GetMapId()];
-
- // except used transport
- for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
- if ((*i) != player->GetTransport() && (*i)->GetMapId() != GetId())
+ for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
+ if (*i != player->GetTransport())
(*i)->BuildOutOfRangeUpdateBlock(&transData);
WorldPacket packet;
@@ -2116,7 +2407,7 @@ void Map::AddObjectToSwitchList(WorldObject* obj, bool on)
ASSERT(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId());
// i_objectsToSwitch is iterated only in Map::RemoveAllObjectsInRemoveList() and it uses
// the contained objects only if GetTypeId() == TYPEID_UNIT , so we can return in all other cases
- if (obj->GetTypeId() != TYPEID_UNIT)
+ if (obj->GetTypeId() != TYPEID_UNIT && obj->GetTypeId() != TYPEID_GAMEOBJECT)
return;
std::map<WorldObject*, bool>::iterator itr = i_objectsToSwitch.find(obj);
@@ -2137,8 +2428,8 @@ void Map::RemoveAllObjectsInRemoveList()
bool on = itr->second;
i_objectsToSwitch.erase(itr);
- if (obj->GetTypeId() == TYPEID_UNIT && !obj->IsPermanentWorldObject())
- SwitchGridContainers(obj->ToCreature(), on);
+ if ((obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_GAMEOBJECT) && !obj->IsPermanentWorldObject())
+ SwitchGridContainers(obj, on);
}
//TC_LOG_DEBUG(LOG_FILTER_MAPS, "Object remover 1 check.");
@@ -2233,6 +2524,13 @@ bool Map::ActiveObjectsNearGrid(NGridType const& ngrid) const
return false;
}
+template<class T>
+void Map::AddToActive(T* obj)
+{
+ AddToActiveHelper(obj);
+}
+
+template <>
void Map::AddToActive(Creature* c)
{
AddToActiveHelper(c);
@@ -2254,6 +2552,18 @@ void Map::AddToActive(Creature* c)
}
}
+template<>
+void Map::AddToActive(DynamicObject* d)
+{
+ AddToActiveHelper(d);
+}
+
+template<class T>
+void Map::RemoveFromActive(T* /*obj*/)
+{
+}
+
+template <>
void Map::RemoveFromActive(Creature* c)
{
RemoveFromActiveHelper(c);
@@ -2275,6 +2585,12 @@ void Map::RemoveFromActive(Creature* c)
}
}
+template<>
+void Map::RemoveFromActive(DynamicObject* obj)
+{
+ RemoveFromActiveHelper(obj);
+}
+
template bool Map::AddToMap(Corpse*);
template bool Map::AddToMap(Creature*);
template bool Map::AddToMap(GameObject*);
@@ -2772,6 +3088,15 @@ GameObject* Map::GetGameObject(uint64 guid)
return ObjectAccessor::GetObjectInMap(guid, this, (GameObject*)NULL);
}
+Transport* Map::GetTransport(uint64 guid)
+{
+ if (GUID_HIPART(guid) != HIGHGUID_MO_TRANSPORT)
+ return NULL;
+
+ GameObject* go = GetGameObject(guid);
+ return go ? go->ToTransport() : NULL;
+}
+
DynamicObject* Map::GetDynamicObject(uint64 guid)
{
return ObjectAccessor::GetObjectInMap(guid, this, (DynamicObject*)NULL);
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 3deeb4e04b1..932f3e213ae 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -52,6 +52,7 @@ struct Position;
class Battleground;
class MapInstanced;
class InstanceMap;
+class Transport;
namespace Trinity { struct ObjectUpdater; }
struct ScriptAction
@@ -278,6 +279,7 @@ class Map : public GridRefManager<NGridType>
void PlayerRelocation(Player*, float x, float y, float z, float orientation);
void CreatureRelocation(Creature* creature, float x, float y, float z, float ang, bool respawnRelocationOnFail = true);
+ void GameObjectRelocation(GameObject* go, float x, float y, float z, float orientation, bool respawnRelocationOnFail = true);
template<class T, class CONTAINER> void Visit(const Cell& cell, TypeContainerVisitor<T, CONTAINER> &visitor);
@@ -350,11 +352,13 @@ class Map : public GridRefManager<NGridType>
}
void MoveAllCreaturesInMoveList();
+ void MoveAllGameObjectsInMoveList();
void RemoveAllObjectsInRemoveList();
virtual void RemoveAllPlayers();
// used only in MoveAllCreaturesInMoveList and ObjectGridUnloader
bool CreatureRespawnRelocation(Creature* c, bool diffGridOnly);
+ bool GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly);
// assert print helper
bool CheckGridIntegrity(Creature* c, bool moved) const;
@@ -415,17 +419,13 @@ class Map : public GridRefManager<NGridType>
// must called with AddToWorld
template<class T>
- void AddToActive(T* obj) { AddToActiveHelper(obj); }
-
- void AddToActive(Creature* obj);
+ void AddToActive(T* obj);
// must called with RemoveFromWorld
template<class T>
- void RemoveFromActive(T* obj) { RemoveFromActiveHelper(obj); }
-
- void RemoveFromActive(Creature* obj);
+ void RemoveFromActive(T* obj);
- void SwitchGridContainers(Creature* creature, bool toWorldContainer);
+ template<class T> void SwitchGridContainers(T* obj, bool on);
template<class NOTIFIER> void VisitAll(const float &x, const float &y, float radius, NOTIFIER &notifier);
template<class NOTIFIER> void VisitFirstFound(const float &x, const float &y, float radius, NOTIFIER &notifier);
template<class NOTIFIER> void VisitWorld(const float &x, const float &y, float radius, NOTIFIER &notifier);
@@ -438,6 +438,7 @@ class Map : public GridRefManager<NGridType>
void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = NULL);
Creature* GetCreature(uint64 guid);
GameObject* GetGameObject(uint64 guid);
+ Transport* GetTransport(uint64 guid);
DynamicObject* GetDynamicObject(uint64 guid);
MapInstanced* ToMapInstanced(){ if (Instanceable()) return reinterpret_cast<MapInstanced*>(this); else return NULL; }
@@ -485,6 +486,9 @@ class Map : public GridRefManager<NGridType>
static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId);
+ void SendInitTransports(Player* player);
+ void SendRemoveTransports(Player* player);
+
private:
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
@@ -496,18 +500,21 @@ class Map : public GridRefManager<NGridType>
void SendInitSelf(Player* player);
- void SendInitTransports(Player* player);
- void SendRemoveTransports(Player* player);
-
bool CreatureCellRelocation(Creature* creature, Cell new_cell);
+ bool GameObjectCellRelocation(GameObject* go, Cell new_cell);
template<class T> void InitializeObject(T* obj);
void AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang);
void RemoveCreatureFromMoveList(Creature* c);
+ void AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang);
+ void RemoveGameObjectFromMoveList(GameObject* go);
bool _creatureToMoveLock;
std::vector<Creature*> _creaturesToMove;
+ bool _gameObjectsToMoveLock;
+ std::vector<GameObject*> _gameObjectsToMove;
+
bool IsGridLoaded(const GridCoord &) const;
void EnsureGridCreated(const GridCoord &);
void EnsureGridCreated_i(const GridCoord &);
@@ -516,9 +523,6 @@ class Map : public GridRefManager<NGridType>
void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); }
- template<class T> void AddType(T *obj);
- template<class T> void RemoveType(T *obj, bool);
-
NGridType* getNGrid(uint32 x, uint32 y) const
{
ASSERT(x < MAX_NUMBER_OF_GRIDS && y < MAX_NUMBER_OF_GRIDS);
@@ -555,6 +559,11 @@ class Map : public GridRefManager<NGridType>
ActiveNonPlayers m_activeNonPlayers;
ActiveNonPlayers::iterator m_activeNonPlayersIter;
+ // Objects that must update even in inactive grids without activating them
+ typedef std::set<Transport*> TransportsContainer;
+ TransportsContainer _transports;
+ TransportsContainer::iterator _transportsUpdateIter;
+
private:
Player* _GetScriptPlayerSourceOrTarget(Object* source, Object* target, const ScriptInfo* scriptInfo) const;
Creature* _GetScriptCreatureSourceOrTarget(Object* source, Object* target, const ScriptInfo* scriptInfo, bool bReverse = false) const;
@@ -589,19 +598,17 @@ class Map : public GridRefManager<NGridType>
// Type specific code for add/remove to/from grid
template<class T>
- void AddToGrid(T* object, Cell const& cell);
+ void AddToGrid(T* object, Cell const& cell);
template<class T>
- void DeleteFromWorld(T*);
+ void DeleteFromWorld(T*);
- template<class T>
- void AddToActiveHelper(T* obj)
+ void AddToActiveHelper(WorldObject* obj)
{
m_activeNonPlayers.insert(obj);
}
- template<class T>
- void RemoveFromActiveHelper(T* obj)
+ void RemoveFromActiveHelper(WorldObject* obj)
{
// Map::Update for active object in proccess
if (m_activeNonPlayersIter != m_activeNonPlayers.end())
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 60ebd3f8699..5aa8b85fbca 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -292,8 +292,6 @@ void MapManager::Update(uint32 diff)
iter->second->DelayedUpdate(uint32(i_timer.GetCurrent()));
sObjectAccessor->Update(uint32(i_timer.GetCurrent()));
- for (TransportSet::iterator itr = m_Transports.begin(); itr != m_Transports.end(); ++itr)
- (*itr)->Update(uint32(i_timer.GetCurrent()));
i_timer.SetCurrent(0);
}
@@ -326,12 +324,6 @@ bool MapManager::IsValidMAP(uint32 mapid, bool startUp)
void MapManager::UnloadAll()
{
- for (TransportSet::iterator i = m_Transports.begin(); i != m_Transports.end(); ++i)
- {
- (*i)->RemoveFromWorld();
- delete *i;
- }
-
for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end();)
{
iter->second->UnloadAll();
diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h
index 8af609c61e2..230b4648f4a 100644
--- a/src/server/game/Maps/MapManager.h
+++ b/src/server/game/Maps/MapManager.h
@@ -107,15 +107,6 @@ class MapManager
void DoDelayedMovesAndRemoves();
- void LoadTransports();
- void LoadTransportNPCs();
-
- typedef std::set<Transport*> TransportSet;
- TransportSet m_Transports;
-
- typedef std::map<uint32, TransportSet> TransportMap;
- TransportMap m_TransportsByMap;
-
bool CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck = false);
void InitializeVisibilityDistanceInfo();
diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp
new file mode 100644
index 00000000000..bd79cd793d5
--- /dev/null
+++ b/src/server/game/Maps/TransportMgr.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2008-2012 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 "TransportMgr.h"
+#include "Transport.h"
+#include "InstanceScript.h"
+#include "MoveSpline.h"
+#include "MapManager.h"
+
+TransportTemplate::~TransportTemplate()
+{
+ // Collect shared pointers into a set to avoid deleting the same memory more than once
+ std::set<TransportSpline*> splines;
+ for (size_t i = 0; i < keyFrames.size(); ++i)
+ splines.insert(keyFrames[i].Spline);
+
+ for (std::set<TransportSpline*>::iterator itr = splines.begin(); itr != splines.end(); ++itr)
+ delete *itr;
+}
+
+TransportMgr::TransportMgr()
+{
+}
+
+TransportMgr::~TransportMgr()
+{
+}
+
+void TransportMgr::Unload()
+{
+ _transportTemplates.clear();
+}
+
+void TransportMgr::LoadTransportTemplates()
+{
+ uint32 oldMSTime = getMSTime();
+
+ QueryResult result = WorldDatabase.Query("SELECT entry FROM gameobject_template WHERE type = 15 ORDER BY entry ASC");
+
+ if (!result)
+ {
+ TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 transport templates. DB table `gameobject_template` has no transports!");
+ return;
+ }
+
+ uint32 count = 0;
+
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 entry = fields[0].GetUInt32();
+ GameObjectTemplate const* goInfo = sObjectMgr->GetGameObjectTemplate(entry);
+ if (goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size())
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Transport %u (name: %s) has an invalid path specified in `gameobject_template`.`data0` (%u) field, skipped.", entry, goInfo->name.c_str(), goInfo->moTransport.taxiPathId);
+ continue;
+ }
+
+ // paths are generated per template, saves us from generating it again in case of instanced transports
+ TransportTemplate& transport = _transportTemplates[entry];
+ transport.entry = entry;
+ GeneratePath(goInfo, &transport);
+
+ // transports in instance are only on one map
+ if (transport.inInstance)
+ _instanceTransports[*transport.mapsUsed.begin()].insert(entry);
+
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded %u transport templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport)
+{
+ uint32 pathId = goInfo->moTransport.taxiPathId;
+ TaxiPathNodeList const& path = sTaxiPathNodesByPath[pathId];
+ std::vector<KeyFrame>& keyFrames = transport->keyFrames;
+ Movement::PointsArray splinePath;
+ bool mapChange = false;
+ bool cyclic = true;
+ for (size_t i = 1; i < path.size() - 1; ++i)
+ {
+ if (!mapChange)
+ {
+ TaxiPathNodeEntry const& node_i = path[i];
+ if (node_i.actionFlag == 1 || node_i.mapid != path[i + 1].mapid)
+ {
+ cyclic = false;
+ keyFrames.back().Teleport = true;
+ mapChange = true;
+ }
+ else
+ {
+ KeyFrame k(node_i);
+ keyFrames.push_back(k);
+ splinePath.push_back(G3D::Vector3(node_i.x, node_i.y, node_i.z));
+ transport->mapsUsed.insert(k.Node->mapid);
+ }
+ }
+ else
+ mapChange = false;
+ }
+
+ if (transport->mapsUsed.size() > 1)
+ {
+ for (std::set<uint32>::const_iterator itr = transport->mapsUsed.begin(); itr != transport->mapsUsed.end(); ++itr)
+ ASSERT(!sMapStore.LookupEntry(*itr)->Instanceable());
+
+ transport->inInstance = false;
+ }
+ else
+ transport->inInstance = sMapStore.LookupEntry(*transport->mapsUsed.begin())->Instanceable();
+
+ // last to first is always "teleport", even for closed paths
+ keyFrames.back().Teleport = true;
+
+ const float speed = float(goInfo->moTransport.moveSpeed);
+ const float accel = float(goInfo->moTransport.accelRate);
+ const float accel_dist = 0.5f * speed * speed / accel;
+
+ transport->accelTime = speed / accel;
+ transport->accelDist = accel_dist;
+
+ int32 firstStop = -1;
+ int32 lastStop = -1;
+
+ // first cell is arrived at by teleportation :S
+ keyFrames[0].DistFromPrev = 0;
+ keyFrames[0].Index = 1;
+ if (keyFrames[0].IsStopFrame())
+ {
+ firstStop = 0;
+ lastStop = 0;
+ }
+
+ // find the rest of the distances between key points
+ // Every path segment has its own spline
+ if (cyclic)
+ {
+ TransportSpline* spline = new TransportSpline();
+ spline->init_cyclic_spline(&splinePath[0], splinePath.size(), Movement::SplineBase::ModeCatmullrom, 0);
+ spline->initLengths();
+ keyFrames[0].DistFromPrev = spline->length(spline->last() - 2, spline->last() - 1);
+ keyFrames[0].Spline = spline;
+ for (size_t i = 1; i < keyFrames.size(); ++i)
+ {
+ keyFrames[i].Index = i + 1;
+ keyFrames[i].DistFromPrev = spline->length(i, i + 1);
+ keyFrames[i - 1].NextDistFromPrev = keyFrames[i].DistFromPrev;
+ keyFrames[i].Spline = spline;
+ if (keyFrames[i].IsStopFrame())
+ {
+ // remember first stop frame
+ if (firstStop == -1)
+ firstStop = i;
+ lastStop = i;
+ }
+ }
+ }
+ else
+ {
+ size_t start = 0;
+ for (size_t i = 1; i < keyFrames.size(); ++i)
+ {
+ if (keyFrames[i - 1].Teleport || i + 1 == keyFrames.size())
+ {
+ size_t extra = !keyFrames[i - 1].Teleport ? 1 : 0;
+ TransportSpline* spline = new TransportSpline();
+ spline->init_spline(&splinePath[start], i - start + extra, Movement::SplineBase::ModeCatmullrom);
+ spline->initLengths();
+ for (size_t j = start; j < i + extra; ++j)
+ {
+ keyFrames[j].Index = j - start + 1;
+ keyFrames[j].DistFromPrev = spline->length(j - start, j + 1 - start);
+ if (j > 0)
+ keyFrames[j - 1].NextDistFromPrev = keyFrames[j].DistFromPrev;
+ keyFrames[j].Spline = spline;
+ }
+
+ if (keyFrames[i - 1].Teleport)
+ {
+ keyFrames[i].Index = i - start + 1;
+ keyFrames[i].DistFromPrev = 0.0f;
+ keyFrames[i - 1].NextDistFromPrev = 0.0f;
+ keyFrames[i].Spline = spline;
+ }
+
+ start = i;
+ }
+
+ if (keyFrames[i].IsStopFrame())
+ {
+ // remember first stop frame
+ if (firstStop == -1)
+ firstStop = i;
+ lastStop = i;
+ }
+ }
+ }
+
+ keyFrames.back().NextDistFromPrev = keyFrames.front().DistFromPrev;
+
+ // at stopping keyframes, we define distSinceStop == 0,
+ // and distUntilStop is to the next stopping keyframe.
+ // this is required to properly handle cases of two stopping frames in a row (yes they do exist)
+ float tmpDist = 0.0f;
+ for (size_t i = 0; i < keyFrames.size(); ++i)
+ {
+ int32 j = (i + lastStop) % keyFrames.size();
+ if (keyFrames[j].IsStopFrame())
+ tmpDist = 0.0f;
+ else
+ tmpDist += keyFrames[j].DistFromPrev;
+ keyFrames[j].DistSinceStop = tmpDist;
+ }
+
+ tmpDist = 0.0f;
+ for (int32 i = int32(keyFrames.size()) - 1; i >= 0; i--)
+ {
+ int32 j = (i + firstStop) % keyFrames.size();
+ tmpDist += keyFrames[(j + 1) % keyFrames.size()].DistFromPrev;
+ keyFrames[j].DistUntilStop = tmpDist;
+ if (keyFrames[j].IsStopFrame())
+ tmpDist = 0.0f;
+ }
+
+ for (size_t i = 0; i < keyFrames.size(); ++i)
+ {
+ float total_dist = keyFrames[i].DistSinceStop + keyFrames[i].DistUntilStop;
+ if (total_dist < 2 * accel_dist) // won't reach full speed
+ {
+ if (keyFrames[i].DistSinceStop < keyFrames[i].DistUntilStop) // is still accelerating
+ {
+ // calculate accel+brake time for this short segment
+ float segment_time = 2.0f * sqrt((keyFrames[i].DistUntilStop + keyFrames[i].DistSinceStop) / accel);
+ // substract acceleration time
+ keyFrames[i].TimeTo = segment_time - sqrt(2 * keyFrames[i].DistSinceStop / accel);
+ }
+ else // slowing down
+ keyFrames[i].TimeTo = sqrt(2 * keyFrames[i].DistUntilStop / accel);
+ }
+ else if (keyFrames[i].DistSinceStop < accel_dist) // still accelerating (but will reach full speed)
+ {
+ // calculate accel + cruise + brake time for this long segment
+ float segment_time = (keyFrames[i].DistUntilStop + keyFrames[i].DistSinceStop) / speed + (speed / accel);
+ // substract acceleration time
+ keyFrames[i].TimeTo = segment_time - sqrt(2 * keyFrames[i].DistSinceStop / accel);
+ }
+ else if (keyFrames[i].DistUntilStop < accel_dist) // already slowing down (but reached full speed)
+ keyFrames[i].TimeTo = sqrt(2 * keyFrames[i].DistUntilStop / accel);
+ else // at full speed
+ keyFrames[i].TimeTo = (keyFrames[i].DistUntilStop / speed) + (0.5f * speed / accel);
+ }
+
+ // calculate tFrom times from tTo times
+ float segmentTime = 0.0f;
+ for (size_t i = 0; i < keyFrames.size(); ++i)
+ {
+ int32 j = (i + lastStop) % keyFrames.size();
+ if (keyFrames[j].IsStopFrame())
+ segmentTime = keyFrames[j].TimeTo;
+ keyFrames[j].TimeFrom = segmentTime - keyFrames[j].TimeTo;
+ }
+
+ // calculate path times
+ keyFrames[0].ArriveTime = 0;
+ float curPathTime = 0.0f;
+ if (keyFrames[0].IsStopFrame())
+ {
+ curPathTime = float(keyFrames[0].Node->delay);
+ keyFrames[0].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
+ }
+
+ for (size_t i = 1; i < keyFrames.size(); ++i)
+ {
+ curPathTime += keyFrames[i-1].TimeTo;
+ if (keyFrames[i].IsStopFrame())
+ {
+ keyFrames[i].ArriveTime = uint32(curPathTime * IN_MILLISECONDS);
+ keyFrames[i - 1].NextArriveTime = keyFrames[i].ArriveTime;
+ curPathTime += (float)keyFrames[i].Node->delay;
+ keyFrames[i].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
+ }
+ else
+ {
+ curPathTime -= keyFrames[i].TimeTo;
+ keyFrames[i].ArriveTime = uint32(curPathTime * IN_MILLISECONDS);
+ keyFrames[i - 1].NextArriveTime = keyFrames[i].ArriveTime;
+ keyFrames[i].DepartureTime = keyFrames[i].ArriveTime;
+ }
+ }
+ keyFrames.back().NextArriveTime = keyFrames.back().DepartureTime;
+
+ transport->pathTime = keyFrames.back().DepartureTime;
+ //WorldDatabase.DirectPExecute("UPDATE `transports` SET `period_gen`=%u WHERE `entry`=%u", transport->pathTime, transport->entry);
+}
+
+void TransportMgr::AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, TransportAnimationEntry const* node)
+{
+ TransportAnimation& animNode = _transportAnimations[transportEntry];
+ if (animNode.TotalTime < timeSeg)
+ animNode.TotalTime = timeSeg;
+
+ animNode.Path[timeSeg] = node;
+}
+
+Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map* map /*= NULL*/)
+{
+ // instance case, execute GetGameObjectEntry hook
+ if (map)
+ {
+ // SetZoneScript() is called after adding to map, so fetch the script using map
+ if (map->IsDungeon())
+ if (InstanceScript* instance = static_cast<InstanceMap*>(map)->GetInstanceScript())
+ entry = instance->GetGameObjectEntry(0, entry);
+
+ if (!entry)
+ return NULL;
+ }
+
+ TransportTemplate const* tInfo = GetTransportTemplate(entry);
+ if (!tInfo)
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Transport %u will not be loaded, `transport_template` missing", entry);
+ return NULL;
+ }
+
+ // create transport...
+ Transport* trans = new Transport();
+
+ // ...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;
+ float o = 0.0f;
+
+ // initialize the gameobject base
+ uint32 guidLow = guid ? guid : sObjectMgr->GenerateLowGuid(HIGHGUID_MO_TRANSPORT);
+ if (!trans->Create(guidLow, entry, mapId, x, y, z, o, 255))
+ {
+ delete trans;
+ return NULL;
+ }
+
+ if (MapEntry const* mapEntry = sMapStore.LookupEntry(mapId))
+ {
+ if (mapEntry->Instanceable() != tInfo->inInstance)
+ {
+ TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Transport %u (name: %s) attempted creation in instance map (id: %u) but it is not an instanced transport!", entry, trans->GetName().c_str(), mapId);
+ delete trans;
+ return NULL;
+ }
+ }
+
+ // use preset map for instances (need to know which instance)
+ trans->SetMap(map ? map : sMapMgr->CreateMap(mapId, NULL));
+ if (map && map->IsDungeon())
+ trans->m_zoneScript = map->ToInstanceMap()->GetInstanceScript();
+
+ // Passengers will be loaded once a player is near
+
+ trans->GetMap()->AddToMap<Transport>(trans);
+ return trans;
+}
+
+void TransportMgr::SpawnContinentTransports()
+{
+ if (_transportTemplates.empty())
+ return;
+
+ uint32 oldMSTime = getMSTime();
+
+ QueryResult result = WorldDatabase.Query("SELECT guid, entry FROM transports");
+
+ uint32 count = 0;
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 guid = fields[0].GetUInt32();
+ uint32 entry = fields[1].GetUInt32();
+
+ if (TransportTemplate const* tInfo = GetTransportTemplate(entry))
+ if (!tInfo->inInstance)
+ if (CreateTransport(entry, guid))
+ ++count;
+
+ } while (result->NextRow());
+ }
+
+ TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Spawned %u continent transports in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void TransportMgr::CreateInstanceTransports(Map* map)
+{
+ TransportInstanceMap::const_iterator mapTransports = _instanceTransports.find(map->GetId());
+
+ // no transports here
+ if (mapTransports == _instanceTransports.end() || mapTransports->second.empty())
+ return;
+
+ // create transports
+ for (std::set<uint32>::const_iterator itr = mapTransports->second.begin(); itr != mapTransports->second.end(); ++itr)
+ CreateTransport(*itr, 0, map);
+}
+
+TransportAnimationEntry const* TransportAnimation::GetAnimNode(uint32 time) const
+{
+ if (Path.empty())
+ return NULL;
+
+ for (TransportPathContainer::const_reverse_iterator itr2 = Path.rbegin(); itr2 != Path.rend(); ++itr2)
+ if (time >= itr2->first)
+ return itr2->second;
+
+ return Path.begin()->second;
+}
+
+G3D::Quat TransportAnimation::GetAnimRotation(uint32 time) const
+{
+ if (Rotations.empty())
+ return G3D::Quat(0.0f, 0.0f, 0.0f, 1.0f);
+
+ TransportRotationEntry const* rot = Rotations.begin()->second;
+ for (TransportPathRotationContainer::const_reverse_iterator itr2 = Rotations.rbegin(); itr2 != Rotations.rend(); ++itr2)
+ {
+ if (time >= itr2->first)
+ {
+ rot = itr2->second;
+ break;
+ }
+ }
+
+ return G3D::Quat(rot->X, rot->Y, rot->Z, rot->W);
+}
diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h
new file mode 100644
index 00000000000..250a2c50bb1
--- /dev/null
+++ b/src/server/game/Maps/TransportMgr.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2008-2012 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 TRANSPORTMGR_H
+#define TRANSPORTMGR_H
+
+#include <ace/Singleton.h>
+#include <G3D/Quat.h>
+#include "Spline.h"
+#include "DBCStores.h"
+
+struct KeyFrame;
+struct GameObjectTemplate;
+struct TransportTemplate;
+class Transport;
+class Map;
+
+typedef Movement::Spline<double> TransportSpline;
+typedef std::vector<KeyFrame> KeyFrameVec;
+typedef UNORDERED_MAP<uint32, TransportTemplate> TransportTemplates;
+typedef std::set<Transport*> TransportSet;
+typedef UNORDERED_MAP<uint32, TransportSet> TransportMap;
+typedef UNORDERED_MAP<uint32, std::set<uint32> > TransportInstanceMap;
+
+struct KeyFrame
+{
+ explicit KeyFrame(TaxiPathNodeEntry const& _node) : Node(&_node),
+ DistSinceStop(-1.0f), DistUntilStop(-1.0f), DistFromPrev(-1.0f), TimeFrom(0.0f), TimeTo(0.0f),
+ Teleport(false), ArriveTime(0), DepartureTime(0), Spline(NULL), NextDistFromPrev(0.0f), NextArriveTime(0)
+ {
+ }
+
+ uint32 Index;
+ TaxiPathNodeEntry const* Node;
+ float DistSinceStop;
+ float DistUntilStop;
+ float DistFromPrev;
+ float TimeFrom;
+ float TimeTo;
+ bool Teleport;
+ uint32 ArriveTime;
+ uint32 DepartureTime;
+ TransportSpline* Spline;
+
+ // Data needed for next frame
+ float NextDistFromPrev;
+ uint32 NextArriveTime;
+
+ bool IsTeleportFrame() const { return Teleport; }
+ bool IsStopFrame() const { return Node->actionFlag == 2; }
+};
+
+struct TransportTemplate
+{
+ TransportTemplate() : pathTime(0), accelTime(0.0f), accelDist(0.0f) { }
+ ~TransportTemplate();
+
+ std::set<uint32> mapsUsed;
+ bool inInstance;
+ uint32 pathTime;
+ KeyFrameVec keyFrames;
+ float accelTime;
+ float accelDist;
+ uint32 entry;
+};
+
+typedef std::map<uint32, TransportAnimationEntry const*> TransportPathContainer;
+typedef std::map<uint32, TransportRotationEntry const*> TransportPathRotationContainer;
+
+struct TransportAnimation
+{
+ TransportPathContainer Path;
+ TransportPathRotationContainer Rotations;
+ uint32 TotalTime;
+
+ TransportAnimationEntry const* GetAnimNode(uint32 time) const;
+ G3D::Quat GetAnimRotation(uint32 time) const;
+};
+
+typedef std::map<uint32, TransportAnimation> TransportAnimationContainer;
+
+class TransportMgr
+{
+ friend class ACE_Singleton<TransportMgr, ACE_Thread_Mutex>;
+ friend void LoadDBCStores(std::string const&);
+
+ public:
+ void Unload();
+
+ void LoadTransportTemplates();
+
+ // Creates a transport using given GameObject template entry
+ Transport* CreateTransport(uint32 entry, uint32 guid = 0, Map* map = NULL);
+
+ // Spawns all continent transports, used at core startup
+ void SpawnContinentTransports();
+
+ // creates all transports for instance
+ void CreateInstanceTransports(Map* map);
+
+ TransportTemplate const* GetTransportTemplate(uint32 entry) const
+ {
+ TransportTemplates::const_iterator itr = _transportTemplates.find(entry);
+ if (itr != _transportTemplates.end())
+ return &itr->second;
+ return NULL;
+ }
+
+ TransportAnimation const* GetTransportAnimInfo(uint32 entry) const
+ {
+ TransportAnimationContainer::const_iterator itr = _transportAnimations.find(entry);
+ if (itr != _transportAnimations.end())
+ return &itr->second;
+
+ return NULL;
+ }
+
+ private:
+ TransportMgr();
+ ~TransportMgr();
+ TransportMgr(TransportMgr const&);
+ TransportMgr& operator=(TransportMgr const&);
+
+ // Generates and precaches a path for transport to avoid generation each time transport instance is created
+ void GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport);
+
+ void AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, TransportAnimationEntry const* node);
+
+ void AddPathRotationToTransport(uint32 transportEntry, uint32 timeSeg, TransportRotationEntry const* node)
+ {
+ _transportAnimations[transportEntry].Rotations[timeSeg] = node;
+ }
+
+ // Container storing transport templates
+ TransportTemplates _transportTemplates;
+
+ // Container storing transport entries to create for instanced maps
+ TransportInstanceMap _instanceTransports;
+
+ TransportAnimationContainer _transportAnimations;
+};
+
+#define sTransportMgr ACE_Singleton<TransportMgr, ACE_Thread_Mutex>::instance()
+
+#endif // TRANSPORTMGR_H
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index c50db983845..327d7ed69fd 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -104,7 +104,7 @@ enum TrinityStrings
LANG_RBAC_PERM_REVOKED = 78,
LANG_RBAC_PERM_REVOKED_NOT_IN_LIST = 79,
// Free 80 - 95
-
+
LANG_GUILD_RENAME_ALREADY_EXISTS = 96,
LANG_GUILD_RENAME_DONE = 97,
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index e561d37ed36..02f5965836f 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -1495,7 +1495,8 @@ enum GameObjectDynamicLowFlags
GO_DYNFLAG_LO_ACTIVATE = 0x01, // enables interaction with GO
GO_DYNFLAG_LO_ANIMATE = 0x02, // possibly more distinct animation of GO
GO_DYNFLAG_LO_NO_INTERACT = 0x04, // appears to disable interaction (not fully verified)
- GO_DYNFLAG_LO_SPARKLE = 0x08 // makes GO sparkle
+ GO_DYNFLAG_LO_SPARKLE = 0x08, // makes GO sparkle
+ GO_DYNFLAG_LO_STOPPED = 0x10 // Transport is stopped
};
enum GameObjectDestructibleState
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 6311e629641..5506f74b221 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -20,6 +20,7 @@
//Extended headers
#include "ObjectMgr.h"
#include "World.h"
+#include "Transport.h"
//Flightmaster grid preloading
#include "MapManager.h"
//Creature-specific headers
@@ -92,14 +93,37 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
{
if (!i_path || i_path->empty())
return false;
+
if (Stopped())
return true;
+ bool transportPath = creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && creature->GetTransGUID();
+
if (m_isArrivalDone)
{
if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
{
- creature->SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature->GetOrientation());
+ float x = i_path->at(i_currentNode)->x;
+ float y = i_path->at(i_currentNode)->y;
+ float z = i_path->at(i_currentNode)->z;
+ float o = creature->GetOrientation();
+
+ if (!transportPath)
+ creature->SetHomePosition(x, y, z, o);
+ else
+ {
+ if (Transport* trans = creature->GetTransport())
+ {
+ o -= trans->GetOrientation();
+ creature->SetTransportHomePosition(x, y, z, o);
+ trans->CalculatePassengerPosition(x, y, z, &o);
+ creature->SetHomePosition(x, y, z, o);
+ }
+ else
+ transportPath = false;
+ // else if (vehicle) - this should never happen, vehicle offsets are const
+ }
+
creature->GetMotionMaster()->Initialize();
return false;
}
@@ -113,7 +137,19 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
+ Movement::Location formationDest(node->x, node->y, node->z, 0.0f);
Movement::MoveSplineInit init(creature);
+
+ //! If creature is on transport, we assume waypoints set in DB are already transport offsets
+ if (transportPath)
+ {
+ init.DisableTransportPathTransformations();
+ if (TransportBase* trans = creature->GetDirectTransport())
+ trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
+ }
+
+ //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
+ //! but formationDest contains global coordinates
init.MoveTo(node->x, node->y, node->z);
//! Accepts angles such as 0.00001 and -0.00001, 0 must be ignored, default value in waypoint table
@@ -125,7 +161,7 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
//Call for creature group update
if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
- creature->GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
+ creature->GetFormation()->LeaderMoveTo(formationDest.x, formationDest.y, formationDest.z);
return true;
}
diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Scripting/MapScripts.cpp
index c37cdf80730..ff133272724 100644
--- a/src/server/game/Scripting/MapScripts.cpp
+++ b/src/server/game/Scripting/MapScripts.cpp
@@ -315,6 +315,7 @@ void Map::ScriptsProcess()
case HIGHGUID_PLAYER:
source = HashMapHolder<Player>::Find(step.sourceGUID);
break;
+ case HIGHGUID_TRANSPORT:
case HIGHGUID_GAMEOBJECT:
source = HashMapHolder<GameObject>::Find(step.sourceGUID);
break;
@@ -322,15 +323,11 @@ void Map::ScriptsProcess()
source = HashMapHolder<Corpse>::Find(step.sourceGUID);
break;
case HIGHGUID_MO_TRANSPORT:
- for (MapManager::TransportSet::iterator itr2 = sMapMgr->m_Transports.begin(); itr2 != sMapMgr->m_Transports.end(); ++itr2)
- {
- if ((*itr2)->GetGUID() == step.sourceGUID)
- {
- source = *itr2;
- break;
- }
- }
+ {
+ GameObject* go = HashMapHolder<GameObject>::Find(step.sourceGUID);
+ source = go ? go->ToTransport() : NULL;
break;
+ }
default:
TC_LOG_ERROR(LOG_FILTER_TSCR, "%s source with unsupported high guid (GUID: " UI64FMTD ", high guid: %u).",
step.script->GetDebugInfo().c_str(), step.sourceGUID, GUID_HIPART(step.sourceGUID));
@@ -353,12 +350,19 @@ void Map::ScriptsProcess()
case HIGHGUID_PLAYER: // empty GUID case also
target = HashMapHolder<Player>::Find(step.targetGUID);
break;
+ case HIGHGUID_TRANSPORT:
case HIGHGUID_GAMEOBJECT:
target = HashMapHolder<GameObject>::Find(step.targetGUID);
break;
case HIGHGUID_CORPSE:
target = HashMapHolder<Corpse>::Find(step.targetGUID);
break;
+ case HIGHGUID_MO_TRANSPORT:
+ {
+ GameObject* go = HashMapHolder<GameObject>::Find(step.targetGUID);
+ target = go ? go->ToTransport() : NULL;
+ break;
+ }
default:
TC_LOG_ERROR(LOG_FILTER_TSCR, "%s target with unsupported high guid (GUID: " UI64FMTD ", high guid: %u).",
step.script->GetDebugInfo().c_str(), step.targetGUID, GUID_HIPART(step.targetGUID));
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 966b3edfcb9..26b3bb5f78f 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -1363,6 +1363,16 @@ void ScriptMgr::OnGroupDisband(Group* group)
}
// Unit
+void ScriptMgr::OnHeal(Unit* healer, Unit* reciever, uint32& gain)
+{
+ FOREACH_SCRIPT(UnitScript)->OnHeal(healer, reciever, gain);
+}
+
+void ScriptMgr::OnDamage(Unit* attacker, Unit* victim, uint32& damage)
+{
+ FOREACH_SCRIPT(UnitScript)->OnDamage(attacker, victim, damage);
+}
+
void ScriptMgr::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage)
{
FOREACH_SCRIPT(UnitScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage);
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index e7946501616..37a95c77254 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -396,6 +396,12 @@ class UnitScript : public ScriptObject
UnitScript(const char* name, bool addToScripts = true);
public:
+ // Called when a unit deals healing to another unit
+ virtual void OnHeal(Unit* /*healer*/, Unit* /*reciever*/, uint32& /*gain*/) { }
+
+ // Called when a unit deals damage to another unit
+ virtual void OnDamage(Unit* /*attacker*/, Unit* /*victim*/, uint32& /*damage*/) { }
+
// Called when DoT's Tick Damage is being Dealt
virtual void ModifyPeriodicDamageAurasTick(Unit* /*target*/, Unit* /*attacker*/, uint32& /*damage*/) { }
@@ -1054,6 +1060,8 @@ class ScriptMgr
public: /* UnitScript */
+ void OnHeal(Unit* healer, Unit* reciever, uint32& gain);
+ void OnDamage(Unit* attacker, Unit* victim, uint32& damage);
void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage);
void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage);
void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage);
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index c60b09438c1..c33c12ae5d4 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -272,6 +272,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
//! delayed packets that were re-enqueued due to improper timing. To prevent an infinite
//! loop caused by re-enqueueing the same packets over and over again, we stop updating this session
//! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session.
+ uint32 processedPackets = 0;
+
while (m_Socket && !m_Socket->IsClosed() &&
!_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket &&
_recvQueue.next(packet, updater))
@@ -383,6 +385,14 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
delete packet;
deletePacket = true;
+
+#define MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE 100
+ processedPackets++;
+
+ //process only a max amout of packets in 1 Update() call.
+ //Any leftover will be processed in next update
+ if (processedPackets > MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE)
+ break;
}
if (m_Socket && !m_Socket->IsClosed() && _warden)
@@ -786,10 +796,6 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi)
if (mi->HasExtraMovementFlag(MOVEMENTFLAG2_INTERPOLATED_MOVEMENT))
data >> mi->transport.time2;
-
- if (mi->pos.m_positionX != mi->transport.pos.m_positionX)
- if (GetPlayer()->GetTransport())
- GetPlayer()->GetTransport()->UpdatePosition(mi);
}
if (mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (mi->HasExtraMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING)))
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 866cd888c3e..2eee80924a4 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -643,7 +643,7 @@ void Spell::InitExplicitTargets(SpellCastTargets const& targets)
if (Player* playerCaster = m_caster->ToPlayer())
{
// selection has to be found and to be valid target for the spell
- if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetSelection()))
+ if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetTarget()))
if (m_spellInfo->CheckExplicitTarget(m_caster, selectedUnit) == SPELL_CAST_OK)
unit = selectedUnit;
}
@@ -1777,9 +1777,9 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex)
{
case SPELL_EFFECT_SUMMON_RAF_FRIEND:
case SPELL_EFFECT_SUMMON_PLAYER:
- if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->GetSelection())
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->GetTarget())
{
- WorldObject* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection());
+ WorldObject* target = ObjectAccessor::FindPlayer(m_caster->GetTarget());
CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex));
@@ -3095,7 +3095,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
// set target for proper facing
if ((m_casttime || m_spellInfo->IsChanneled()) && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING))
if (m_caster->GetTypeId() == TYPEID_UNIT && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
- m_caster->FocusTarget(this, m_targets.GetObjectTarget());
+ m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget());
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_GCD))
TriggerGlobalCooldown();
@@ -3661,8 +3661,8 @@ void Spell::finish(bool ok)
((Puppet*)charm)->UnSummon();
}
- if (m_caster->GetTypeId() == TYPEID_UNIT)
- m_caster->ReleaseFocus(this);
+ if (Creature* creatureCaster = m_caster->ToCreature())
+ creatureCaster->ReleaseFocus(this);
if (!ok)
return;
@@ -5323,10 +5323,10 @@ SpellCastResult Spell::CheckCast(bool strict)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_BAD_TARGETS;
- if (!m_caster->ToPlayer()->GetSelection())
+ if (!m_caster->GetTarget())
return SPELL_FAILED_BAD_TARGETS;
- Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection());
+ Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetTarget());
if (!target || m_caster->ToPlayer() == target || (!target->IsInSameRaidWith(m_caster->ToPlayer()) && m_spellInfo->Id != 48955)) // refer-a-friend spell
return SPELL_FAILED_BAD_TARGETS;
@@ -5358,10 +5358,10 @@ SpellCastResult Spell::CheckCast(bool strict)
Player* playerCaster = m_caster->ToPlayer();
//
- if (!(playerCaster->GetSelection()))
+ if (!(playerCaster->GetTarget()))
return SPELL_FAILED_BAD_TARGETS;
- Player* target = ObjectAccessor::FindPlayer(playerCaster->GetSelection());
+ Player* target = playerCaster->GetSelectedPlayer();
if (!target ||
!(target->GetSession()->GetRecruiterId() == playerCaster->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == playerCaster->GetSession()->GetRecruiterId()))
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 29a869cf458..ff89cc61f6f 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -1855,7 +1855,7 @@ void SpellMgr::LoadSpellProcEvents()
}
if (!spellInfo->ProcFlags && !spellProcEvent.procFlags)
- TC_LOG_ERROR(LOG_FILTER_SQL, "Spell %u listed in `spell_proc_event` probally not triggered spell", spellInfo->Id);
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Spell %u listed in `spell_proc_event` probably not triggered spell", spellInfo->Id);
mSpellProcEventMap[spellInfo->Id] = spellProcEvent;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 8ca2e1db56e..7ad7b68b210 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -80,6 +80,7 @@
#include "Warden.h"
#include "CalendarMgr.h"
#include "BattlefieldMgr.h"
+#include "TransportMgr.h"
ACE_Atomic_Op<ACE_Thread_Mutex, bool> World::m_stopEvent = false;
uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
@@ -1374,6 +1375,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, "Loading Game Object Templates..."); // must be after LoadPageTexts
sObjectMgr->LoadGameObjectTemplate();
+ TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, "Loading Transport templates...");
+ sTransportMgr->LoadTransportTemplates();
+
TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, "Loading Spell Rank Data...");
sSpellMgr->LoadSpellRanks();
@@ -1784,10 +1788,7 @@ void World::SetInitialWorldSettings()
sBattlefieldMgr->InitBattlefield();
TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, "Loading Transports...");
- sMapMgr->LoadTransports();
-
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, "Loading Transport NPCs...");
- sMapMgr->LoadTransportNPCs();
+ sTransportMgr->SpawnContinentTransports();
///- Initialize Warden
TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, "Loading Warden Checks...");
diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp
index 332169ebd00..45ab88e9688 100644
--- a/src/server/scripts/Commands/cs_account.cpp
+++ b/src/server/scripts/Commands/cs_account.cpp
@@ -450,12 +450,12 @@ public:
uint32 pwConfig = sWorld->getIntConfig(CONFIG_ACC_PASSCHANGESEC); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
// Command is supposed to be: .account password [$oldpassword] [$newpassword] [$newpasswordconfirmation] [$emailconfirmation]
- char* oldPassword = strtok((char*)args, " "); // This extracts [$oldpassword]
- char* newPassword = strtok(NULL, " "); // This extracts [$newpassword]
- char* passwordConfirmation = strtok(NULL, " "); // This extracts [$newpasswordconfirmation]
- const char* emailConfirmation; // This defines the emailConfirmation variable, which is optional depending on sec type.
- if (!(emailConfirmation = strtok(NULL, " "))) // This extracts [$emailconfirmation]. If it doesn't exist, however...
- emailConfirmation = ""; // ... it's simply "" for emailConfirmation.
+ char* oldPassword = strtok((char*)args, " "); // This extracts [$oldpassword]
+ char* newPassword = strtok(NULL, " "); // This extracts [$newpassword]
+ char* passwordConfirmation = strtok(NULL, " "); // This extracts [$newpasswordconfirmation]
+ char const* emailConfirmation = strtok(NULL, " "); // This defines the emailConfirmation variable, which is optional depending on sec type.
+ if (!emailConfirmation) // This extracts [$emailconfirmation]. If it doesn't exist, however...
+ emailConfirmation = ""; // ... it's simply "" for emailConfirmation.
//Is any of those variables missing for any reason ? We return false.
if (!oldPassword || !newPassword || !passwordConfirmation)
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp
index 6c831520d59..f33e583522e 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -31,6 +31,7 @@ EndScriptData */
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "GossipDef.h"
+#include "Transport.h"
#include "Language.h"
#include <fstream>
@@ -91,6 +92,7 @@ public:
{ "areatriggers", rbac::RBAC_PERM_COMMAND_DEBUG_AREATRIGGERS, false, &HandleDebugAreaTriggersCommand, "", NULL },
{ "los", rbac::RBAC_PERM_COMMAND_DEBUG_LOS, false, &HandleDebugLoSCommand, "", NULL },
{ "moveflags", rbac::RBAC_PERM_COMMAND_DEBUG_MOVEFLAGS, false, &HandleDebugMoveflagsCommand, "", NULL },
+ { "transport", rbac::RBAC_PERM_COMMAND_DEBUG_TRANSPORT, false, &HandleDebugTransportCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand commandTable[] =
@@ -179,7 +181,7 @@ public:
return false;
}
- if (handler->GetSession()->GetPlayer()->GetSelection())
+ if (handler->GetSession()->GetPlayer()->GetTarget())
unit->PlayDistanceSound(soundId, handler->GetSession()->GetPlayer());
else
unit->PlayDirectSound(soundId, handler->GetSession()->GetPlayer());
@@ -1363,6 +1365,30 @@ public:
handler->PSendSysMessage("Waypoint SQL written to SQL Developer log");
return true;
}
+
+ static bool HandleDebugTransportCommand(ChatHandler* handler, char const* args)
+ {
+ Transport* transport = handler->GetSession()->GetPlayer()->GetTransport();
+ if (!transport)
+ return false;
+
+ bool start = false;
+ if (!stricmp(args, "stop"))
+ transport->EnableMovement(false);
+ else if (!stricmp(args, "start"))
+ {
+ transport->EnableMovement(true);
+ start = true;
+ }
+ else
+ {
+ handler->PSendSysMessage("Transport %s is %s", transport->GetName().c_str(), transport->GetGoState() == GO_STATE_READY ? "stopped" : "moving");
+ return true;
+ }
+
+ handler->PSendSysMessage("Transport %s %s", transport->GetName().c_str(), start ? "started" : "stopped");
+ return true;
+ }
};
void AddSC_debug_commandscript()
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 513d378287b..3d531cee1f5 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -529,7 +529,7 @@ public:
{
Unit* target = handler->getSelectedUnit();
- if (!target || !handler->GetSession()->GetPlayer()->GetSelection())
+ if (!target || !handler->GetSession()->GetPlayer()->GetTarget())
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
@@ -597,7 +597,7 @@ public:
static bool HandleGUIDCommand(ChatHandler* handler, char const* /*args*/)
{
- uint64 guid = handler->GetSession()->GetPlayer()->GetSelection();
+ uint64 guid = handler->GetSession()->GetPlayer()->GetTarget();
if (guid == 0)
{
@@ -1762,7 +1762,7 @@ public:
// accept only explicitly selected target (not implicitly self targeting case)
Unit* target = handler->getSelectedUnit();
- if (player->GetSelection() && target)
+ if (player->GetTarget() && target)
{
if (target->GetTypeId() != TYPEID_UNIT || target->IsPet())
{
@@ -2107,7 +2107,7 @@ public:
}
Unit* target = handler->getSelectedUnit();
- if (!target || !handler->GetSession()->GetPlayer()->GetSelection())
+ if (!target || !handler->GetSession()->GetPlayer()->GetTarget())
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index f10a929c675..a1b23fd5935 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -245,24 +245,22 @@ public:
float o = chr->GetOrientation();
Map* map = chr->GetMap();
- if (chr->GetTransport())
+ if (Transport* trans = chr->GetTransport())
{
- uint32 tguid = chr->GetTransport()->AddNPCPassenger(0, id, chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO());
- if (tguid > 0)
- {
- PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_TRANSPORT);
+ uint32 guid = sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT);
+ CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid);
+ data.id = id;
+ data.phaseMask = chr->GetPhaseMaskForSpawn();
+ data.posX = chr->GetTransOffsetX();
+ data.posY = chr->GetTransOffsetY();
+ data.posZ = chr->GetTransOffsetZ();
+ data.orientation = chr->GetTransOffsetO();
- stmt->setInt32(0, int32(tguid));
- stmt->setInt32(1, int32(id));
- stmt->setInt32(2, int32(chr->GetTransport()->GetEntry()));
- stmt->setFloat(3, chr->GetTransOffsetX());
- stmt->setFloat(4, chr->GetTransOffsetY());
- stmt->setFloat(5, chr->GetTransOffsetZ());
- stmt->setFloat(6, chr->GetTransOffsetO());
+ Creature* creature = trans->CreateNPCPassenger(guid, &data);
- WorldDatabase.Execute(stmt);
- }
+ creature->SaveToDB(trans->GetGOInfo()->moTransport.mapID, 1 << map->GetSpawnMode(), chr->GetPhaseMaskForSpawn());
+ sObjectMgr->AddCreatureToGrid(guid, &data);
return true;
}
@@ -899,17 +897,6 @@ public:
return false;
}
- if (target->GetTransport() && target->GetGUIDTransport())
- {
- PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_TRANSPORT_EMOTE);
-
- stmt->setInt32(0, int32(emote));
- stmt->setInt32(1, target->GetTransport()->GetEntry());
- stmt->setInt32(2, target->GetGUIDTransport());
-
- WorldDatabase.Execute(stmt);
- }
-
target->SetUInt32Value(UNIT_NPC_EMOTESTATE, emote);
return true;
@@ -1297,22 +1284,17 @@ public:
char* receiver_str = strtok((char*)args, " ");
char* text = strtok(NULL, "");
- uint64 guid = handler->GetSession()->GetPlayer()->GetSelection();
- Creature* creature = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(guid);
-
+ Creature* creature = handler->getSelectedCreature();
if (!creature || !receiver_str || !text)
- {
return false;
- }
- uint64 receiver_guid= atol(receiver_str);
+ uint64 receiver_guid = atol(receiver_str);
// check online security
if (handler->HasLowerSecurity(ObjectAccessor::FindPlayer(receiver_guid), 0))
return false;
creature->MonsterWhisper(text, receiver_guid);
-
return true;
}
@@ -1342,7 +1324,8 @@ public:
{
if (!*args)
return false;
- char* charID = strtok((char*)args, " ");
+
+ char* charID = handler->extractKeyFromLink((char*)args, "Hcreature_entry");
if (!charID)
return false;
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
index fb2d8374c18..1b5d0a80eda 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
@@ -580,7 +580,11 @@ public:
Map::PlayerList const& players = me->GetMap()->GetPlayers();
if (!players.isEmpty())
- sLFGMgr->FinishDungeon(players.begin()->GetSource()->GetGroup()->GetGUID(), 285);
+ {
+ if (Group* group = players.begin()->GetSource()->GetGroup())
+ if (group->isLFGGroup())
+ sLFGMgr->FinishDungeon(group->GetGUID(), 285);
+ }
}
void SpellHit(Unit* caster, const SpellInfo* spell) OVERRIDE
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp
index d8dfa2f5cf6..19024172aa0 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp
@@ -196,7 +196,7 @@ public:
TC_LOG_DEBUG(LOG_FILTER_TSCR, "Instance The Black Morass: Starting event.");
InitWorldState();
m_auiEncounter[1] = IN_PROGRESS;
- Events.ScheduleEvent(EVENT_NEXT_PORTAL, 15000);
+ ScheduleEventNextPortal(15000);
}
if (data == DONE)
@@ -228,7 +228,7 @@ public:
if (data == SPECIAL)
{
if (mRiftPortalCount < 7)
- Events.ScheduleEvent(EVENT_NEXT_PORTAL, 5000);
+ ScheduleEventNextPortal(5000);
}
else
m_auiEncounter[1] = data;
@@ -336,10 +336,16 @@ public:
++mRiftPortalCount;
DoUpdateWorldState(WORLD_STATE_BM_RIFT, mRiftPortalCount);
DoSpawnPortal();
- Events.ScheduleEvent(EVENT_NEXT_PORTAL, RiftWaves[GetRiftWaveId()].NextPortalTime);
+ ScheduleEventNextPortal(RiftWaves[GetRiftWaveId()].NextPortalTime);
}
}
+ void ScheduleEventNextPortal(uint32 nextPortalTime)
+ {
+ if (nextPortalTime > 0)
+ Events.RescheduleEvent(EVENT_NEXT_PORTAL, nextPortalTime);
+ }
+
protected:
EventMap Events;
};
diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp
index 2f01cc734e6..e0098570923 100644
--- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp
@@ -17,6 +17,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "Player.h"
#include "ahnkahet.h"
enum Spells
@@ -29,11 +30,9 @@ enum Spells
SPELL_FLAME_SPHERE_SPAWN_EFFECT = 55891,
SPELL_FLAME_SPHERE_VISUAL = 55928,
SPELL_FLAME_SPHERE_PERIODIC = 55926,
- H_SPELL_FLAME_SPHERE_PERIODIC = 59508,
SPELL_FLAME_SPHERE_DEATH_EFFECT = 55947,
SPELL_BEAM_VISUAL = 60342,
SPELL_EMBRACE_OF_THE_VAMPYR = 55959,
- H_SPELL_EMBRACE_OF_THE_VAMPYR = 59513,
SPELL_VANISH = 55964,
CREATURE_FLAME_SPHERE = 30106,
H_CREATURE_FLAME_SPHERE_1 = 31686,
@@ -48,8 +47,8 @@ enum Misc
DATA_SPHERE_DISTANCE = 15
};
-#define DATA_SPHERE_ANGLE_OFFSET 0.7f
-#define DATA_GROUND_POSITION_Z 11.30809f
+#define DATA_SPHERE_ANGLE_OFFSET 0.7f
+#define DATA_GROUND_POSITION_Z 11.30809f
enum Yells
{
@@ -61,315 +60,299 @@ enum Yells
SAY_FEED = 5,
SAY_VANISH = 6
};
-enum CombatPhase
+
+enum Events
+{
+ EVENT_CASTING_FLAME_SPHERES = 1,
+ EVENT_JUST_VANISHED,
+ EVENT_VANISHED,
+ EVENT_FEEDING,
+
+ EVENT_BLOODTHIRST,
+ EVENT_FLAME_SPHERE,
+ EVENT_VANISH
+};
+
+enum Phase
{
- NORMAL,
- CASTING_FLAME_SPHERES,
- JUST_VANISHED,
- VANISHED,
- FEEDING
+ PHASE_NORMAL = 1,
+ PHASE_SPECIAL = 2
};
class boss_taldaram : public CreatureScript
{
-public:
- boss_taldaram() : CreatureScript("boss_taldaram") { }
+ public:
+ boss_taldaram() : CreatureScript("boss_taldaram") { }
- struct boss_taldaramAI : public ScriptedAI
- {
- boss_taldaramAI(Creature* creature) : ScriptedAI(creature)
+ struct boss_taldaramAI : public BossAI
{
- instance = creature->GetInstanceScript();
- me->SetDisableGravity(true);
- }
-
- uint32 uiBloodthirstTimer;
- uint32 uiVanishTimer;
- uint32 uiWaitTimer;
- uint32 uiEmbraceTimer;
- uint32 uiEmbraceTakenDamage;
- uint32 uiFlamesphereTimer;
- uint32 uiPhaseTimer;
+ boss_taldaramAI(Creature* creature) : BossAI(creature, DATA_PRINCE_TALDARAM)
+ {
+ me->SetDisableGravity(true);
+ }
- uint64 uiEmbraceTarget;
+ void Reset() OVERRIDE
+ {
+ _Reset();
+ _embraceTargetGUID = 0;
+ _embraceTakenDamage = 0;
+ }
- CombatPhase Phase;
+ void EnterCombat(Unit* /*who*/) OVERRIDE
+ {
+ _EnterCombat();
+ Talk(SAY_AGGRO);
+ events.SetPhase(PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_BLOODTHIRST, 10000);
+ events.ScheduleEvent(EVENT_VANISH, urand(25000, 35000));
+ events.ScheduleEvent(EVENT_FLAME_SPHERE, 5000);
+ }
- InstanceScript* instance;
+ void UpdateAI(uint32 diff) OVERRIDE
+ {
+ if (!UpdateVictim())
+ return;
- void Reset() OVERRIDE
- {
- uiBloodthirstTimer = 10*IN_MILLISECONDS;
- uiVanishTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS);
- uiEmbraceTimer = 20*IN_MILLISECONDS;
- uiFlamesphereTimer = 5*IN_MILLISECONDS;
- uiEmbraceTakenDamage = 0;
- Phase = NORMAL;
- uiPhaseTimer = 0;
- uiEmbraceTarget = 0;
- if (instance)
- instance->SetBossState(DATA_PRINCE_TALDARAM, NOT_STARTED);
- }
+ events.Update(diff);
- void EnterCombat(Unit* /*who*/) OVERRIDE
- {
- if (instance)
- instance->SetBossState(DATA_PRINCE_TALDARAM, IN_PROGRESS);
- Talk(SAY_AGGRO);
- }
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- void UpdateAI(uint32 diff) OVERRIDE
- {
- if (!UpdateVictim())
- return;
- if (uiPhaseTimer <= diff)
- {
- switch (Phase)
+ while (uint32 eventId = events.ExecuteEvent())
{
- case CASTING_FLAME_SPHERES:
+ switch (eventId)
{
- Creature* pSpheres[3];
-
- //DoCast(me, SPELL_FLAME_SPHERE_SUMMON_1);
- pSpheres[0] = DoSpawnCreature(CREATURE_FLAME_SPHERE, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS);
- Unit* pSphereTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (pSphereTarget && pSpheres[0])
- {
- float angle, x, y;
- angle = pSpheres[0]->GetAngle(pSphereTarget);
- x = pSpheres[0]->GetPositionX() + DATA_SPHERE_DISTANCE * std::cos(angle);
- y = pSpheres[0]->GetPositionY() + DATA_SPHERE_DISTANCE * std::sin(angle);
- pSpheres[0]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[0]->GetPositionZ());
- }
- if (IsHeroic())
+ if (events.IsInPhase(PHASE_NORMAL))
{
- //DoCast(me, H_SPELL_FLAME_SPHERE_SUMMON_1);
- pSpheres[1] = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_1, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS);
- //DoCast(me, H_SPELL_FLAME_SPHERE_SUMMON_2);
- pSpheres[2] = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_2, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10*IN_MILLISECONDS);
- if (pSphereTarget && pSpheres[1] && pSpheres[2])
+ case EVENT_BLOODTHIRST:
+ DoCast(me, SPELL_BLOODTHIRST);
+ events.ScheduleEvent(EVENT_BLOODTHIRST, 10000);
+ break;
+ case EVENT_FLAME_SPHERE:
+ DoCastVictim(SPELL_CONJURE_FLAME_SPHERE);
+ events.SetPhase(PHASE_SPECIAL);
+ events.ScheduleEvent(EVENT_CASTING_FLAME_SPHERES, 3000);
+ events.ScheduleEvent(EVENT_FLAME_SPHERE, 15000);
+ break;
+ case EVENT_VANISH:
{
- float angle, x, y;
- angle = pSpheres[1]->GetAngle(pSphereTarget) + DATA_SPHERE_ANGLE_OFFSET;
- x = pSpheres[1]->GetPositionX() + DATA_SPHERE_DISTANCE/2 * std::cos(angle);
- y = pSpheres[1]->GetPositionY() + DATA_SPHERE_DISTANCE/2 * std::sin(angle);
- pSpheres[1]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[1]->GetPositionZ());
- angle = pSpheres[2]->GetAngle(pSphereTarget) - DATA_SPHERE_ANGLE_OFFSET;
- x = pSpheres[2]->GetPositionX() + DATA_SPHERE_DISTANCE/2 * std::cos(angle);
- y = pSpheres[2]->GetPositionY() + DATA_SPHERE_DISTANCE/2 * std::sin(angle);
- pSpheres[2]->GetMotionMaster()->MovePoint(0, x, y, pSpheres[2]->GetPositionZ());
+ Map::PlayerList const& players = me->GetMap()->GetPlayers();
+ uint32 targets = 0;
+ for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
+ {
+ Player* player = i->GetSource();
+ if (player && player->IsAlive())
+ ++targets;
+ }
+
+ if (targets > 2)
+ {
+ Talk(SAY_VANISH);
+ DoCast(me, SPELL_VANISH);
+ events.SetPhase(PHASE_SPECIAL);
+ events.ScheduleEvent(EVENT_JUST_VANISHED, 500);
+ if (Unit* embraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
+ _embraceTargetGUID = embraceTarget->GetGUID();
+ }
+ events.ScheduleEvent(EVENT_VANISH, urand(25000, 35000));
+ break;
}
}
-
- Phase = NORMAL;
- uiPhaseTimer = 0;
- break;
- }
- case JUST_VANISHED:
- if (Unit* pEmbraceTarget = GetEmbraceTarget())
- {
- me->GetMotionMaster()->Clear();
- me->SetSpeed(MOVE_WALK, 2.0f, true);
- me->GetMotionMaster()->MoveChase(pEmbraceTarget);
- }
- Phase = VANISHED;
- uiPhaseTimer = 1300;
- break;
- case VANISHED:
- if (Unit* pEmbraceTarget = GetEmbraceTarget())
- DoCast(pEmbraceTarget, DUNGEON_MODE(SPELL_EMBRACE_OF_THE_VAMPYR, H_SPELL_EMBRACE_OF_THE_VAMPYR));
- Talk(SAY_FEED);
- me->GetMotionMaster()->Clear();
- me->SetSpeed(MOVE_WALK, 1.0f, true);
- me->GetMotionMaster()->MoveChase(me->GetVictim());
- Phase = FEEDING;
- uiPhaseTimer = 20*IN_MILLISECONDS;
- break;
- case FEEDING:
- Phase = NORMAL;
- uiPhaseTimer = 0;
- uiEmbraceTarget = 0;
- break;
- case NORMAL:
- if (uiBloodthirstTimer <= diff)
+ case EVENT_CASTING_FLAME_SPHERES:
{
- DoCast(me, SPELL_BLOODTHIRST);
- uiBloodthirstTimer = 10*IN_MILLISECONDS;
- } else uiBloodthirstTimer -= diff;
+ events.SetPhase(PHASE_NORMAL);
+ Unit* sphereTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
+ if (!sphereTarget)
+ break;
- if (uiFlamesphereTimer <= diff)
- {
- // because TARGET_UNIT_TARGET_ENEMY we need a target selected to cast
- DoCastVictim(SPELL_CONJURE_FLAME_SPHERE);
- Phase = CASTING_FLAME_SPHERES;
- uiPhaseTimer = 3*IN_MILLISECONDS + diff;
- uiFlamesphereTimer = 15*IN_MILLISECONDS;
- } else uiFlamesphereTimer -= diff;
-
- if (uiVanishTimer <= diff)
- {
- //Count alive players
- Unit* target = NULL;
- std::list<HostileReference*> t_list = me->getThreatManager().getThreatList();
- std::vector<Unit*> target_list;
- for (std::list<HostileReference*>::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr)
+ float angle, x, y;
+
+ //DoCast(me, SPELL_FLAME_SPHERE_SUMMON_1);
+ if (Creature* sphere = DoSpawnCreature(CREATURE_FLAME_SPHERE, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10 * IN_MILLISECONDS))
{
- target = Unit::GetUnit(*me, (*itr)->getUnitGuid());
- // exclude pets & totems
- if (target && target->GetTypeId() == TYPEID_PLAYER && target->IsAlive())
- target_list.push_back(target);
- target = NULL;
+ angle = sphere->GetAngle(sphereTarget);
+ x = sphere->GetPositionX() + DATA_SPHERE_DISTANCE * std::cos(angle);
+ y = sphere->GetPositionY() + DATA_SPHERE_DISTANCE * std::sin(angle);
+ sphere->GetMotionMaster()->MovePoint(0, x, y, sphere->GetPositionZ());
}
- //He only vanishes if there are 3 or more alive players
- if (target_list.size() > 2)
- {
- Talk(SAY_VANISH);
- DoCast(me, SPELL_VANISH);
- Phase = JUST_VANISHED;
- uiPhaseTimer = 500;
- if (Unit* pEmbraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- uiEmbraceTarget = pEmbraceTarget->GetGUID();
+ if (IsHeroic())
+ {
+ //DoCast(me, H_SPELL_FLAME_SPHERE_SUMMON_1);
+ if (Creature* sphere = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_1, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10 * IN_MILLISECONDS))
+ {
+ angle = sphere->GetAngle(sphereTarget) + DATA_SPHERE_ANGLE_OFFSET;
+ x = sphere->GetPositionX() + DATA_SPHERE_DISTANCE/2 * std::cos(angle);
+ y = sphere->GetPositionY() + DATA_SPHERE_DISTANCE/2 * std::sin(angle);
+ sphere->GetMotionMaster()->MovePoint(0, x, y, sphere->GetPositionZ());
+ }
+
+ //DoCast(me, H_SPELL_FLAME_SPHERE_SUMMON_2);
+ if (Creature* sphere = DoSpawnCreature(H_CREATURE_FLAME_SPHERE_2, 0, 0, 5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10 * IN_MILLISECONDS))
+ {
+ angle = sphere->GetAngle(sphereTarget) - DATA_SPHERE_ANGLE_OFFSET;
+ x = sphere->GetPositionX() + DATA_SPHERE_DISTANCE/2 * std::cos(angle);
+ y = sphere->GetPositionY() + DATA_SPHERE_DISTANCE/2 * std::sin(angle);
+ sphere->GetMotionMaster()->MovePoint(0, x, y, sphere->GetPositionZ());
+ }
}
- uiVanishTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS);
- } else uiVanishTimer -= diff;
-
- DoMeleeAttackIfReady();
- break;
+ break;
+ }
+ case EVENT_JUST_VANISHED:
+ if (Unit* embraceTarget = GetEmbraceTarget())
+ {
+ me->GetMotionMaster()->Clear();
+ me->SetSpeed(MOVE_WALK, 2.0f, true);
+ me->GetMotionMaster()->MoveChase(embraceTarget);
+ }
+ events.ScheduleEvent(EVENT_VANISHED, 1300);
+ break;
+ case EVENT_VANISHED:
+ if (Unit* embraceTarget = GetEmbraceTarget())
+ DoCast(embraceTarget, SPELL_EMBRACE_OF_THE_VAMPYR);
+ Talk(SAY_FEED);
+ me->GetMotionMaster()->Clear();
+ me->SetSpeed(MOVE_WALK, 1.0f, true);
+ me->GetMotionMaster()->MoveChase(me->GetVictim());
+ events.ScheduleEvent(EVENT_FEEDING, 20000);
+ break;
+ case EVENT_FEEDING:
+ _embraceTargetGUID = 0;
+ events.SetPhase(PHASE_NORMAL);
+ break;
+ default:
+ break;
+ }
}
- } else uiPhaseTimer -= diff;
- }
- void DamageTaken(Unit* /*done_by*/, uint32 &damage) OVERRIDE
- {
- Unit* pEmbraceTarget = GetEmbraceTarget();
+ DoMeleeAttackIfReady();
+ }
- if (Phase == FEEDING && pEmbraceTarget && pEmbraceTarget->IsAlive())
+ void DamageTaken(Unit* /*doneBy*/, uint32& damage) OVERRIDE
{
- uiEmbraceTakenDamage += damage;
- if (uiEmbraceTakenDamage > (uint32) DUNGEON_MODE(DATA_EMBRACE_DMG, H_DATA_EMBRACE_DMG))
- {
- Phase = NORMAL;
- uiPhaseTimer = 0;
- uiEmbraceTarget = 0;
- me->CastStop();
- }
+ Unit* embraceTarget = GetEmbraceTarget();
+
+ if (events.IsInPhase(PHASE_SPECIAL) && embraceTarget && embraceTarget->IsAlive())
+ {
+ _embraceTakenDamage += damage;
+ if (_embraceTakenDamage > DUNGEON_MODE<uint32>(DATA_EMBRACE_DMG, H_DATA_EMBRACE_DMG))
+ {
+ _embraceTargetGUID = 0;
+ events.SetPhase(PHASE_NORMAL);
+ me->CastStop();
+ }
+ }
}
- }
- void JustDied(Unit* /*killer*/) OVERRIDE
- {
- Talk(SAY_DEATH);
+ void JustDied(Unit* /*killer*/) OVERRIDE
+ {
+ Talk(SAY_DEATH);
+ _JustDied();
+ }
- if (instance)
- instance->SetBossState(DATA_PRINCE_TALDARAM, DONE);
- }
+ void KilledUnit(Unit* victim) OVERRIDE
+ {
+ if (victim->GetTypeId() != TYPEID_PLAYER)
+ return;
- void KilledUnit(Unit* victim) OVERRIDE
- {
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
+ Unit* embraceTarget = GetEmbraceTarget();
+ if (events.IsInPhase(PHASE_SPECIAL) && embraceTarget && victim == embraceTarget)
+ {
+ _embraceTargetGUID = 0;
+ events.SetPhase(PHASE_NORMAL);
+ }
+ Talk(SAY_SLAY);
+ }
- Unit* pEmbraceTarget = GetEmbraceTarget();
- if (Phase == FEEDING && pEmbraceTarget && victim == pEmbraceTarget)
+ bool CheckSpheres()
{
- Phase = NORMAL;
- uiPhaseTimer = 0;
- uiEmbraceTarget = 0;
- }
- Talk(SAY_SLAY);
- }
+ for (uint8 i = 0; i < 2; ++i)
+ if (!instance->GetData(DATA_SPHERE_1 + i))
+ return false;
- bool CheckSpheres()
- {
- for (uint8 i = 0; i < 2; ++i)
- if (!instance->GetData(DATA_SPHERE_1 + i))
- return false;
+ RemovePrison();
+ return true;
+ }
- RemovePrison();
- return true;
- }
+ Unit* GetEmbraceTarget()
+ {
+ if (_embraceTargetGUID)
+ return ObjectAccessor::GetUnit(*me, _embraceTargetGUID);
- Unit* GetEmbraceTarget()
- {
- if (!uiEmbraceTarget)
return NULL;
+ }
- return Unit::GetUnit(*me, uiEmbraceTarget);
- }
+ void RemovePrison()
+ {
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->RemoveAurasDueToSpell(SPELL_BEAM_VISUAL);
+ me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), DATA_GROUND_POSITION_Z, me->GetOrientation());
+ DoCast(SPELL_HOVER_FALL);
+ me->SetDisableGravity(false);
+ me->GetMotionMaster()->MovePoint(0, me->GetHomePosition());
+ Talk(SAY_WARNING);
+ instance->HandleGameObject(instance->GetData64(DATA_PRINCE_TALDARAM_PLATFORM), true);
+ }
+
+ private:
+ uint64 _embraceTargetGUID;
+ uint32 _embraceTakenDamage;
+ };
- void RemovePrison()
+ CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
- if (!instance)
- return;
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- me->RemoveAurasDueToSpell(SPELL_BEAM_VISUAL);
- me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), DATA_GROUND_POSITION_Z, me->GetOrientation());
- DoCast(SPELL_HOVER_FALL);
- me->SetDisableGravity(false);
- me->GetMotionMaster()->MovePoint(0, me->GetHomePosition());
- Talk(SAY_WARNING);
- uint64 prison_GUID = instance->GetData64(DATA_PRINCE_TALDARAM_PLATFORM);
- instance->HandleGameObject(prison_GUID, true);
+ return GetAhnKahetAI<boss_taldaramAI>(creature);
}
- };
-
- CreatureAI* GetAI(Creature* creature) const OVERRIDE
- {
- return GetAhnKahetAI<boss_taldaramAI>(creature);
- }
};
class npc_taldaram_flamesphere : public CreatureScript
{
-public:
- npc_taldaram_flamesphere() : CreatureScript("npc_taldaram_flamesphere") { }
+ public:
+ npc_taldaram_flamesphere() : CreatureScript("npc_taldaram_flamesphere") { }
- struct npc_taldaram_flamesphereAI : public ScriptedAI
- {
- npc_taldaram_flamesphereAI(Creature* creature) : ScriptedAI(creature)
+ struct npc_taldaram_flamesphereAI : public ScriptedAI
{
- instance = creature->GetInstanceScript();
- }
+ npc_taldaram_flamesphereAI(Creature* creature) : ScriptedAI(creature)
+ {
+ }
- uint32 uiDespawnTimer;
- InstanceScript* instance;
+ void Reset() OVERRIDE
+ {
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ //! HACK: Creature's can't have MOVEMENTFLAG_FLYING
+ me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
+ me->setFaction(16);
+ me->SetObjectScale(1.0f);
+ DoCast(me, SPELL_FLAME_SPHERE_VISUAL);
+ DoCast(me, SPELL_FLAME_SPHERE_SPAWN_EFFECT);
+ DoCast(me, SPELL_FLAME_SPHERE_PERIODIC);
+ _despawnTimer = 10 * IN_MILLISECONDS;
+ }
- void Reset() OVERRIDE
- {
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- //! HACK: Creature's can't have MOVEMENTFLAG_FLYING
- me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
- me->setFaction(16);
- me->SetObjectScale(1.0f);
- DoCast(me, SPELL_FLAME_SPHERE_VISUAL);
- DoCast(me, SPELL_FLAME_SPHERE_SPAWN_EFFECT);
- DoCast(me, SPELL_FLAME_SPHERE_PERIODIC);
- uiDespawnTimer = 10*IN_MILLISECONDS;
- }
+ void EnterCombat(Unit* /*who*/) OVERRIDE { }
+ void MoveInLineOfSight(Unit* /*who*/) OVERRIDE { }
- void EnterCombat(Unit* /*who*/) OVERRIDE {}
- void MoveInLineOfSight(Unit* /*who*/) OVERRIDE {}
+ void JustDied(Unit* /*killer*/) OVERRIDE
+ {
+ DoCast(me, SPELL_FLAME_SPHERE_DEATH_EFFECT);
+ }
+ void UpdateAI(uint32 diff) OVERRIDE
+ {
+ if (_despawnTimer <= diff)
+ me->DisappearAndDie();
+ else
+ _despawnTimer -= diff;
+ }
- void JustDied(Unit* /*killer*/) OVERRIDE
- {
- DoCast(me, SPELL_FLAME_SPHERE_DEATH_EFFECT);
- }
+ private:
+ uint32 _despawnTimer;
+ };
- void UpdateAI(uint32 diff) OVERRIDE
+ CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
- if (uiDespawnTimer <= diff)
- me->DisappearAndDie();
- else
- uiDespawnTimer -= diff;
+ return new npc_taldaram_flamesphereAI(creature);
}
- };
-
- CreatureAI* GetAI(Creature* creature) const OVERRIDE
- {
- return new npc_taldaram_flamesphereAI(creature);
- }
};
class prince_taldaram_sphere : public GameObjectScript
@@ -377,7 +360,7 @@ class prince_taldaram_sphere : public GameObjectScript
public:
prince_taldaram_sphere() : GameObjectScript("prince_taldaram_sphere") { }
- bool OnGossipHello(Player* /*player*/, GameObject* go)
+ bool OnGossipHello(Player* /*player*/, GameObject* go) OVERRIDE
{
InstanceScript* instance = go->GetInstanceScript();
if (!instance)
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
index 987807c2080..04145b8784e 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
@@ -181,7 +181,7 @@ enum Events
EVENT_ESCAPE_13,
EVENT_ESCAPE_14,
EVENT_ESCAPE_15,
- EVENT_ESCAPE_16,
+ //EVENT_ESCAPE_16,
EVENT_ESCAPE_17,
EVENT_ESCAPE_18,
EVENT_ESCAPE_19,
@@ -226,7 +226,7 @@ enum Spells
SPELL_SOUL_REAPER = 69409, // Lich King Soul Reaper
SPELL_FURY_OF_FROSTMOURNE = 70063, // Lich King Fury of FrostMourne
SPELL_JAINA_DESTROY_ICE_WALL = 69784, // Jaina
- SPELL_SYLVANAS_DESTROY_ICE_WALL = 70225, // Sylvanas
+ SPELL_SYLVANAS_DESTROY_ICE_WALL = 70224, // Sylvanas
SPELL_SYLVANAS_JUMP = 68339, // Sylvanas Jump
SPELL_RAISE_DEAD = 69818,
SPELL_HARVEST_SOUL = 70070,
@@ -234,16 +234,16 @@ enum Spells
SPELL_SUMMON_LUMBERING_ABOMINATION = 69835,
SPELL_SUMMON_ICE_WALL = 69768, // Visual effect and icewall summoning
- //Raging gnoul
+ // Raging Ghoul
SPELL_EMERGE_VISUAL = 50142,
SPELL_GHOUL_JUMP = 70150,
- //Witch Doctor
+ // Witch Doctor
SPELL_COURSE_OF_DOOM = 70144,
SPELL_SHADOW_BOLT_VOLLEY = 70145,
SPELL_SHADOW_BOLT = 70080,
- //Lumbering Abomination
+ // Lumbering Abomination
SPELL_ABON_STRIKE = 40505,
SPELL_VOMIT_SPRAY = 70176,
};
@@ -344,6 +344,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
void UpdateAI(uint32 diff) OVERRIDE
{
_events.Update(diff);
+
switch (_events.ExecuteEvent())
{
case EVENT_WALK_INTRO1:
@@ -398,7 +399,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_A2_5, 2000);
break;
case EVENT_INTRO_A2_5:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_A2_1);
_events.ScheduleEvent(EVENT_INTRO_A2_6, 3000);
break;
@@ -407,7 +408,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_A2_7, 7000);
break;
case EVENT_INTRO_A2_7:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_A2_2);
_events.ScheduleEvent(EVENT_INTRO_A2_8, 7000);
break;
@@ -416,7 +417,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_A2_9, 1200);
break;
case EVENT_INTRO_A2_9:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_A2_3);
_events.ScheduleEvent(EVENT_INTRO_A2_10, 11000);
break;
@@ -425,7 +426,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_A2_11, 6000);
break;
case EVENT_INTRO_A2_11:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_A2_4);
_events.ScheduleEvent(EVENT_INTRO_A2_12, 12000);
break;
@@ -434,7 +435,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_A2_13, 6000);
break;
case EVENT_INTRO_A2_13:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_A2_5);
_events.ScheduleEvent(EVENT_INTRO_A2_14, 13000);
break;
@@ -443,12 +444,12 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_A2_15, 12000);
break;
case EVENT_INTRO_A2_15:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_A2_6);
_events.ScheduleEvent(EVENT_INTRO_A2_16, 25000);
break;
case EVENT_INTRO_A2_16:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_A2_7);
_events.ScheduleEvent(EVENT_INTRO_A2_17, 6000);
break;
@@ -457,7 +458,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_A2_18, 5000);
break;
case EVENT_INTRO_A2_18:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
{
uther->HandleEmoteCommand(EMOTE_ONESHOT_NO);
uther->AI()->Talk(SAY_UTHER_INTRO_A2_8);
@@ -494,7 +495,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_H2_5, 2000);
break;
case EVENT_INTRO_H2_5:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_H2_1);
_events.ScheduleEvent(EVENT_INTRO_H2_6, 11000);
break;
@@ -503,7 +504,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_H2_7, 3000);
break;
case EVENT_INTRO_H2_7:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_H2_2);
_events.ScheduleEvent(EVENT_INTRO_H2_8, 6000);
break;
@@ -512,7 +513,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_H2_9, 5000);
break;
case EVENT_INTRO_H2_9:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_H2_3);
_events.ScheduleEvent(EVENT_INTRO_H2_10, 19000);
break;
@@ -521,7 +522,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_H2_11, 1500);
break;
case EVENT_INTRO_H2_11:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_H2_4);
_events.ScheduleEvent(EVENT_INTRO_H2_12, 19500);
break;
@@ -530,7 +531,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_H2_13, 2000);
break;
case EVENT_INTRO_H2_13:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
{
uther->HandleEmoteCommand(EMOTE_ONESHOT_NO);
uther->AI()->Talk(SAY_UTHER_INTRO_H2_5);
@@ -538,7 +539,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_H2_14, 12000);
break;
case EVENT_INTRO_H2_14:
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
uther->AI()->Talk(SAY_UTHER_INTRO_H2_6);
_events.ScheduleEvent(EVENT_INTRO_H2_15, 8000);
break;
@@ -557,7 +558,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 0);
_events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 4000);
}
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
{
uther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER);
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
@@ -568,13 +569,13 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_LK_2, 10000);
break;
case EVENT_INTRO_LK_2:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
lichking->AI()->Talk(SAY_LK_INTRO_1);
_events.ScheduleEvent(EVENT_INTRO_LK_3, 1000);
break;
case EVENT_INTRO_LK_3:
// The Lich King banishes Uther to the abyss.
- if (Creature* uther = me->GetCreature(*me, _utherGUID))
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _utherGUID))
{
uther->CastSpell(uther, SPELL_UTHER_DESPAWN, true);
uther->DespawnOrUnsummon(5000);
@@ -584,7 +585,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
break;
case EVENT_INTRO_LK_4:
// He steps forward and removes the runeblade from the heap of skulls.
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
if (GameObject* frostmourne = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_FROSTMOURNE)))
frostmourne->SetPhaseMask(2, true);
@@ -594,7 +595,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_LK_5, 8000);
break;
case EVENT_INTRO_LK_5:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
lichking->AI()->Talk(SAY_LK_INTRO_2);
_events.ScheduleEvent(EVENT_INTRO_LK_6, 10000);
break;
@@ -610,7 +611,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true);
marwyn->SetVisible(true);
}
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
lichking->AI()->Talk(SAY_LK_INTRO_3);
lichking->SetWalk(true);
@@ -653,7 +654,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
_events.ScheduleEvent(EVENT_INTRO_LK_11, 5000);
break;
case EVENT_INTRO_LK_11:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
lichking->AI()->Talk(SAY_LK_JAINA_INTRO_END);
@@ -666,7 +667,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
if (_instance)
_instance->SetData(DATA_INTRO_EVENT, DONE);
// Loralen or Koreln disappearAndDie()
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
lichking->DespawnOrUnsummon(5000);
_lichkingGUID = 0;
@@ -702,7 +703,7 @@ class npc_jaina_or_sylvanas_hor : public CreatureScript
CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
- return new npc_jaina_or_sylvanas_horAI(creature);
+ return GetHallsOfReflectionAI<npc_jaina_or_sylvanas_horAI>(creature);
}
};
@@ -716,9 +717,8 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
{
npc_jaina_or_sylvanas_escape_horAI(Creature* creature) : ScriptedAI(creature),
_instance(creature->GetInstanceScript()), _lichkingGUID(0), _walltargetGUID(0),
- _icewallGUID(0), _icewall(0), _isattackingwall(0)
+ _icewallGUID(0), _icewall(0)
{
- _instance = me->GetInstanceScript();
}
InstanceScript* _instance;
@@ -726,33 +726,29 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
uint64 _walltargetGUID; // dummy
uint64 _icewallGUID; // object
uint32 _icewall; // icewall number
- uint32 _isattackingwall; //sylvannas attacking icewall
EventMap _events;
-
void Reset() OVERRIDE
{
_events.Reset();
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
lichking->DespawnOrUnsummon(1);
_lichkingGUID = 0;
_walltargetGUID = 0;
_icewallGUID = 0;
_icewall = 0;
- _isattackingwall = false;
_events.ScheduleEvent(EVENT_ESCAPE, 0);
}
void JustDied(Unit* /*Killer*/) OVERRIDE
{
- if (_instance)
_instance->SetData(DATA_ESCAPE_EVENT, FAIL);
}
- void DoAction(int32 actionID) OVERRIDE
+ void DoAction(int32 actionId) OVERRIDE
{
- switch (actionID)
+ switch (actionId)
{
case ACTION_START_ESCAPING: // called by InstanceScript when we need to start the escaping event
_events.ScheduleEvent(EVENT_ESCAPE_1, 1000);
@@ -760,10 +756,9 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
case ACTION_WALL_BROKEN:
_icewall++;
if (_icewall != 4)
- _events.ScheduleEvent(EVENT_ESCAPE_17,3000);
+ _events.ScheduleEvent(EVENT_ESCAPE_17, 3000);
else
- _events.ScheduleEvent(EVENT_ESCAPE_23,3000);
- _isattackingwall = false;
+ _events.ScheduleEvent(EVENT_ESCAPE_23, 3000);
break;
}
}
@@ -781,6 +776,19 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
}
}
+ void DestroyIceWall()
+ {
+ if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
+ me->RemoveAurasDueToSpell(SPELL_JAINA_DESTROY_ICE_WALL);
+ else
+ me->RemoveAurasDueToSpell(SPELL_SYLVANAS_DESTROY_ICE_WALL);
+
+ _instance->HandleGameObject(_icewallGUID, true);
+
+ if (Creature* wallTarget = ObjectAccessor::GetCreature(*me, _walltargetGUID))
+ wallTarget->DespawnOrUnsummon();
+ }
+
void UpdateAI(uint32 diff) OVERRIDE
{
_events.Update(diff);
@@ -792,21 +800,21 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
case EVENT_ESCAPE:
if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_PART2, LichKingSpawnPos2, TEMPSUMMON_MANUAL_DESPAWN))
{
- me->Attack(lichking,true);
- lichking->Attack(me,true);
+ me->Attack(lichking, true);
+ lichking->Attack(me, true);
me->SetReactState(REACT_PASSIVE);
lichking->SetReactState(REACT_PASSIVE);
_lichkingGUID = lichking->GetGUID();
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->AI()->DoCast(me, SPELL_JAINA_ICEBARRIER);
+ DoCast(me, SPELL_JAINA_ICEBARRIER);
else
- me->AI()->DoCast(me, SPELL_SYLVANAS_CLOAKOFDARKNESS);
+ DoCast(me, SPELL_SYLVANAS_CLOAKOFDARKNESS);
}
me->SetHealth(252000);
break;
case EVENT_ESCAPE_1:
_instance->SetData(DATA_ESCAPE_EVENT, IN_PROGRESS);
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
lichking->AI()->Talk(SAY_LK_ESCAPE_1);
@@ -817,30 +825,27 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
break;
case EVENT_ESCAPE_2:
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->AI()->DoCast(me,SPELL_CAST_VISUAL,true);
+ DoCast(me, SPELL_CAST_VISUAL, true);
else
- me->AI()->DoCast(me,SPELL_SYLVANAS_JUMP,true);
+ DoCast(me, SPELL_SYLVANAS_JUMP, true);
_events.ScheduleEvent(EVENT_ESCAPE_3, 1000);
break;
case EVENT_ESCAPE_3:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
- {
- if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- lichking->AI()->DoCast(lichking, SPELL_JAINA_ICEPRISON, true);
- else
- lichking->AI()->DoCast(lichking, SPELL_SYLVANAS_DARKBINDING, true);
- }
+ if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
+ DoCastAOE(SPELL_JAINA_ICEPRISON, true);
+ else
+ DoCastAOE(SPELL_SYLVANAS_DARKBINDING, true);
_events.ScheduleEvent(EVENT_ESCAPE_4, 2000);
break;
case EVENT_ESCAPE_4:
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->AI()->Talk(SAY_JAINA_ESCAPE_1);
+ Talk(SAY_JAINA_ESCAPE_1);
else
- me->AI()->Talk(SAY_SYLVANAS_ESCAPE_1);
+ Talk(SAY_SYLVANAS_ESCAPE_1);
_events.ScheduleEvent(EVENT_ESCAPE_5, 2000);
break;
case EVENT_ESCAPE_5:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
lichking->CombatStop();
me->GetMotionMaster()->MovePoint(0, JainaShadowThroneDoor);
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
@@ -853,7 +858,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER);
break;
case EVENT_ESCAPE_7:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
lichking->RemoveAurasDueToSpell(SPELL_JAINA_ICEPRISON);
@@ -863,13 +868,13 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
_events.ScheduleEvent(EVENT_ESCAPE_8, 1000);
break;
case EVENT_ESCAPE_8:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
lichking->HandleEmoteCommand(TEXT_EMOTE_ROAR);
me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[0]);
_events.ScheduleEvent(EVENT_ESCAPE_9, 3000);
break;
case EVENT_ESCAPE_9:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
lichking->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[0]);
_events.ScheduleEvent(EVENT_ESCAPE_10, 1000);
break;
@@ -879,39 +884,39 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
break;
case EVENT_ESCAPE_11:
me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[2]);
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
lichking->GetMotionMaster()->MovePoint(0, LichKingFirstSummon);
_events.ScheduleEvent(EVENT_ESCAPE_12, 6000);
break;
case EVENT_ESCAPE_12:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
lichking->AI()->Talk(SAY_LK_ESCAPE_3);
lichking->AI()->DoCast(me, SPELL_RAISE_DEAD);
- lichking->Attack(me,true);
+ lichking->Attack(me, true);
}
_events.ScheduleEvent(EVENT_ESCAPE_13, 4000);
break;
case EVENT_ESCAPE_13:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
lichking->AI()->DoCast(lichking, SPELL_REMORSELESS_WINTER, true);
lichking->AI()->DoCast(lichking, SPELL_SUMMON_RISE_WITCH_DOCTOR);
lichking->GetMotionMaster()->MoveIdle();
lichking->GetMotionMaster()->MoveChase(me);
}
- if (Creature* walltarget = me->SummonCreature(NPC_ICE_WALL,IceWalls[0].GetPositionX(), IceWalls[0].GetPositionY(), IceWalls[0].GetPositionZ(), IceWalls[0].GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN, 720000))
+ if (Creature* walltarget = me->SummonCreature(NPC_ICE_WALL, IceWalls[0], TEMPSUMMON_MANUAL_DESPAWN, 720000))
{
_walltargetGUID = walltarget->GetGUID();
walltarget->AI()->DoCast(walltarget, SPELL_SUMMON_ICE_WALL);
walltarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- me->Attack(walltarget,false);
+ me->Attack(walltarget, false);
}
me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[3]);
_events.ScheduleEvent(EVENT_ESCAPE_14, 8000);
break;
case EVENT_ESCAPE_14:
- if (Creature* walltarget = me->GetCreature(*me, _walltargetGUID))
+ if (Creature* walltarget = ObjectAccessor::GetCreature(*me, _walltargetGUID))
{
if (GameObject* icewall = walltarget->FindNearestGameObject(GO_ICE_WALL, 50.00f))
{
@@ -919,61 +924,42 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
icewall->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
_instance->HandleGameObject(0, false, icewall);
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->AI()->Talk(SAY_JAINA_ESCAPE_2);
+ Talk(SAY_JAINA_ESCAPE_2);
else
- me->AI()->Talk(SAY_SYLVANAS_ESCAPE_2);
+ Talk(SAY_SYLVANAS_ESCAPE_2);
}
}
_events.ScheduleEvent(EVENT_ESCAPE_15, 1000);
break;
case EVENT_ESCAPE_15:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
lichking->GetMotionMaster()->MoveIdle();
lichking->GetMotionMaster()->MoveChase(me);
lichking->SetReactState(REACT_PASSIVE);
}
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->AI()->DoCast(me, SPELL_JAINA_DESTROY_ICE_WALL, false);
+ DoCast(me, SPELL_JAINA_DESTROY_ICE_WALL, true);
else
- {
- _isattackingwall = true;
- me->AI()->DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, false);
- _events.ScheduleEvent(EVENT_ESCAPE_16, 1000);
- }
- break;
- case EVENT_ESCAPE_16:
- if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE)
- {
- me->AI()->DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, false);
- if (_isattackingwall)
- _events.ScheduleEvent(EVENT_ESCAPE_16, 1000);
- }
+ DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, true);
break;
case EVENT_ESCAPE_17:// ICEWALL BROKEN
me->GetMotionMaster()->MoveIdle();
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
lichking->StopMoving();
lichking->AI()->Talk(SAY_LK_ESCAPE_3);
lichking->AI()->DoCast(me, SPELL_RAISE_DEAD);
}
- if (Creature* walltarget = me->GetCreature(*me, _walltargetGUID))
- walltarget->DespawnOrUnsummon(0);
- if (GameObject* icewall = ObjectAccessor::GetGameObject(*me, _icewallGUID))
- {
- _instance->HandleGameObject(0 ,true, icewall);
- if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->RemoveAurasDueToSpell(SPELL_JAINA_DESTROY_ICE_WALL);
- else
- me->RemoveAurasDueToSpell(SPELL_SYLVANAS_DESTROY_ICE_WALL);
- }
+
+ DestroyIceWall();
+
if (_icewall && _icewall < 4)
me->GetMotionMaster()->MovePoint(0, NpcJainaOrSylvanasEscapeRoute[_icewall + 3]);
_events.ScheduleEvent(EVENT_ESCAPE_18, 2000);
break;
case EVENT_ESCAPE_18:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
lichking->GetMotionMaster()->MoveIdle();
lichking->GetMotionMaster()->MoveChase(me);
@@ -981,29 +967,29 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
_events.ScheduleEvent(EVENT_ESCAPE_19, 6000);
break;
case EVENT_ESCAPE_19:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
if (_icewall && _icewall < 4)
lichking->AI()->DoCast(lichking, SPELL_SUMMON_RISE_WITCH_DOCTOR);
lichking->GetMotionMaster()->MoveIdle();
lichking->GetMotionMaster()->MoveChase(me);
lichking->SetReactState(REACT_PASSIVE);
- lichking->Attack(me,true);
+ lichking->Attack(me, true);
}
if (_icewall < 4)
{
- if (Creature* walltarget = me->SummonCreature(NPC_ICE_WALL, IceWalls[_icewall].GetPositionX(), IceWalls[_icewall].GetPositionY(), IceWalls[_icewall].GetPositionZ(), IceWalls[_icewall].GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN, 720000))
+ if (Creature* walltarget = me->SummonCreature(NPC_ICE_WALL, IceWalls[_icewall], TEMPSUMMON_MANUAL_DESPAWN, 720000))
{
_walltargetGUID = walltarget->GetGUID();
walltarget->AI()->DoCast(walltarget, SPELL_SUMMON_ICE_WALL);
walltarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- me->Attack(walltarget,false);
+ me->Attack(walltarget, false);
}
}
_events.ScheduleEvent(EVENT_ESCAPE_20, 3000);
break;
case EVENT_ESCAPE_20:
- if (Creature* walltarget = me->GetCreature(*me, _walltargetGUID))
+ if (Creature* walltarget = ObjectAccessor::GetCreature(*me, _walltargetGUID))
{
if (GameObject* icewall = walltarget->FindNearestGameObject(GO_ICE_WALL, 50.00f))
{
@@ -1013,24 +999,24 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
{
if (_icewall == 1)
- me->AI()->Talk(SAY_JAINA_ESCAPE_3);
+ Talk(SAY_JAINA_ESCAPE_3);
else if (_icewall == 2)
- me->AI()->Talk(SAY_JAINA_ESCAPE_4);
+ Talk(SAY_JAINA_ESCAPE_4);
else if (_icewall == 3)
- me->AI()->Talk(SAY_JAINA_ESCAPE_5);
+ Talk(SAY_JAINA_ESCAPE_5);
}
else if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE)
{
if (_icewall == 1)
- me->AI()->Talk(SAY_SYLVANAS_ESCAPE_3);
+ Talk(SAY_SYLVANAS_ESCAPE_3);
else if (_icewall == 2)
- me->AI()->Talk(SAY_SYLVANAS_ESCAPE_4);
+ Talk(SAY_SYLVANAS_ESCAPE_4);
else if (_icewall == 3)
- me->AI()->Talk(SAY_SYLVANAS_ESCAPE_5);
+ Talk(SAY_SYLVANAS_ESCAPE_5);
}
}
}
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
if (_icewall && _icewall < 3)
lichking->AI()->DoCast(lichking, SPELL_SUMMON_RISE_WITCH_DOCTOR);
@@ -1044,53 +1030,37 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
break;
case EVENT_ESCAPE_21:
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->AI()->DoCast(me, SPELL_JAINA_DESTROY_ICE_WALL, false);
+ DoCast(me, SPELL_JAINA_DESTROY_ICE_WALL, true);
else
- {
- me->AI()->DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, false);
- _isattackingwall = true;
- _events.ScheduleEvent(EVENT_ESCAPE_22, 1000);
- }
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, true);
+
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
if (_icewall == 1)
lichking->AI()->DoCast(lichking, SPELL_SUMMON_LUMBERING_ABOMINATION);
else if (_icewall > 1 && _icewall < 4)
+ {
lichking->AI()->DoCast(lichking, SPELL_SUMMON_RISE_WITCH_DOCTOR);
+ _events.ScheduleEvent(EVENT_ESCAPE_22, 1000);
+ }
}
break;
case EVENT_ESCAPE_22:
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
if (_icewall >= 2 && _icewall < 4)
lichking->AI()->DoCast(lichking, SPELL_SUMMON_LUMBERING_ABOMINATION);
}
- if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE)
- {
- me->AI()->DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, false);
- if (_isattackingwall)
- _events.ScheduleEvent(EVENT_ESCAPE_22, 1000);
- }
break;
+ case EVENT_ESCAPE_23: // FINAL PART
+ DestroyIceWall();
- case EVENT_ESCAPE_23:// FINAL PART
- if (Creature* walltarget = me->GetCreature(*me, _walltargetGUID))
- walltarget->DespawnOrUnsummon(0);
- if (GameObject* icewall = ObjectAccessor::GetGameObject(*me, _icewallGUID))
- {
- _instance->HandleGameObject(0 ,true, icewall);
- if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- {
- me->RemoveAurasDueToSpell(SPELL_JAINA_DESTROY_ICE_WALL);
- me->AI()->Talk(SAY_JAINA_ESCAPE_6);
- }
- else
- {
- me->RemoveAurasDueToSpell(SPELL_SYLVANAS_DESTROY_ICE_WALL);
- me->AI()->Talk(SAY_SYLVANAS_ESCAPE_6);
- }
- }
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
+ Talk(SAY_JAINA_ESCAPE_6);
+ else
+ Talk(SAY_SYLVANAS_ESCAPE_6);
+
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
{
lichking->GetMotionMaster()->MovePoint(0, LichKingFinalPos);
lichking->AI()->Talk(SAY_LK_ESCAPE_11);
@@ -1100,21 +1070,21 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
break;
case EVENT_ESCAPE_24:
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->AI()->Talk(SAY_JAINA_ESCAPE_8);
+ Talk(SAY_JAINA_ESCAPE_8);
else
- me->AI()->Talk(SAY_SYLVANAS_ESCAPE_8);
+ Talk(SAY_SYLVANAS_ESCAPE_8);
_events.ScheduleEvent(EVENT_ESCAPE_25, 5000);
break;
case EVENT_ESCAPE_25:
- if (GameObject* cave = _instance->instance->GetGameObject(_instance->GetData64(DATA_CAVE_IN)))
- cave->SetGoState(GO_STATE_READY);
+ if (GameObject* cave = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_CAVE_IN)))
+ cave->SetGoState(GO_STATE_READY);
_events.ScheduleEvent(EVENT_ESCAPE_26, 4000);
break;
case EVENT_ESCAPE_26:
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
- me->AI()->Talk(SAY_JAINA_ESCAPE_10);
+ Talk(SAY_JAINA_ESCAPE_10);
else
- me->AI()->Talk(SAY_SYLVANAS_ESCAPE_9);
+ Talk(SAY_SYLVANAS_ESCAPE_9);
_events.ScheduleEvent(EVENT_ESCAPE_27, 4000);
break;
case EVENT_ESCAPE_27:
@@ -1123,7 +1093,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
else
me->SummonGameObject(GO_CAPTAIN_CHEST_3, ChestPos.GetPositionX(), ChestPos.GetPositionY(), ChestPos.GetPositionZ(), ChestPos.GetOrientation(), 0, 0, 0, 0, 720000);
me->SummonGameObject(GO_PORTAL, FinalPortalPos.GetPositionX(), FinalPortalPos.GetPositionY(), FinalPortalPos.GetPositionZ(), FinalPortalPos.GetOrientation(), 0, 0, 0, 0, 720000);
- if (Creature* lichking = me->GetCreature(*me, _lichkingGUID))
+ if (Creature* lichking = ObjectAccessor::GetCreature(*me, _lichkingGUID))
lichking->DespawnOrUnsummon(1);
break;
}
@@ -1133,7 +1103,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
- return new npc_jaina_or_sylvanas_escape_horAI(creature);
+ return GetHallsOfReflectionAI<npc_jaina_or_sylvanas_escape_horAI>(creature);
}
};
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
index 3223ecf66a5..d8d4f2d5524 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
@@ -175,4 +175,10 @@ struct boss_horAI : ScriptedAI
}
};
+template<class AI>
+AI* GetHallsOfReflectionAI(Creature* creature)
+{
+ return GetInstanceAI<AI>(creature, HoRScriptName);
+}
+
#endif
diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp
index 532ede3f849..3a2d5c592fe 100644
--- a/src/server/scripts/Northrend/zone_zuldrak.cpp
+++ b/src/server/scripts/Northrend/zone_zuldrak.cpp
@@ -1815,7 +1815,7 @@ class spell_fetch_ingredient_aura : public SpellScriptLoader
}
};
-enum StormCloud
+enum StormCloud
{
STORM_COULD = 29939,
HEALING_WINDS = 55549,
@@ -1842,7 +1842,7 @@ public:
{
Reset();
}
-
+
void SpellHit(Unit* caster, const SpellInfo* spell) OVERRIDE
{
if (spell->Id != GYMERS_GRAB)
diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp
index 41280471bd4..f27ee2b72e0 100644
--- a/src/server/shared/Database/Implementation/WorldDatabase.cpp
+++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp
@@ -75,8 +75,6 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_UPD_WAYPOINT_SCRIPT_O, "UPDATE waypoint_scripts SET o = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(WORLD_INS_CREATURE_TRANSPORT, "INSERT INTO creature_transport (guid, npc_entry, transport_entry, TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO) values (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
- PrepareStatement(WORLD_UPD_CREATURE_TRANSPORT_EMOTE, "UPDATE creature_transport SET emote = ? WHERE transport_entry = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction_A, faction_H, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH);
diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h
index 171627bb83a..b17aa0dedbb 100644
--- a/src/server/shared/Database/Implementation/WorldDatabase.h
+++ b/src/server/shared/Database/Implementation/WorldDatabase.h
@@ -95,8 +95,6 @@ enum WorldDatabaseStatements
WORLD_UPD_WAYPOINT_SCRIPT_O,
WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID,
WORLD_DEL_CREATURE,
- WORLD_INS_CREATURE_TRANSPORT,
- WORLD_UPD_CREATURE_TRANSPORT_EMOTE,
WORLD_SEL_COMMANDS,
WORLD_SEL_CREATURE_TEMPLATE,
WORLD_SEL_WAYPOINT_SCRIPT_BY_ID,
diff --git a/src/tools/mesh_extractor/ContinentBuilder.cpp b/src/tools/mesh_extractor/ContinentBuilder.cpp
index be74357d1f0..c90a6e527f7 100644
--- a/src/tools/mesh_extractor/ContinentBuilder.cpp
+++ b/src/tools/mesh_extractor/ContinentBuilder.cpp
@@ -153,9 +153,9 @@ void ContinentBuilder::Build()
}
else
{
- params.maxPolys = 1 << STATIC_POLY_BITS;
- params.maxTiles = TileMap->TileTable.size();
- rcVcopy(params.orig, bmin);
+ params.maxPolys = 32768;
+ params.maxTiles = 4096;
+ rcVcopy(params.orig, Constants::Origin);
params.tileHeight = Constants::TileSize;
params.tileWidth = Constants::TileSize;
fwrite(&params, sizeof(dtNavMeshParams), 1, mmap);
diff --git a/src/tools/mesh_extractor/Geometry.cpp b/src/tools/mesh_extractor/Geometry.cpp
index 658c312a6e8..df828dcd573 100644
--- a/src/tools/mesh_extractor/Geometry.cpp
+++ b/src/tools/mesh_extractor/Geometry.cpp
@@ -17,7 +17,7 @@ void Geometry::CalculateBoundingBox( float*& min, float*& max )
max = new float[3];
for (int i = 0; i < 3; ++i)
{
- max[i] = std::numeric_limits<float>::min();
+ max[i] = std::numeric_limits<float>::lowest();
min[i] = std::numeric_limits<float>::max();
}
@@ -43,7 +43,7 @@ void Geometry::CalculateBoundingBox( float*& min, float*& max )
void Geometry::CalculateMinMaxHeight( float& min, float& max )
{
min = std::numeric_limits<float>::max();
- max = std::numeric_limits<float>::min();
+ max = std::numeric_limits<float>::lowest();
for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr)
{
diff --git a/src/tools/mesh_extractor/MPQ.h b/src/tools/mesh_extractor/MPQ.h
index 2f8b082f526..30e11741550 100644
--- a/src/tools/mesh_extractor/MPQ.h
+++ b/src/tools/mesh_extractor/MPQ.h
@@ -26,7 +26,8 @@ public:
libmpq__off_t size, transferred;
libmpq__file_unpacked_size(mpq_a, filenum, &size);
- char *buffer = new char[size];
+ char* buffer = new char[size + 1];
+ buffer[size] = '\0';
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
diff --git a/src/tools/mesh_extractor/MPQManager.cpp b/src/tools/mesh_extractor/MPQManager.cpp
index e1ce4b92bf9..4d3ab808a2e 100644
--- a/src/tools/mesh_extractor/MPQManager.cpp
+++ b/src/tools/mesh_extractor/MPQManager.cpp
@@ -109,5 +109,7 @@ FILE* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file )
exit(1);
}
fwrite(buffer, sizeof(uint8), size, ret);
+ fseek(ret, 0, SEEK_SET);
+ delete[] buffer;
return ret;
}
diff --git a/src/tools/mesh_extractor/MeshExtractor.cpp b/src/tools/mesh_extractor/MeshExtractor.cpp
index 3443b3d9e0a..0d9160a610b 100644
--- a/src/tools/mesh_extractor/MeshExtractor.cpp
+++ b/src/tools/mesh_extractor/MeshExtractor.cpp
@@ -76,7 +76,7 @@ void ExtractDBCs()
std::string component = "component.wow-" + std::string(MPQManager::Languages[*itr]) + ".txt";
// Extract the component file
- Utils::SaveToDisk(MPQHandler->GetFile(component), path + component);
+ Utils::SaveToDisk(MPQHandler->GetFileFrom(component, MPQHandler->LocaleFiles[*itr]), path + component);
// Extract the DBC files for the given locale
for (std::set<std::string>::iterator itr2 = DBCFiles.begin(); itr2 != DBCFiles.end(); ++itr2)
Utils::SaveToDisk(MPQHandler->GetFileFrom(*itr2, MPQHandler->LocaleFiles[*itr]), path + (itr2->c_str() + folderLen));
@@ -378,8 +378,8 @@ int main(int argc, char* argv[])
if (extractFlags & Constants::EXTRACT_FLAG_TEST)
{
- float start[] = { -44.641f, -34.606f, -1.045f };
- float end[] = { -66.18f, 20.222f, -1.128f };
+ float start[] = { 16226.200195f, 16257.000000f, 13.202200f };
+ float end[] = { 16245.725586f, 16382.465820f, 47.384956f };
//
float m_spos[3];
@@ -408,7 +408,7 @@ int main(int argc, char* argv[])
dtPolyRef m_startRef;
dtPolyRef m_endRef;
- FILE* mmap = fopen("mmaps/555.mmap", "rb");
+ FILE* mmap = fopen("mmaps/001.mmap", "rb");
dtNavMeshParams params;
int count = fread(&params, sizeof(dtNavMeshParams), 1, mmap);
fclose(mmap);
@@ -427,7 +427,7 @@ int main(int argc, char* argv[])
for (int j = 0; j <= 32; ++j)
{
char buff[100];
- sprintf(buff, "mmaps/555%02i%02i.mmtile", i, j);
+ sprintf(buff, "mmaps/001%02i%02i.mmtile", i, j);
LoadTile(navMesh, buff);
}
}
diff --git a/src/tools/mesh_extractor/TileBuilder.cpp b/src/tools/mesh_extractor/TileBuilder.cpp
index 13566456329..51df91d2652 100644
--- a/src/tools/mesh_extractor/TileBuilder.cpp
+++ b/src/tools/mesh_extractor/TileBuilder.cpp
@@ -283,6 +283,15 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail();
rcBuildPolyMeshDetail(Context, *pmesh, *chf, Config.detailSampleDist, Config.detailSampleMaxError, *dmesh);
+ // Set flags according to area types (e.g. Swim for Water)
+ for (int i = 0; i < pmesh->npolys; i++)
+ {
+ if (pmesh->areas[i] == Constants::POLY_AREA_ROAD || pmesh->areas[i] == Constants::POLY_AREA_TERRAIN)
+ pmesh->flags[i] = Constants::POLY_FLAG_WALK;
+ else if (pmesh->areas[i] == Constants::POLY_AREA_WATER)
+ pmesh->flags[i] = Constants::POLY_FLAG_SWIM;
+ }
+
dtNavMeshCreateParams params;
memset(&params, 0, sizeof(params));
// PolyMesh data
@@ -299,21 +308,25 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
params.detailVertsCount = dmesh->nverts;
params.detailTris = dmesh->tris;
params.detailTriCount = dmesh->ntris;
- rcVcopy(params.bmin, pmesh->bmin);
- rcVcopy(params.bmax, pmesh->bmax);
// General settings
- params.ch = InstanceConfig.ch;
- params.cs = InstanceConfig.cs;
- params.walkableClimb = InstanceConfig.walkableClimb * InstanceConfig.ch;
- params.walkableHeight = InstanceConfig.walkableHeight * InstanceConfig.ch;
- params.walkableRadius = InstanceConfig.walkableRadius * InstanceConfig.cs;
+ params.ch = Config.ch;
+ params.cs = Config.cs;
+ params.walkableClimb = Config.walkableClimb * Config.ch;
+ params.walkableHeight = Config.walkableHeight * Config.ch;
+ params.walkableRadius = Config.walkableRadius * Config.cs;
params.tileX = X;
params.tileY = Y;
params.tileLayer = 0;
params.buildBvTree = true;
- rcVcopy(params.bmax, bmax);
- rcVcopy(params.bmin, bmin);
+ // Recalculate the bounds with the added geometry
+ float* bmin2 = NULL, *bmax2 = NULL;
+ CalculateTileBounds(bmin2, bmax2, navMeshParams);
+ bmin2[1] = bmin[1];
+ bmax2[1] = bmax[1];
+
+ rcVcopy(params.bmax, bmax2);
+ rcVcopy(params.bmin, bmin2);
// Offmesh-connection settings
params.offMeshConCount = 0; // none for now
diff --git a/src/tools/mesh_extractor/Utils.cpp b/src/tools/mesh_extractor/Utils.cpp
index e7ffc0ed919..24cfb5cd1db 100644
--- a/src/tools/mesh_extractor/Utils.cpp
+++ b/src/tools/mesh_extractor/Utils.cpp
@@ -173,24 +173,38 @@ void Utils::SaveToDisk( FILE* stream, const std::string& path )
if (!disk)
{
printf("SaveToDisk: Could not save file %s to disk, please verify that you have write permissions on that directory\n", path.c_str());
+ fclose(stream);
return;
}
uint32 size = Utils::Size(stream);
uint8* data = new uint8[size];
// Read the data to an array
- if (fread(data, 1, size, stream) != 1)
+ size_t read = fread(data, size, 1, stream);
+ if (read != 1)
{
- printf("SaveToDisk: Error reading from Stream while trying to save file %s to disck.\n", path.c_str());
+ printf("SaveToDisk: Error reading from Stream while trying to save file %s to disk.\n", path.c_str());
+ fclose(disk);
+ fclose(stream);
return;
}
+
// And write it in the file
- fwrite(data, 1, size, disk);
+ size_t wrote = fwrite(data, size, 1, disk);
+ if (wrote != 1)
+ {
+ printf("SaveToDisk: Error writing to the file while trying to save %s to disk.\n", path.c_str());
+ fclose(stream);
+ fclose(disk);
+ return;
+ }
// Close the filestream
fclose(disk);
+ fclose(stream);
+
// Free the used memory
- delete [] data;
+ delete[] data;
}
Vector3 Utils::ToWoWCoords(const Vector3& vec )