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
+9
View File
@@ -474,6 +474,15 @@ namespace Game.AI
// Object destruction is handled by Unit::RemoveCharmedBy
public virtual PlayerAI GetAIForCharmedPlayer(Player who) { return null; }
/// <summary>
/// Should return true if the NPC is target of an escort quest
/// If onlyIfActive is set, should return true only if the escort quest is currently active
/// </summary>
/// <param name="onlyIfActive"></param>
/// <returns></returns>
public virtual bool IsEscortNPC(bool onlyIfActive) { return false; }
List<AreaBoundary> GetBoundary() { return _boundary; }
bool MoveInLineOfSight_locked;
+7 -5
View File
@@ -495,7 +495,7 @@ namespace Game.AI
_events.Reset();
summons.DespawnAll();
_scheduler.CancelAll();
if (instance != null)
if (instance != null && instance.GetBossState(_bossId) != EncounterState.Done)
instance.SetBossState(_bossId, EncounterState.NotStarted);
}
@@ -576,12 +576,14 @@ namespace Game.AI
DoMeleeAttackIfReady();
}
public void _DespawnAtEvade(uint delayToRespawn = 30, Creature who = null)
public void _DespawnAtEvade(uint delayToRespawn = 30, Creature who = null) { _DespawnAtEvade(TimeSpan.FromSeconds(delayToRespawn), who); }
public void _DespawnAtEvade(TimeSpan delayToRespawn, Creature who = null)
{
if (delayToRespawn < 2)
if (delayToRespawn < TimeSpan.FromSeconds(2))
{
Log.outError(LogFilter.Scripts, "_DespawnAtEvade called with delay of {0} seconds, defaulting to 2.", delayToRespawn);
delayToRespawn = 2;
delayToRespawn = TimeSpan.FromSeconds(2);
}
if (!who)
@@ -595,7 +597,7 @@ namespace Game.AI
return;
}
who.DespawnOrUnsummon(0, TimeSpan.FromSeconds(delayToRespawn));
who.DespawnOrUnsummon(0, delayToRespawn);
if (instance != null && who == me)
instance.SetBossState(_bossId, EncounterState.Fail);
+44 -2
View File
@@ -18,6 +18,7 @@
using Framework.Constants;
using Game.Entities;
using Game.Groups;
using Game.Maps;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -234,13 +235,17 @@ namespace Game.AI
return;
}
if (m_bCanInstantRespawn)
if (m_bCanInstantRespawn && !WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc))
{
me.SetDeathState(DeathState.JustDied);
me.Respawn();
}
else
{
if (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc))
me.GetMap().RemoveRespawnTime(SpawnObjectType.Creature, me.GetSpawnId(), true);
me.DespawnOrUnsummon();
}
return;
}
@@ -274,11 +279,18 @@ namespace Game.AI
{
Log.outDebug(LogFilter.Scripts, "EscortAI failed because player/group was to far away or not found");
if (m_bCanInstantRespawn)
bool isEscort = false;
CreatureData cdata = me.GetCreatureData();
if (cdata != null)
isEscort = (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc) && cdata.spawnGroupData.flags.HasAnyFlag(SpawnGroupFlags.EscortQuestNpc));
if (m_bCanInstantRespawn && !isEscort)
{
me.SetDeathState(DeathState.JustDied);
me.Respawn();
}
else if (m_bCanInstantRespawn && isEscort)
me.GetMap().RemoveRespawnTime(SpawnObjectType.Creature, me.GetSpawnId(), true);
else
me.DespawnOrUnsummon();
@@ -391,6 +403,25 @@ namespace Game.AI
/// todo get rid of this many variables passed in function.
public void Start(bool isActiveAttacker = true, bool run = false, ObjectGuid playerGUID = default, Quest quest = null, bool instantRespawn = false, bool canLoopPath = false, bool resetWaypoints = true)
{
// Queue respawn from the point it starts
Map map = me.GetMap();
if (map != null)
{
CreatureData cdata = me.GetCreatureData();
if (cdata != null)
{
SpawnGroupTemplateData groupdata = cdata.spawnGroupData;
if (groupdata != null)
{
if (WorldConfig.GetBoolValue(WorldCfg.RespawnDynamicEscortNpc) && groupdata.flags.HasAnyFlag(SpawnGroupFlags.EscortQuestNpc) && map.GetCreatureRespawnTime(me.GetSpawnId()) == 0)
{
me.SetRespawnTime(me.GetRespawnDelay());
me.SaveRespawnTime();
}
}
}
}
if (me.GetVictim())
{
Log.outError(LogFilter.Server, "TSCR ERROR: EscortAI (script: {0}, creature entry: {1}) attempts to Start while in combat", me.GetScriptName(), me.GetEntry());
@@ -536,6 +567,17 @@ namespace Game.AI
return false;
}
public override bool IsEscortNPC(bool onlyIfActive)
{
if (!onlyIfActive)
return true;
if (!GetEventStarterGUID().IsEmpty())
return true;
return false;
}
public virtual void WaypointReached(uint pointId) { }
public virtual void WaypointStart(uint pointId) { }
+21 -9
View File
@@ -129,39 +129,39 @@ namespace Game.AI
continue;
}
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(creature.id);
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(creature.Id);
if (creatureInfo == null)
{
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: Creature entry ({creature.id}) guid ({-temp.entryOrGuid}) does not exist, skipped loading.");
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: Creature entry ({creature.Id}) guid ({-temp.entryOrGuid}) does not exist, skipped loading.");
continue;
}
if (creatureInfo.AIName != "SmartAI")
{
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: Creature entry ({creature.id}) guid ({-temp.entryOrGuid}) is not using SmartAI, skipped loading.");
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: Creature entry ({creature.Id}) guid ({-temp.entryOrGuid}) is not using SmartAI, skipped loading.");
continue;
}
break;
}
case SmartScriptType.GameObject:
{
GameObjectData gameObject = Global.ObjectMgr.GetGOData((ulong)-temp.entryOrGuid);
GameObjectData gameObject = Global.ObjectMgr.GetGameObjectData((ulong)-temp.entryOrGuid);
if (gameObject == null)
{
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: GameObject guid ({-temp.entryOrGuid}) does not exist, skipped loading.");
continue;
}
GameObjectTemplate gameObjectInfo = Global.ObjectMgr.GetGameObjectTemplate(gameObject.id);
GameObjectTemplate gameObjectInfo = Global.ObjectMgr.GetGameObjectTemplate(gameObject.Id);
if (gameObjectInfo == null)
{
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: GameObject entry ({gameObject.id}) guid ({-temp.entryOrGuid}) does not exist, skipped loading.");
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: GameObject entry ({gameObject.Id}) guid ({-temp.entryOrGuid}) does not exist, skipped loading.");
continue;
}
if (gameObjectInfo.AIName != "SmartGameObjectAI")
{
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: GameObject entry ({gameObject.id}) guid ({-temp.entryOrGuid}) is not using SmartGameObjectAI, skipped loading.");
Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: GameObject entry ({gameObject.Id}) guid ({-temp.entryOrGuid}) is not using SmartGameObjectAI, skipped loading.");
continue;
}
break;
@@ -758,7 +758,7 @@ namespace Game.AI
return false;
}
if (e.Event.distance.guid != 0 && Global.ObjectMgr.GetGOData(e.Event.distance.guid) == null)
if (e.Event.distance.guid != 0 && Global.ObjectMgr.GetGameObjectData(e.Event.distance.guid) == null)
{
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid {0}, skipped.", e.Event.distance.guid);
return false;
@@ -1376,6 +1376,8 @@ namespace Game.AI
case SmartActions.TriggerRandomTimedEvent:
case SmartActions.SetCounter:
case SmartActions.RemoveAllGameobjects:
case SmartActions.SpawnSpawngroup:
case SmartActions.DespawnSpawngroup:
break;
default:
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Not handled action_type({0}), event_type({1}), Entry {2} SourceType {3} Event {4}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
@@ -1423,7 +1425,7 @@ namespace Game.AI
return false;
}
else
entry = data.id;
entry = data.Id;
}
else
entry = (uint)e.entryOrGuid;
@@ -2368,6 +2370,9 @@ namespace Game.AI
[FieldOffset(4)]
public DisableEvade disableEvade;
[FieldOffset(4)]
public GroupSpawn groupSpawn;
[FieldOffset(4)]
public AuraType auraType;
@@ -2854,6 +2859,13 @@ namespace Game.AI
{
public uint disable;
}
public struct GroupSpawn
{
public uint groupId;
public uint minDelay;
public uint maxDelay;
public uint spawnflags;
}
public struct AuraType
{
public uint type;
@@ -2051,6 +2051,91 @@ namespace Game.AI
target.ToCreature().SetCorpseDelay(e.Action.corpseDelay.timer);
break;
}
case SmartActions.SpawnSpawngroup:
{
if (e.Action.groupSpawn.minDelay == 0 && e.Action.groupSpawn.maxDelay == 0)
{
bool ignoreRespawn = ((e.Action.groupSpawn.spawnflags & (uint)SmartAiSpawnFlags.IgnoreRespawn) != 0);
bool force = ((e.Action.groupSpawn.spawnflags & (uint)SmartAiSpawnFlags.ForceSpawn) != 0);
// Instant spawn
Global.ObjectMgr.SpawnGroupSpawn(e.Action.groupSpawn.groupId, GetBaseObject().GetMap(), ignoreRespawn, force);
}
else
{
// Delayed spawn (use values from parameter to schedule event to call us back
SmartEvent ne = new SmartEvent();
ne.type = SmartEvents.Update;
ne.event_chance = 100;
ne.minMaxRepeat.min = e.Action.groupSpawn.minDelay;
ne.minMaxRepeat.max = e.Action.groupSpawn.maxDelay;
ne.minMaxRepeat.repeatMin = 0;
ne.minMaxRepeat.repeatMax = 0;
ne.event_flags = 0;
ne.event_flags |= SmartEventFlags.NotRepeatable;
SmartAction ac = new SmartAction();
ac.type = SmartActions.SpawnSpawngroup;
ac.groupSpawn.groupId = e.Action.groupSpawn.groupId;
ac.groupSpawn.minDelay = 0;
ac.groupSpawn.maxDelay = 0;
ac.groupSpawn.spawnflags = e.Action.groupSpawn.spawnflags;
ac.timeEvent.id = e.Action.timeEvent.id;
SmartScriptHolder ev = new SmartScriptHolder();
ev.Event = ne;
ev.event_id = e.event_id;
ev.Target = e.Target;
ev.Action = ac;
InitTimer(ev);
mStoredEvents.Add(ev);
}
break;
}
case SmartActions.DespawnSpawngroup:
{
if (e.Action.groupSpawn.minDelay == 0 && e.Action.groupSpawn.maxDelay == 0)
{
bool deleteRespawnTimes = ((e.Action.groupSpawn.spawnflags & (uint)SmartAiSpawnFlags.NosaveRespawn) != 0);
// Instant spawn
Global.ObjectMgr.SpawnGroupDespawn(e.Action.groupSpawn.groupId, GetBaseObject().GetMap(), deleteRespawnTimes);
}
else
{
// Delayed spawn (use values from parameter to schedule event to call us back
SmartEvent ne = new SmartEvent();
ne.type = SmartEvents.Update;
ne.event_chance = 100;
ne.minMaxRepeat.min = e.Action.groupSpawn.minDelay;
ne.minMaxRepeat.max = e.Action.groupSpawn.maxDelay;
ne.minMaxRepeat.repeatMin = 0;
ne.minMaxRepeat.repeatMax = 0;
ne.event_flags = 0;
ne.event_flags |= SmartEventFlags.NotRepeatable;
SmartAction ac = new SmartAction();
ac.type = SmartActions.DespawnSpawngroup;
ac.groupSpawn.groupId = e.Action.groupSpawn.groupId;
ac.groupSpawn.minDelay = 0;
ac.groupSpawn.maxDelay = 0;
ac.groupSpawn.spawnflags = e.Action.groupSpawn.spawnflags;
ac.timeEvent.id = e.Action.timeEvent.id;
SmartScriptHolder ev = new SmartScriptHolder();
ev.Event = ne;
ev.event_id = e.event_id;
ev.Target = e.Target;
ev.Action = ac;
InitTimer(ev);
mStoredEvents.Add(ev);
}
break;
}
case SmartActions.DisableEvade:
{
if (!IsSmart())