Dynamic Creature/Go spawning

Port From (https://github.com/TrinityCore/TrinityCore/commit/03b125e6d1947258316c931499746696a95aded2)
This commit is contained in:
hondacrx
2020-08-23 21:52:32 -04:00
parent 8fc9c45d50
commit 15ae7a7c66
45 changed files with 3925 additions and 1963 deletions
@@ -71,6 +71,7 @@ namespace Game.Entities
//Formation var
CreatureGroup m_formation;
bool TriggerJustRespawned;
bool m_respawnCompatibilityMode;
public uint[] m_spells = new uint[SharedConst.MaxCreatureSpells];
+247 -158
View File
@@ -123,45 +123,62 @@ namespace Game.Entities
if (GetDeathState() != DeathState.Corpse)
return;
m_corpseRemoveTime = Time.UnixTime;
SetDeathState(DeathState.Dead);
RemoveAllAuras();
DestroyForNearbyPlayers(); // old UpdateObjectVisibility()
loot.Clear();
uint respawnDelay = m_respawnDelay;
if (IsAIEnabled)
GetAI().CorpseRemoved(respawnDelay);
if (destroyForNearbyPlayers)
DestroyForNearbyPlayers();
// Should get removed later, just keep "compatibility" with scripts
if (setSpawnTime)
m_respawnTime = Math.Max(Time.UnixTime + respawnDelay, m_respawnTime);
// if corpse was removed during falling, the falling will continue and override relocation to respawn position
if (IsFalling())
StopMoving();
float x, y, z, o;
GetRespawnPosition(out x, out y, out z, out o);
// We were spawned on transport, calculate real position
if (IsSpawnedOnTransport())
if (m_respawnCompatibilityMode)
{
Position pos = m_movementInfo.transport.pos;
pos.posX = x;
pos.posY = y;
pos.posZ = z;
pos.SetOrientation(o);
m_corpseRemoveTime = Time.UnixTime;
SetDeathState(DeathState.Dead);
RemoveAllAuras();
//DestroyForNearbyPlayers(); // old UpdateObjectVisibility()
loot.Clear();
uint respawnDelay = m_respawnDelay;
if (IsAIEnabled)
GetAI().CorpseRemoved(respawnDelay);
ITransport transport = GetDirectTransport();
if (transport != null)
transport.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
if (destroyForNearbyPlayers)
DestroyForNearbyPlayers();
// Should get removed later, just keep "compatibility" with scripts
if (setSpawnTime)
m_respawnTime = Math.Max(Time.UnixTime + respawnDelay, m_respawnTime);
// if corpse was removed during falling, the falling will continue and override relocation to respawn position
if (IsFalling())
StopMoving();
float x, y, z, o;
GetRespawnPosition(out x, out y, out z, out o);
// We were spawned on transport, calculate real position
if (IsSpawnedOnTransport())
{
Position pos = m_movementInfo.transport.pos;
pos.posX = x;
pos.posY = y;
pos.posZ = z;
pos.SetOrientation(o);
ITransport transport = GetDirectTransport();
if (transport != null)
transport.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
}
SetHomePosition(x, y, z, o);
GetMap().CreatureRelocation(this, x, y, z, o);
}
else
{
// In case this is called directly and normal respawn timer not set
// Since this timer will be longer than the already present time it
// will be ignored if the correct place added a respawn timer
if (setSpawnTime)
{
uint respawnDelay = m_respawnDelay;
m_respawnTime = Math.Max(Time.UnixTime + respawnDelay, m_respawnTime);
SetHomePosition(x, y, z, o);
GetMap().CreatureRelocation(this, x, y, z, o);
SaveRespawnTime(0, false);
}
AddObjectToRemoveList();
}
}
public bool InitEntry(uint entry, CreatureData data = null)
@@ -375,7 +392,7 @@ namespace Game.Entities
{
case DeathState.JustRespawned:
case DeathState.JustDied:
Log.outError(LogFilter.Unit, "Creature ({0}) in wrong state: {2}", GetGUID().ToString(), m_deathState);
Log.outError(LogFilter.Unit, "Creature ({0}) in wrong state: {1}", GetGUID().ToString(), m_deathState);
break;
case DeathState.Dead:
{
@@ -383,22 +400,25 @@ namespace Game.Entities
if (m_respawnTime <= now)
{
// First check if there are any scripts that object to us respawning
if (!Global.ScriptMgr.CanSpawn(GetSpawnId(), GetEntry(), GetCreatureTemplate(), GetCreatureData(), GetMap()))
break; // Will be rechecked on next Update call
if (!Global.ScriptMgr.CanSpawn(GetSpawnId(), GetEntry(), GetCreatureData(), GetMap()))
{
m_respawnTime = now + RandomHelper.URand(4, 7);
break; // Will be rechecked on next Update call after delay expires
}
ObjectGuid dbtableHighGuid = ObjectGuid.Create(HighGuid.Creature, GetMapId(), GetEntry(), m_spawnId);
long linkedRespawntime = GetMap().GetLinkedRespawnTime(dbtableHighGuid);
if (linkedRespawntime == 0) // Can respawn
long linkedRespawnTime = GetMap().GetLinkedRespawnTime(dbtableHighGuid);
if (linkedRespawnTime == 0) // Can respawn
Respawn();
else // the master is dead
{
ObjectGuid targetGuid = Global.ObjectMgr.GetLinkedRespawnGuid(dbtableHighGuid);
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
SetRespawnTime(Time.Day);
SetRespawnTime(Time.Week);
else
{
// else copy time from master and add a little
long baseRespawnTime = Math.Max(linkedRespawntime, now);
long baseRespawnTime = Math.Max(linkedRespawnTime, now);
long offset = RandomHelper.URand(5, Time.Minute);
// linked guid can be a boss, uses std::numeric_limits<time_t>::max to never respawn in that instance
@@ -731,7 +751,7 @@ namespace Game.Entities
lowGuid = map.GenerateLowGuid(HighGuid.Creature);
Creature creature = new Creature();
if (!creature.Create(lowGuid, map, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), null, vehId))
if (!creature.Create(lowGuid, map, entry, pos, null, vehId))
return null;
return creature;
@@ -740,13 +760,13 @@ namespace Game.Entities
public static Creature CreateCreatureFromDB(ulong spawnId, Map map, bool addToMap = true, bool allowDuplicate = false)
{
Creature creature = new Creature();
if (!creature.LoadCreatureFromDB(spawnId, map, addToMap, allowDuplicate))
if (!creature.LoadFromDB(spawnId, map, addToMap, allowDuplicate))
return null;
return creature;
}
public bool Create(ulong guidlow, Map map, uint entry, float x, float y, float z, float ang, CreatureData data, uint vehId)
public bool Create(ulong guidlow, Map map, uint entry, Position pos, CreatureData data = null, uint vehId = 0, bool dynamic = false)
{
SetMap(map);
@@ -756,6 +776,10 @@ namespace Game.Entities
PhasingHandler.InitDbVisibleMapId(GetPhaseShift(), data.terrainSwapMap);
}
// Set if this creature can handle dynamic spawns
if (!dynamic)
SetRespawnCompatibilityMode();
CreatureTemplate cinfo = Global.ObjectMgr.GetCreatureTemplate(entry);
if (cinfo == null)
{
@@ -765,13 +789,13 @@ namespace Game.Entities
//! Relocate before CreateFromProto, to initialize coords and allow
//! returning correct zone id for selecting OutdoorPvP/Battlefield script
Relocate(x, y, z, ang);
Relocate(pos);
// Check if the position is valid before calling CreateFromProto(), otherwise we might add Auras to Creatures at
// invalid position, triggering a crash about Auras not removed in the destructor
if (!IsPositionValid())
{
Log.outError(LogFilter.Unit, "Creature.Create: given coordinates for creature (guidlow {0}, entry {1}) are not valid (X: {2}, Y: {3}, Z: {4}, O: {5})", guidlow, entry, x, y, z, ang);
Log.outError(LogFilter.Unit, $"Creature.Create: given coordinates for creature (guidlow {guidlow}, entry {entry}) are not valid ({pos})");
return false;
}
UpdatePositionData();
@@ -810,10 +834,8 @@ namespace Game.Entities
//! Need to be called after LoadCreaturesAddon - MOVEMENTFLAG_HOVER is set there
if (HasUnitMovementFlag(MovementFlag.Hover))
{
z += m_unitData.HoverHeight;
//! Relocate again with updated Z coord
Relocate(x, y, z, ang);
posZ += m_unitData.HoverHeight;
}
LastUsedScriptID = GetScriptId();
@@ -924,6 +946,14 @@ namespace Game.Entities
&& !GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoXpAtKill);
}
public bool IsEscortNPC(bool onlyIfActive = true)
{
if (!IsAIEnabled)
return false;
return GetAI().IsEscortNPC(onlyIfActive);
}
public override bool IsMovementPreventedByCasting()
{
// first check if currently a movement allowed channel is active and we're not casting
@@ -1068,16 +1098,20 @@ namespace Game.Entities
dynamicflags = 0;
}
// data.guid = guid must not be updated at save
data.id = GetEntry();
data.mapid = (ushort)mapid;
if (data.spawnId == 0)
data.spawnId = m_spawnId;
Cypher.Assert(data.spawnId == m_spawnId);
data.Id = GetEntry();
data.displayid = displayId;
data.equipmentId = GetCurrentEquipmentId();
data.posX = GetPositionX();
data.posY = GetPositionY();
data.posZ = GetPositionZMinusOffset();
data.orientation = GetOrientation();
data.spawntimesecs = m_respawnDelay;
data.equipmentId = (sbyte)GetCurrentEquipmentId();
if (GetTransport() == null)
data.spawnPoint.WorldRelocate(this);
else
data.spawnPoint.WorldRelocate(mapid, GetTransOffsetX(), GetTransOffsetY(), GetTransOffsetZ(), GetTransOffsetO());
data.spawntimesecs = (int)m_respawnDelay;
// prevent add data integrity problems
data.spawndist = GetDefaultMovementType() == MovementGeneratorType.Idle ? 0.0f : m_respawnradius;
data.currentwaypoint = 0;
@@ -1092,6 +1126,8 @@ namespace Game.Entities
data.unit_flags2 = unitFlags2;
data.unit_flags3 = unitFlags3;
data.dynamicflags = (uint)dynamicflags;
if (data.spawnGroupData == null)
data.spawnGroupData = Global.ObjectMgr.GetDefaultSpawnGroup();
data.phaseId = GetDBPhase() > 0 ? (uint)GetDBPhase() : data.phaseId;
data.phaseGroup = GetDBPhase() < 0 ? (uint)-GetDBPhase() : data.phaseGroup;
@@ -1414,7 +1450,7 @@ namespace Game.Entities
return;
}
GetMap().RemoveCreatureRespawnTime(m_spawnId);
GetMap().RemoveRespawnTime(SpawnObjectType.Creature, m_spawnId);
Global.ObjectMgr.DeleteCreatureData(m_spawnId);
SQLTransaction trans = new SQLTransaction();
@@ -1423,6 +1459,11 @@ namespace Game.Entities
stmt.AddValue(0, m_spawnId);
trans.Append(stmt);
stmt = DB.World.GetPreparedStatement(WorldStatements.DEL_SPAWNGROUP_MEMBER);
stmt.AddValue(0, (byte)SpawnObjectType.Creature);
stmt.AddValue(1, m_spawnId);
trans.Append(stmt);
stmt = DB.World.GetPreparedStatement(WorldStatements.DEL_CREATURE_ADDON);
stmt.AddValue(0, m_spawnId);
trans.Append(stmt);
@@ -1549,14 +1590,31 @@ namespace Game.Entities
if (s == DeathState.JustDied)
{
m_corpseRemoveTime = Time.UnixTime + m_corpseDelay;
if (IsDungeonBoss() && m_respawnDelay == 0)
m_respawnTime = long.MaxValue; // never respawn in this instance
uint respawnDelay = m_respawnDelay;
uint scalingMode = WorldConfig.GetUIntValue(WorldCfg.RespawnDynamicMode);
if (scalingMode != 0)
GetMap().ApplyDynamicModeRespawnScaling(this, m_spawnId, ref respawnDelay, scalingMode);
// @todo remove the boss respawn time hack in a dynspawn follow-up once we have creature groups in instances
if (m_respawnCompatibilityMode)
{
if (IsDungeonBoss() && m_respawnDelay == 0)
m_respawnTime = long.MaxValue; // never respawn in this instance
else
m_respawnTime = Time.UnixTime + respawnDelay + m_corpseDelay;
}
else
m_respawnTime = Time.UnixTime + m_respawnDelay + m_corpseDelay;
{
if (IsDungeonBoss() && m_respawnDelay == 0)
m_respawnTime = long.MaxValue; // never respawn in this instance
else
m_respawnTime = Time.UnixTime + respawnDelay;
}
// always save boss respawn time at death to prevent crash cheating
if (WorldConfig.GetBoolValue(WorldCfg.SaveRespawnTimeImmediately) || IsWorldBoss())
SaveRespawnTime();
else if (!m_respawnCompatibilityMode)
SaveRespawnTime(0, false);
ReleaseFocus(null, false); // remove spellcast focus
DoNotReacquireTarget(); // cancel delayed re-target
@@ -1632,8 +1690,6 @@ namespace Game.Entities
public void Respawn(bool force = false)
{
DestroyForNearbyPlayers();
if (force)
{
if (IsAlive())
@@ -1642,49 +1698,60 @@ namespace Game.Entities
SetDeathState(DeathState.Corpse);
}
RemoveCorpse(false, false);
if (GetDeathState() == DeathState.Dead)
if (m_respawnCompatibilityMode)
{
if (m_spawnId != 0)
GetMap().RemoveCreatureRespawnTime(m_spawnId);
DestroyForNearbyPlayers();
RemoveCorpse(false, false);
Log.outDebug(LogFilter.Unit, "Respawning creature {0} ({1})", GetName(), GetGUID().ToString());
m_respawnTime = 0;
ResetPickPocketRefillTimer();
loot.Clear();
if (GetDeathState() == DeathState.Dead)
{
if (m_spawnId != 0)
GetMap().RemoveRespawnTime(SpawnObjectType.Creature, m_spawnId);
Log.outDebug(LogFilter.Unit, "Respawning creature {0} ({1})", GetName(), GetGUID().ToString());
m_respawnTime = 0;
ResetPickPocketRefillTimer();
loot.Clear();
if (m_originalEntry != GetEntry())
UpdateEntry(m_originalEntry);
if (m_originalEntry != GetEntry())
UpdateEntry(m_originalEntry);
else
SelectLevel();
SetDeathState(DeathState.JustRespawned);
SetDeathState(DeathState.JustRespawned);
CreatureModel display = new CreatureModel(GetNativeDisplayId(), GetNativeDisplayScale(), 1.0f);
if (Global.ObjectMgr.GetCreatureModelRandomGender(ref display, GetCreatureTemplate()) != null)
{
SetDisplayId(display.CreatureDisplayID, display.DisplayScale);
SetNativeDisplayId(display.CreatureDisplayID, display.DisplayScale);
CreatureModel display = new CreatureModel(GetNativeDisplayId(), GetNativeDisplayScale(), 1.0f);
if (Global.ObjectMgr.GetCreatureModelRandomGender(ref display, GetCreatureTemplate()) != null)
{
SetDisplayId(display.CreatureDisplayID, display.DisplayScale);
SetNativeDisplayId(display.CreatureDisplayID, display.DisplayScale);
}
GetMotionMaster().InitDefault();
//Re-initialize reactstate that could be altered by movementgenerators
InitializeReactState();
//Call AI respawn virtual function//Call AI respawn virtual function
if (IsAIEnabled)
{
//reset the AI to be sure no dirty or uninitialized values will be used till next tick
GetAI().Reset();
TriggerJustRespawned = true;//delay event to next tick so all creatures are created on the map before processing
}
uint poolid = GetSpawnId() != 0 ? Global.PoolMgr.IsPartOfAPool<Creature>(GetSpawnId()) : 0;
if (poolid != 0)
Global.PoolMgr.UpdatePool<Creature>(poolid, GetSpawnId());
}
GetMotionMaster().InitDefault();
//Re-initialize reactstate that could be altered by movementgenerators
InitializeReactState();
//Call AI respawn virtual function
if (IsAIEnabled)
{
GetAI().Reset();
TriggerJustRespawned = true;//delay event to next tick so all creatures are created on the map before processing
}
uint poolid = GetSpawnId() != 0 ? Global.PoolMgr.IsPartOfAPool<Creature>(GetSpawnId()) : 0;
if (poolid != 0)
Global.PoolMgr.UpdatePool<Creature>(poolid, GetSpawnId());
UpdateObjectVisibility();
}
else
{
if (m_spawnId != 0)
GetMap().RemoveRespawnTime(SpawnObjectType.Creature, m_spawnId, true);
}
UpdateObjectVisibility();
Log.outDebug(LogFilter.Unit, $"Respawning creature {GetName()} ({GetGUID()})");
}
public void ForcedDespawn(uint timeMSToDespawn = 0, TimeSpan forceRespawnTimer = default)
@@ -1695,30 +1762,49 @@ namespace Game.Entities
return;
}
uint corpseDelay = GetCorpseDelay();
uint respawnDelay = GetRespawnDelay();
// do it before killing creature
DestroyForNearbyPlayers();
bool overrideRespawnTime = false;
if (IsAlive())
if (m_respawnCompatibilityMode)
{
if (forceRespawnTimer > TimeSpan.Zero)
uint corpseDelay = GetCorpseDelay();
uint respawnDelay = GetRespawnDelay();
// do it before killing creature
DestroyForNearbyPlayers();
bool overrideRespawnTime = false;
if (IsAlive())
{
SetCorpseDelay(0);
SetRespawnDelay((uint)forceRespawnTimer.TotalSeconds);
overrideRespawnTime = false;
if (forceRespawnTimer > TimeSpan.Zero)
{
SetCorpseDelay(0);
SetRespawnDelay((uint)forceRespawnTimer.TotalSeconds);
overrideRespawnTime = false;
}
SetDeathState(DeathState.JustDied);
}
SetDeathState(DeathState.JustDied);
// Skip corpse decay time
RemoveCorpse(overrideRespawnTime, false);
SetCorpseDelay(corpseDelay);
SetRespawnDelay(respawnDelay);
}
else
{
if (forceRespawnTimer > TimeSpan.Zero)
SaveRespawnTime((uint)forceRespawnTimer.TotalSeconds);
else
{
uint respawnDelay = m_respawnDelay;
uint scalingMode = WorldConfig.GetUIntValue(WorldCfg.RespawnDynamicMode);
if (scalingMode != 0)
GetMap().ApplyDynamicModeRespawnScaling(this, m_spawnId, ref respawnDelay, scalingMode);
m_respawnTime = Time.UnixTime + respawnDelay;
SaveRespawnTime();
}
// Skip corpse decay time
RemoveCorpse(overrideRespawnTime, false);
SetCorpseDelay(corpseDelay);
SetRespawnDelay(respawnDelay);
AddObjectToRemoveList();
}
}
public void DespawnOrUnsummon(TimeSpan time, TimeSpan forceRespawnTimer = default) { DespawnOrUnsummon((uint)time.TotalMilliseconds, forceRespawnTimer); }
@@ -2074,12 +2160,19 @@ namespace Game.Entities
return false;
}
public override void SaveRespawnTime()
public override void SaveRespawnTime(uint forceDelay = 0, bool saveToDb = true)
{
if (IsSummon() || m_spawnId == 0 || (m_creatureData != null && !m_creatureData.dbData))
return;
GetMap().SaveCreatureRespawnTime(m_spawnId, m_respawnTime);
if (m_respawnCompatibilityMode)
{
GetMap().SaveRespawnTimeDB(SpawnObjectType.Creature, m_spawnId, m_respawnTime);
return;
}
uint thisRespawnTime = (uint)(forceDelay != 0 ? Time.UnixTime + forceDelay : m_respawnTime);
GetMap().SaveRespawnTime(SpawnObjectType.Creature, m_spawnId, GetEntry(), thisRespawnTime, GetMap().GetZoneId(GetPhaseShift(), GetHomePosition()), GridDefines.ComputeGridCoord(GetHomePosition().GetPositionX(), GetHomePosition().GetPositionY()).GetId(), m_creatureData.dbData && saveToDb);
}
public bool CanCreatureAttack(Unit victim, bool force = true)
@@ -2293,32 +2386,20 @@ namespace Game.Entities
}
public void GetRespawnPosition(out float x, out float y, out float z, out float ori, out float dist)
{
// for npcs on transport, this will return transport offset
if (m_spawnId != 0)
if (m_creatureData != null)
{
CreatureData data = Global.ObjectMgr.GetCreatureData(GetSpawnId());
if (data != null)
{
x = data.posX;
y = data.posY;
z = data.posZ;
ori = data.orientation;
dist = data.spawndist;
return;
}
m_creatureData.spawnPoint.GetPosition(out x, out y, out z, out ori);
dist = m_creatureData.spawndist;
}
else
{
Position homePos = GetHomePosition();
homePos.GetPosition(out x, out y, out z, out ori);
dist = 0;
}
// changed this from current position to home position, fixes world summons with infinite duration (wg npcs for example)
Position homePos = GetHomePosition();
x = homePos.GetPositionX();
y = homePos.GetPositionY();
z = homePos.GetPositionZ();
ori = homePos.GetOrientation();
dist = 0;
}
bool IsSpawnedOnTransport() { return m_creatureData != null && m_creatureData.mapid != GetMapId(); }
bool IsSpawnedOnTransport() { return m_creatureData != null && m_creatureData.spawnPoint.GetMapId() != GetMapId(); }
public void AllLootRemovedFromCorpse()
{
@@ -2934,12 +3015,7 @@ namespace Game.Entities
public CreatureTemplate GetCreatureTemplate() { return m_creatureInfo; }
public CreatureData GetCreatureData() { return m_creatureData; }
public override bool LoadFromDB(ulong spawnId, Map map)
{
return LoadCreatureFromDB(spawnId, map, false, false);
}
public bool LoadCreatureFromDB(ulong spawnId, Map map, bool addToMap, bool allowDuplicate)
public override bool LoadFromDB(ulong spawnId, Map map, bool addToMap, bool allowDuplicate)
{
if (!allowDuplicate)
{
@@ -2976,39 +3052,48 @@ namespace Game.Entities
}
m_spawnId = spawnId;
m_respawnCompatibilityMode = data.spawnGroupData.flags.HasAnyFlag(SpawnGroupFlags.CompatibilityMode);
m_creatureData = data;
m_respawnradius = data.spawndist;
m_respawnDelay = data.spawntimesecs;
if (!Create(map.GenerateLowGuid(HighGuid.Creature), map, data.id, data.posX, data.posY, data.posZ, data.orientation, data, 0))
m_respawnDelay = (uint)data.spawntimesecs;
// Is the creature script objecting to us spawning? If yes, delay by a little bit (then re-check in ::Update)
if (!m_respawnCompatibilityMode && m_respawnTime == 0 && !Global.ScriptMgr.CanSpawn(spawnId, data.Id, data, map))
{
SaveRespawnTime(RandomHelper.URand(4, 7));
return false;
}
if (!Create(map.GenerateLowGuid(HighGuid.Creature), map, data.Id, data.spawnPoint, data, 0, !m_respawnCompatibilityMode))
return false;
//We should set first home position, because then AI calls home movement
SetHomePosition(data.posX, data.posY, data.posZ, data.orientation);
SetHomePosition(data.spawnPoint);
m_deathState = DeathState.Alive;
m_respawnTime = GetMap().GetCreatureRespawnTime(m_spawnId);
// Is the creature script objecting to us spawning? If yes, delay by one second (then re-check in ::Update)
if (m_respawnTime == 0 && !Global.ScriptMgr.CanSpawn(spawnId, GetEntry(), GetCreatureTemplate(), GetCreatureData(), map))
m_respawnTime = Time.UnixTime + 1;
// Is the creature script objecting to us spawning? If yes, delay by a little bit (then re-check in ::Update)
if (m_respawnCompatibilityMode && m_respawnTime == 0 && !Global.ScriptMgr.CanSpawn(spawnId, GetEntry(), GetCreatureData(), map))
m_respawnTime = Time.UnixTime + RandomHelper.URand(4, 7);
if (m_respawnTime != 0) // respawn on Update
if (m_respawnTime != 0) // respawn on UpdateLoadCreatureFromDB
{
m_deathState = DeathState.Dead;
if (CanFly())
{
float tz = map.GetHeight(GetPhaseShift(), data.posX, data.posY, data.posZ, true, MapConst.MaxFallDistance);
if (data.posZ - tz > 0.1f && GridDefines.IsValidMapCoord(tz))
Relocate(data.posX, data.posY, tz);
float tz = map.GetHeight(GetPhaseShift(), data.spawnPoint, true, MapConst.MaxFallDistance);
if (data.spawnPoint.GetPositionZ() - tz > 0.1f && GridDefines.IsValidMapCoord(tz))
Relocate(data.spawnPoint.GetPositionX(), data.spawnPoint.GetPositionY(), tz);
}
}
SetSpawnHealth();
// checked at creature_template loading
DefaultMovementType = (MovementGeneratorType)data.movementType;
loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, data.mapid, data.id, GetMap().GenerateLowGuid(HighGuid.LootObject)));
loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, GetMapId(), data.Id, GetMap().GenerateLowGuid(HighGuid.LootObject)));
if (addToMap && !GetMap().AddToMap(this))
return false;
@@ -3102,6 +3187,10 @@ namespace Game.Entities
m_originalEntry = entry;
}
// There's many places not ready for dynamic spawns. This allows them to live on for now.
void SetRespawnCompatibilityMode(bool mode = true) { m_respawnCompatibilityMode = mode; }
public bool GetRespawnCompatibilityMode() { return m_respawnCompatibilityMode; }
public Unit SelectVictim()
{
// function provides main threat functionality
+8 -19
View File
@@ -21,6 +21,7 @@ using System;
using System.Collections.Generic;
using Framework.Dynamic;
using Game.Networking.Packets;
using Game.Maps;
namespace Game.Entities
{
@@ -327,34 +328,22 @@ namespace Game.Entities
public EquipmentItem[] Items = new EquipmentItem[SharedConst.MaxEquipmentItems];
}
public class CreatureData
public class CreatureData : SpawnData
{
public uint id; // entry in creature_template
public ushort mapid;
public uint displayid;
public int equipmentId;
public float posX;
public float posY;
public float posZ;
public float orientation;
public uint spawntimesecs;
public sbyte equipmentId;
public float spawndist;
public uint currentwaypoint;
public uint curhealth;
public uint curmana;
public byte movementType;
public List<Difficulty> spawnDifficulties = new List<Difficulty>();
public ulong npcflag;
public uint unit_flags; // enum UnitFlags mask values
public uint unit_flags2; // enum UnitFlags2 mask values
public uint unit_flags3; // enum UnitFlags3 mask values
public uint unit_flags; // enum UnitFlags mask values
public uint unit_flags2; // enum UnitFlags2 mask values
public uint unit_flags3; // enum UnitFlags3 mask values
public uint dynamicflags;
public PhaseUseFlagsValues phaseUseFlags;
public uint phaseId;
public uint phaseGroup;
public int terrainSwapMap;
public uint ScriptId;
public bool dbData;
public CreatureData() : base(SpawnObjectType.Creature) { }
}
public class CreatureModelInfo
+151 -123
View File
@@ -166,7 +166,7 @@ namespace Game.Entities
return null;
GameObject go = new GameObject();
if (!go.Create(entry, map, pos, rotation, animProgress, goState, artKit))
if (!go.Create(entry, map, pos, rotation, animProgress, goState, artKit, false, 0))
return null;
return go;
@@ -175,13 +175,13 @@ namespace Game.Entities
public static GameObject CreateGameObjectFromDB(ulong spawnId, Map map, bool addToMap = true)
{
GameObject go = new GameObject();
if (!go.LoadGameObjectFromDB(spawnId, map, addToMap))
if (!go.LoadFromDB(spawnId, map, addToMap))
return null;
return go;
}
bool Create(uint entry, Map map, Position pos, Quaternion rotation, uint animProgress, GameObjectState goState, uint artKit)
bool Create(uint entry, Map map, Position pos, Quaternion rotation, uint animProgress, GameObjectState goState, uint artKit, bool dynamic, ulong spawnid)
{
Cypher.Assert(map);
SetMap(map);
@@ -194,6 +194,10 @@ namespace Game.Entities
return false;
}
// Set if this object can handle dynamic spawns
if (!dynamic)
SetRespawnCompatibilityMode();
UpdatePositionData();
SetZoneScript();
@@ -373,6 +377,9 @@ namespace Game.Entities
if (map.Is25ManRaid())
loot.maxDuplicates = 3;
if (spawnid != 0)
m_spawnId = spawnid;
uint linkedEntry = GetGoInfo().GetLinkedGameObjectEntry();
if (linkedEntry != 0)
{
@@ -507,81 +514,88 @@ namespace Game.Entities
goto case LootState.Ready;
case LootState.Ready:
{
if (m_respawnTime > 0) // timer on
if (m_respawnCompatibilityMode)
{
long now = Time.UnixTime;
if (m_respawnTime <= now) // timer expired
if (m_respawnTime > 0) // timer on
{
ObjectGuid dbtableHighGuid = ObjectGuid.Create(HighGuid.GameObject, GetMapId(), GetEntry(), m_spawnId);
long linkedRespawntime = GetMap().GetLinkedRespawnTime(dbtableHighGuid);
if (linkedRespawntime != 0) // Can't respawn, the master is dead
long now = Time.UnixTime;
if (m_respawnTime <= now) // timer expired
{
ObjectGuid targetGuid = Global.ObjectMgr.GetLinkedRespawnGuid(dbtableHighGuid);
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
SetRespawnTime(Time.Day);
else
m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + RandomHelper.IRand(5, Time.Minute); // else copy time from master and add a little
SaveRespawnTime(); // also save to DB immediately
return;
}
ObjectGuid dbtableHighGuid = ObjectGuid.Create(HighGuid.GameObject, GetMapId(), GetEntry(), m_spawnId);
long linkedRespawntime = GetMap().GetLinkedRespawnTime(dbtableHighGuid);
if (linkedRespawntime != 0) // Can't respawn, the master is dead
{
ObjectGuid targetGuid = Global.ObjectMgr.GetLinkedRespawnGuid(dbtableHighGuid);
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
SetRespawnTime(Time.Week);
else
m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + RandomHelper.IRand(5, Time.Minute); // else copy time from master and add a little
SaveRespawnTime(); // also save to DB immediately
return;
}
m_respawnTime = 0;
m_SkillupList.Clear();
m_usetimes = 0;
m_respawnTime = 0;
m_SkillupList.Clear();
m_usetimes = 0;
// If nearby linked trap exists, respawn it
GameObject linkedTrap = GetLinkedTrap();
if (linkedTrap)
linkedTrap.SetLootState(LootState.Ready);
// If nearby linked trap exists, respawn it
GameObject linkedTrap = GetLinkedTrap();
if (linkedTrap)
linkedTrap.SetLootState(LootState.Ready);
switch (GetGoType())
{
case GameObjectTypes.FishingNode: // can't fish now
{
Unit caster = GetOwner();
if (caster != null && caster.IsTypeId(TypeId.Player))
switch (GetGoType())
{
case GameObjectTypes.FishingNode: // can't fish now
{
caster.ToPlayer().RemoveGameObject(this, false);
caster.ToPlayer().SendPacket(new FishEscaped());
Unit caster = GetOwner();
if (caster != null && caster.IsTypeId(TypeId.Player))
{
caster.ToPlayer().RemoveGameObject(this, false);
caster.ToPlayer().SendPacket(new FishEscaped());
}
// can be delete
m_lootState = LootState.JustDeactivated;
return;
}
// can be delete
m_lootState = LootState.JustDeactivated;
return;
}
case GameObjectTypes.Door:
case GameObjectTypes.Button:
//we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for Battlegrounds)
if (GetGoState() != GameObjectState.Ready)
ResetDoorOrButton();
break;
case GameObjectTypes.FishingHole:
// Initialize a new max fish count on respawn
m_goValue.FishingHole.MaxOpens = RandomHelper.URand(GetGoInfo().FishingHole.minRestock, GetGoInfo().FishingHole.maxRestock);
break;
default:
break;
case GameObjectTypes.Door:
case GameObjectTypes.Button:
//we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for Battlegrounds)
if (GetGoState() != GameObjectState.Ready)
ResetDoorOrButton();
break;
case GameObjectTypes.FishingHole:
// Initialize a new max fish count on respawn
m_goValue.FishingHole.MaxOpens = RandomHelper.URand(GetGoInfo().FishingHole.minRestock, GetGoInfo().FishingHole.maxRestock);
break;
default:
break;
}
if (!m_spawnedByDefault) // despawn timer
{
// can be despawned or destroyed
SetLootState(LootState.JustDeactivated);
return;
}
// Call AI Reset (required for example in SmartAI to clear one time events)
if (GetAI() != null)
GetAI().Reset();
// respawn timer
uint poolid = GetSpawnId() != 0 ? Global.PoolMgr.IsPartOfAPool<GameObject>(GetSpawnId()) : 0;
if (poolid != 0)
Global.PoolMgr.UpdatePool<GameObject>(poolid, GetSpawnId());
else
GetMap().AddToMap(this);
}
if (!m_spawnedByDefault) // despawn timer
{
// can be despawned or destroyed
SetLootState(LootState.JustDeactivated);
return;
}
// Call AI Reset (required for example in SmartAI to clear one time events)
if (GetAI() != null)
GetAI().Reset();
// respawn timer
uint poolid = GetSpawnId() != 0 ? Global.PoolMgr.IsPartOfAPool<GameObject>(GetSpawnId()) : 0;
if (poolid != 0)
Global.PoolMgr.UpdatePool<GameObject>(poolid, GetSpawnId());
else
GetMap().AddToMap(this);
}
}
// Set respawn timer
if (!m_respawnCompatibilityMode && m_respawnTime > 0)
SaveRespawnTime(0, false);
if (IsSpawned())
{
GameObjectTemplate goInfo = GetGoInfo();
@@ -785,6 +799,7 @@ namespace Game.Entities
if (m_respawnDelayTime == 0)
return;
// ToDo: Decide if we should properly despawn these. Maybe they expect to be able to manually respawn from script?
if (!m_spawnedByDefault)
{
m_respawnTime = 0;
@@ -792,12 +807,29 @@ namespace Game.Entities
return;
}
m_respawnTime = Time.UnixTime + m_respawnDelayTime;
uint respawnDelay = m_respawnDelayTime;
uint scalingMode = WorldConfig.GetUIntValue(WorldCfg.RespawnDynamicMode);
if (scalingMode != 0)
GetMap().ApplyDynamicModeRespawnScaling(this, m_spawnId, ref respawnDelay, scalingMode);
m_respawnTime = Time.UnixTime + respawnDelay;
// if option not set then object will be saved at grid unload
// Otherwise just save respawn time to map object memory
if (WorldConfig.GetBoolValue(WorldCfg.SaveRespawnTimeImmediately))
SaveRespawnTime();
if (!m_respawnCompatibilityMode)
{
// Respawn time was just saved if set to save to DB
// If not, we save only to map memory
if (!WorldConfig.GetBoolValue(WorldCfg.SaveRespawnTimeImmediately))
SaveRespawnTime(0, false);
// Then despawn
AddObjectToRemoveList();
return;
}
DestroyForNearbyPlayers(); // old UpdateObjectVisibility()
break;
}
@@ -890,7 +922,7 @@ namespace Game.Entities
{
// this should only be used when the gameobject has already been loaded
// preferably after adding to map, because mapid may not be valid otherwise
GameObjectData data = Global.ObjectMgr.GetGOData(m_spawnId);
GameObjectData data = Global.ObjectMgr.GetGameObjectData(m_spawnId);
if (data == null)
{
Log.outError(LogFilter.Maps, "GameObject.SaveToDB failed, cannot get gameobject data!");
@@ -911,22 +943,22 @@ namespace Game.Entities
m_spawnId = Global.ObjectMgr.GenerateGameObjectSpawnId();
// update in loaded data (changing data only in this place)
GameObjectData data = new GameObjectData();
GameObjectData data = Global.ObjectMgr.NewOrExistGameObjectData(m_spawnId);
// guid = guid must not be updated at save
data.id = GetEntry();
data.mapid = (ushort)mapid;
data.posX = GetPositionX();
data.posY = GetPositionY();
data.posZ = GetPositionZ();
data.orientation = GetOrientation();
if (data.spawnId == 0)
data.spawnId = m_spawnId;
Cypher.Assert(data.spawnId == m_spawnId);
data.Id = GetEntry();
data.spawnPoint.WorldRelocate(this);
data.rotation = m_worldRotation;
data.spawntimesecs = (int)(m_spawnedByDefault ? m_respawnDelayTime : -m_respawnDelayTime);
data.animprogress = GetGoAnimProgress();
data.go_state = GetGoState();
data.goState = GetGoState();
data.spawnDifficulties = spawnDifficulties;
data.artKit = (byte)GetGoArtKit();
Global.ObjectMgr.NewGOData(m_spawnId, data);
if (data.spawnGroupData == null)
data.spawnGroupData = Global.ObjectMgr.GetDefaultSpawnGroup();
data.phaseId = GetDBPhase() > 0 ? (uint)GetDBPhase() : data.phaseId;
data.phaseGroup = GetDBPhase() < 0 ? (uint)-GetDBPhase() : data.phaseGroup;
@@ -958,24 +990,24 @@ namespace Game.Entities
DB.World.Execute(stmt);
}
bool LoadGameObjectFromDB(ulong spawnId, Map map, bool addToMap)
public override bool LoadFromDB(ulong spawnId, Map map, bool addToMap, bool unused = true)
{
GameObjectData data = Global.ObjectMgr.GetGOData(spawnId);
GameObjectData data = Global.ObjectMgr.GetGameObjectData(spawnId);
if (data == null)
{
Log.outError(LogFilter.Maps, "Gameobject (SpawnId: {0}) not found in table `gameobject`, can't load. ", spawnId);
return false;
}
uint entry = data.id;
Position pos = new Position(data.posX, data.posY, data.posZ, data.orientation);
uint entry = data.Id;
uint animprogress = data.animprogress;
GameObjectState go_state = data.go_state;
GameObjectState go_state = data.goState;
uint artKit = data.artKit;
m_spawnId = spawnId;
if (!Create(entry, map, pos, data.rotation, animprogress, go_state, artKit))
m_respawnCompatibilityMode = ((data.spawnGroupData.flags & SpawnGroupFlags.CompatibilityMode) != 0);
if (!Create(entry, map, data.spawnPoint, data.rotation, animprogress, go_state, artKit, !m_respawnCompatibilityMode, spawnId))
return false;
PhasingHandler.InitDbPhaseShift(GetPhaseShift(), data.phaseUseFlags, data.phaseId, data.phaseGroup);
@@ -1000,7 +1032,7 @@ namespace Game.Entities
if (m_respawnTime != 0 && m_respawnTime <= Time.UnixTime)
{
m_respawnTime = 0;
GetMap().RemoveGORespawnTime(m_spawnId);
GetMap().RemoveRespawnTime(SpawnObjectType.GameObject, m_spawnId);
}
}
}
@@ -1021,20 +1053,20 @@ namespace Game.Entities
public void DeleteFromDB()
{
GetMap().RemoveGORespawnTime(m_spawnId);
Global.ObjectMgr.DeleteGOData(m_spawnId);
GetMap().RemoveRespawnTime(SpawnObjectType.GameObject, m_spawnId);
Global.ObjectMgr.DeleteGameObjectData(m_spawnId);
SQLTransaction trans = new SQLTransaction();
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.DEL_GAMEOBJECT);
stmt.AddValue(0, m_spawnId);
DB.World.Execute(stmt);
trans.Append(stmt);
stmt = DB.World.GetPreparedStatement(WorldStatements.DEL_EVENT_GAMEOBJECT);
stmt.AddValue(0, m_spawnId);
trans.Append(stmt);
DB.World.Execute(stmt);
DB.World.CommitTransaction(trans);
}
public override bool HasQuest(uint quest_id)
@@ -1097,10 +1129,19 @@ namespace Game.Entities
return Global.ObjAccessor.GetUnit(this, GetOwnerGUID());
}
public override void SaveRespawnTime()
public override void SaveRespawnTime(uint forceDelay = 0, bool savetodb = true)
{
if (m_goData != null && m_goData.dbData && m_respawnTime > Time.UnixTime && m_spawnedByDefault)
GetMap().SaveGORespawnTime(m_spawnId, m_respawnTime);
if (m_goData != null && m_respawnTime > Time.UnixTime && m_spawnedByDefault)
{
if (m_respawnCompatibilityMode)
{
GetMap().SaveRespawnTimeDB(SpawnObjectType.GameObject, m_spawnId, m_respawnTime);
return;
}
uint thisRespawnTime = (uint)(forceDelay != 0 ? Time.UnixTime + forceDelay : m_respawnTime);
GetMap().SaveRespawnTime(SpawnObjectType.GameObject, m_spawnId, GetEntry(), thisRespawnTime, GetZoneId(), GridDefines.ComputeGridCoord(GetPositionX(), GetPositionY()).GetId(), m_goData.dbData ? savetodb : false);
}
}
public override bool IsNeverVisibleFor(WorldObject seer)
@@ -1160,7 +1201,7 @@ namespace Game.Entities
if (m_spawnedByDefault && m_respawnTime > 0)
{
m_respawnTime = Time.UnixTime;
GetMap().RemoveGORespawnTime(m_spawnId);
GetMap().RemoveRespawnTime(SpawnObjectType.GameObject, m_spawnId, true);
}
}
@@ -1262,7 +1303,7 @@ namespace Game.Entities
public void SetGoArtKit(byte kit)
{
SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.ArtKit), kit);
GameObjectData data = Global.ObjectMgr.GetGOData(m_spawnId);
GameObjectData data = Global.ObjectMgr.GetGameObjectData(m_spawnId);
if (data != null)
data.artKit = kit;
}
@@ -1273,10 +1314,10 @@ namespace Game.Entities
if (go != null)
{
go.SetGoArtKit(artkit);
data = go.GetGoData();
data = go.GetGameObjectData();
}
else if (lowguid != 0)
data = Global.ObjectMgr.GetGOData(lowguid);
data = Global.ObjectMgr.GetGameObjectData(lowguid);
if (data != null)
data.artKit = artkit;
@@ -2075,7 +2116,7 @@ namespace Game.Entities
public uint GetScriptId()
{
GameObjectData gameObjectData = GetGoData();
GameObjectData gameObjectData = GetGameObjectData();
if (gameObjectData != null)
{
uint scriptId = gameObjectData.ScriptId;
@@ -2548,23 +2589,10 @@ namespace Game.Entities
public void GetRespawnPosition(out float x, out float y, out float z, out float ori)
{
if (m_spawnId != 0)
{
GameObjectData data = Global.ObjectMgr.GetGOData(GetSpawnId());
if (data != null)
{
x = posX;
y = posY;
z = posZ;
ori = data.orientation;
return;
}
}
x = GetPositionX();
y = GetPositionY();
z = GetPositionZ();
ori = GetOrientation();
if (m_goData != null)
m_goData.spawnPoint.GetPosition(out x, out y, out z, out ori);
else
GetPosition(out x, out y, out z, out ori);
}
public float GetInteractionDistance()
@@ -2624,18 +2652,13 @@ namespace Game.Entities
public GameObjectTemplate GetGoInfo() { return m_goInfo; }
public GameObjectTemplateAddon GetTemplateAddon() { return m_goTemplateAddon; }
public GameObjectData GetGoData() { return m_goData; }
public GameObjectData GetGameObjectData() { return m_goData; }
public GameObjectValue GetGoValue() { return m_goValue; }
public ulong GetSpawnId() { return m_spawnId; }
public long GetPackedWorldRotation() { return m_packedRotation; }
public override bool LoadFromDB(ulong spawnId, Map map)
{
return LoadGameObjectFromDB(spawnId, map, false);
}
public void SetOwnerGUID(ObjectGuid owner)
{
// Owner already found and different than expected owner - remove object from old owner
@@ -2768,6 +2791,10 @@ namespace Game.Entities
AddFlag(GameObjectFlags.MapObject);
}
// There's many places not ready for dynamic spawns. This allows them to live on for now.
void SetRespawnCompatibilityMode(bool mode = true) { m_respawnCompatibilityMode = mode; }
public bool GetRespawnCompatibilityMode() { return m_respawnCompatibilityMode; }
#region Fields
protected GameObjectFieldData m_gameObjectData;
protected GameObjectValue m_goValue;
@@ -2799,6 +2826,7 @@ namespace Game.Entities
public Position StationaryPosition { get; set; }
GameObjectAI m_AI;
bool m_respawnCompatibilityMode;
ushort _animKitId;
uint _worldEffectID;
@@ -21,6 +21,7 @@ using Framework.GameMath;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Game.Networking.Packets;
using Game.Maps;
namespace Game.Entities
{
@@ -1274,25 +1275,13 @@ namespace Game.Entities
public uint WorldEffectID;
}
public class GameObjectData
public class GameObjectData : SpawnData
{
public uint id; // entry in gamobject_template
public ushort mapid;
public float posX;
public float posY;
public float posZ;
public float orientation;
public Quaternion rotation;
public int spawntimesecs;
public uint animprogress;
public GameObjectState go_state;
public List<Difficulty> spawnDifficulties = new List<Difficulty>();
public GameObjectState goState;
public byte artKit;
public PhaseUseFlagsValues phaseUseFlags;
public uint phaseId;
public uint phaseGroup;
public int terrainSwapMap;
public uint ScriptId;
public bool dbData = true;
public GameObjectData() : base(SpawnObjectType.GameObject) { }
}
}
+12
View File
@@ -345,6 +345,10 @@ namespace Game.Entities
{
if (_nextGuid >= ObjectGuid.GetMaxCounter(_highGuid) - 1)
HandleCounterOverflow();
if (_highGuid == HighGuid.Creature || _highGuid == HighGuid.Vehicle || _highGuid == HighGuid.GameObject || _highGuid == HighGuid.Transport)
CheckGuidTrigger(_nextGuid);
return _nextGuid++;
}
@@ -355,5 +359,13 @@ namespace Game.Entities
Log.outFatal(LogFilter.Server, "{0} guid overflow!! Can't continue, shutting down server. ", _highGuid);
Global.WorldMgr.StopNow();
}
void CheckGuidTrigger(ulong guidlow)
{
if (!Global.WorldMgr.IsGuidAlert() && guidlow > WorldConfig.GetUInt64Value(WorldCfg.RespawnGuidAlertLevel))
Global.WorldMgr.TriggerGuidAlert();
else if (!Global.WorldMgr.IsGuidWarning() && guidlow > WorldConfig.GetUInt64Value(WorldCfg.RespawnGuidWarnLevel))
Global.WorldMgr.TriggerGuidWarning();
}
}
}
+6
View File
@@ -364,6 +364,12 @@ namespace Game.Entities
Relocate(pos);
}
public void WorldRelocate(uint mapId, Position pos)
{
_mapId = mapId;
Relocate(pos);
}
public void WorldRelocate(WorldLocation loc)
{
_mapId = loc._mapId;
+2 -2
View File
@@ -1731,7 +1731,7 @@ namespace Game.Entities
public virtual uint GetLevelForTarget(WorldObject target) { return 1; }
public virtual void SaveRespawnTime() { }
public virtual void SaveRespawnTime(uint forceDelay = 0, bool saveToDB = true) { }
public ZoneScript GetZoneScript() { return m_zoneScript; }
@@ -1770,7 +1770,7 @@ namespace Game.Entities
public virtual bool IsInvisibleDueToDespawn() { return false; }
public virtual bool IsAlwaysDetectableFor(WorldObject seer) { return false; }
public virtual bool LoadFromDB(ulong guid, Map map) { return true; }
public virtual bool LoadFromDB(ulong spawnId, Map map, bool addToMap, bool allowDuplicate) { return true; }
//Position
@@ -160,6 +160,8 @@ namespace Game.Entities
guild.UpdateMemberData(this, GuildMemberData.ZoneId, newZone);
}
GetMap().UpdatePlayerZoneStats(m_zoneUpdateId, newZone);
// group update
if (GetGroup())
{
+7 -11
View File
@@ -318,14 +318,12 @@ namespace Game.Entities
{
Map map = GetMap();
Creature creature = Creature.CreateCreatureFromDB(guid, map, false);
Creature creature = Creature.CreateCreatureFromDB(guid, map, false, true);
if (!creature)
return null;
float x = data.posX;
float y = data.posY;
float z = data.posZ;
float o = data.orientation;
float x, y, z, o;
data.spawnPoint.GetPosition(out x, out y, out z, out o);
creature.SetTransport(this);
creature.m_movementInfo.transport.guid = GetGUID();
@@ -365,10 +363,8 @@ namespace Game.Entities
if (!go)
return null;
float x = data.posX;
float y = data.posY;
float z = data.posZ;
float o = data.orientation;
float x, y, z, o;
data.spawnPoint.GetPosition(out x, out y, out z, out o);
go.SetTransport(this);
go.m_movementInfo.transport.guid = GetGUID();
@@ -472,7 +468,7 @@ namespace Game.Entities
pos.GetPosition(out x, out y, out z, out o);
CalculatePassengerPosition(ref x, ref y, ref z, ref o);
if (!summon.Create(map.GenerateLowGuid(HighGuid.Creature), map, entry, x, y, z, o, null, vehId))
if (!summon.Create(map.GenerateLowGuid(HighGuid.Creature), map, entry, new Position(x, y, z, o), null, vehId))
return null;
PhasingHandler.InheritPhaseShift(summon, summoner ? (WorldObject)summoner : this);
@@ -553,7 +549,7 @@ namespace Game.Entities
// GameObjects on transport
foreach (var go in cell.Value.gameobjects)
CreateGOPassenger(go, Global.ObjectMgr.GetGOData(go));
CreateGOPassenger(go, Global.ObjectMgr.GetGameObjectData(go));
}
}