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