diff --git a/doc/bt/ZC_DIRECTION_APC.bt b/doc/bt/ZC_DIRECTION_APC.bt
index 54851a32a..e6b2d61dd 100644
--- a/doc/bt/ZC_DIRECTION_APC.bt
+++ b/doc/bt/ZC_DIRECTION_APC.bt
@@ -14,8 +14,9 @@
#include "inc/common.bt"
ServerHeaderFixed header;
+
+int handle;
+int packetString;
int i1;
int i2;
-int i3;
-int i4;
-float f2;
\ No newline at end of file
+float serverAppTimeOffset;
\ No newline at end of file
diff --git a/src/Shared/Network/NormalOp.cs b/src/Shared/Network/NormalOp.cs
index 597fda8d6..fb6bfc623 100644
--- a/src/Shared/Network/NormalOp.cs
+++ b/src/Shared/Network/NormalOp.cs
@@ -50,6 +50,8 @@ public static class Zone
public const int AccountProperties = 0x4D;
public const int UnkDynamicCastStart = 0x4F;
public const int UnkDynamicCastEnd = 0x50;
+ public const int NPC_PlayTrack = 0x53;
+ public const int SetNPCTrackPosition = 0x54;
public const int PadUpdate = 0x59;
public const int PadSetMonsterAltitude = 0x5C;
public const int ParticleEffect = 0x61;
@@ -71,7 +73,7 @@ public static class Zone
public const int Unknown_EF = 0xF2;
public const int ChannelTraffic = 0x12D;
public const int SetGreetingMessage = 0x136;
- public const int Unk13E = 0x13E;
+ public const int Revive = 0x13E;
public const int SetSessionKey = 0x14F;
public const int ItemDrop = 0x152;
public const int NGSCallback = 0x170;
diff --git a/src/ZoneServer/Network/Send.Normal.cs b/src/ZoneServer/Network/Send.Normal.cs
index ebb09e5e9..5759eef60 100644
--- a/src/ZoneServer/Network/Send.Normal.cs
+++ b/src/ZoneServer/Network/Send.Normal.cs
@@ -1179,23 +1179,6 @@ public static void LeapJump(ICombatEntity entity, Position targetPos, float f1,
entity.Map.Broadcast(packet, entity);
}
- ///
- /// Purpose unknown. Added for testing purposes, but turned
- /// out to not be necessary.
- ///
- ///
- ///
- public static void Unk13E(ICombatEntity entity, bool b1)
- {
- var packet = new Packet(Op.ZC_NORMAL);
- packet.PutInt(NormalOp.Zone.Unk13E);
-
- packet.PutInt(entity.Handle);
- packet.PutByte(b1);
-
- entity.Map.Broadcast(packet, entity);
- }
-
///
/// Starts a time action, displaying a progress bar and
/// potentially putting the character in an animation.
@@ -1357,6 +1340,55 @@ public static void OpenBook(Character character, string bookName)
character.Connection.Send(packet);
}
+
+ ///
+ /// Sent with Resurrect Packets?
+ ///
+ ///
+ ///
+ public static void Revive(IZoneConnection conn, IActor actor)
+ {
+ var packet = new Packet(Op.ZC_NORMAL);
+ packet.PutInt(NormalOp.Zone.Revive);
+
+ packet.PutInt(actor.Handle);
+ packet.PutByte(0);
+
+ conn.Send(packet);
+ }
+
+ ///
+ /// NPC Position For a script?
+ ///
+ ///
+ ///
+ public static void SetNPCTrackPosition(IZoneConnection conn, IActor actor)
+ {
+ var packet = new Packet(Op.ZC_NORMAL);
+ packet.PutInt(NormalOp.Zone.SetNPCTrackPosition);
+
+ packet.PutInt(actor.Handle);
+ packet.PutPosition(actor.Position);
+
+ conn.Send(packet);
+ }
+
+ ///
+ /// NPC Play a Track (Client side direction)
+ ///
+ public static void NPC_PlayTrack(IActor actor, string trackName, int i1, int i2, float f1)
+ {
+ var packet = new Packet(Op.ZC_NORMAL);
+ packet.PutInt(NormalOp.Zone.NPC_PlayTrack);
+
+ packet.PutInt(actor.Handle);
+ packet.PutLpString(trackName);
+ packet.PutInt(i1);
+ packet.PutInt(i2);
+ packet.PutFloat(f1);
+
+ actor.Map.Broadcast(packet);
+ }
}
}
}
diff --git a/src/ZoneServer/Network/Send.cs b/src/ZoneServer/Network/Send.cs
index 8adb3d947..77c1f1b17 100644
--- a/src/ZoneServer/Network/Send.cs
+++ b/src/ZoneServer/Network/Send.cs
@@ -4550,5 +4550,27 @@ public static void ZC_ACTION_PKS(IActor toActor, IActor fromActor, byte type, in
toActor.Map.Broadcast(packet);
}
+
+ ///
+ /// Sends ZC_DIRECTION_APC packet to initialize track animation.
+ ///
+ /// The connection to send to.
+ /// The actor to animate.
+ /// The packet string ID for the track.
+ /// Track start index.
+ /// Track end index.
+ /// Time parameter.
+ public static void ZC_DIRECTION_APC(IZoneConnection conn, IActor actor, int packetStringId, int i1, int i2, float f1)
+ {
+ var packet = new Packet(Op.ZC_DIRECTION_APC);
+
+ packet.PutInt(actor.Handle);
+ packet.PutInt(packetStringId);
+ packet.PutInt(i1);
+ packet.PutInt(i2);
+ packet.PutFloat(f1);
+
+ conn.Send(packet);
+ }
}
}
diff --git a/src/ZoneServer/Scripting/Shortcuts.Npcs.cs b/src/ZoneServer/Scripting/Shortcuts.Npcs.cs
index f69aa128b..028d1d27d 100644
--- a/src/ZoneServer/Scripting/Shortcuts.Npcs.cs
+++ b/src/ZoneServer/Scripting/Shortcuts.Npcs.cs
@@ -99,6 +99,111 @@ public static Npc AddNpc(int monsterId, string name, string uniqueName, string m
return monster;
}
+ ///
+ /// Adds new NPC to the world with explicit Y coordinate.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Npc AddNpc(int monsterId, string name, string uniqueName, string map, double x, double y, double z, double direction, DialogFunc dialog = null)
+ {
+ if (!ZoneServer.Instance.World.TryGetMap(map, out var mapObj))
+ throw new ArgumentException($"Map '{map}' not found.");
+
+ if (ZoneServer.Instance.World.TryGetMonster(a => a.UniqueName == uniqueName, out _))
+ throw new ArgumentException($"An NPC with the unique name '{uniqueName}' already exists.");
+
+ var pos = new Position((float)x, (float)y, (float)z);
+
+ // Wrap name in localization code if applicable
+ if (Dialog.IsLocalizationKey(name))
+ {
+ name = Dialog.WrapLocalizationKey(name);
+ }
+ // Insert line breaks in tagged NPC names that don't have one
+ else if (name.StartsWith('[') && !name.Contains("{nl}"))
+ {
+ var endIndex = name.LastIndexOf("] ");
+ if (endIndex != -1)
+ {
+ // Remove space and insert new line instead.
+ name = name.Remove(endIndex + 1, 1);
+ name = name.Insert(endIndex + 1, "{nl}");
+ }
+ }
+
+ var location = new Location(mapObj.Id, pos);
+ var dir = new Direction(direction);
+
+ var monster = new Npc(monsterId, name, location, dir);
+ monster.UniqueName = uniqueName;
+
+ if (dialog != null)
+ monster.SetClickTrigger("DYNAMIC_DIALOG", dialog);
+
+ mapObj.AddMonster(monster);
+
+ return monster;
+ }
+
+ ///
+ /// Adds new NPC to the world with explicit Y coordinate.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Npc AddNpc(int monsterId, string name, string map, double x, double y, double z, double direction, DialogFunc dialog = null)
+ {
+ var uniqueId = Interlocked.Increment(ref UniqueNpcNameId);
+ var uniqueName = $"__NPC{uniqueId}__";
+
+ return AddNpc(monsterId, name, uniqueName, map, x, y, z, direction, dialog);
+ }
+
+ ///
+ /// Adds a Track NPC to the world.
+ ///
+ /// Monster ID for the NPC
+ /// Display name (usually empty for track NPCs)
+ /// Map class name
+ /// X coordinate
+ /// Y coordinate
+ /// Z coordinate
+ /// Facing direction
+ /// Track animation string
+ /// Track start index (default: 2)
+ /// Track end index (default: 5)
+ /// The created NPC, or null if map is invalid
+ public static Npc AddTrackNPC(int monsterId, string name, string map, double x, double y, double z, double direction, string trackString, int i1 = 2, int i2 = 5)
+ {
+ if (string.IsNullOrEmpty(map) || map == "None")
+ {
+ Yggdrasil.Logging.Log.Debug($"Skipped adding Track NPC {monsterId} - {name} at {x},{y},{z} because of invalid map: {map}");
+ return null;
+ }
+
+ var npc = AddNpc(monsterId, name, map, x, y, z, direction);
+ npc.Visibility = World.Actors.ActorVisibility.Always;
+ npc.AddEffect(new World.Actors.Effects.ReviveEffect());
+ npc.AddEffect(new World.Actors.Effects.SetTrackPosition());
+ npc.AddEffect(new World.Actors.Effects.DirectionAPC(trackString, i1, i2));
+
+ return npc;
+ }
+
///
/// Creates a custom shop.
///
diff --git a/src/ZoneServer/World/Actors/Actor.cs b/src/ZoneServer/World/Actors/Actor.cs
index eda519145..444ac7b3d 100644
--- a/src/ZoneServer/World/Actors/Actor.cs
+++ b/src/ZoneServer/World/Actors/Actor.cs
@@ -1,6 +1,8 @@
using System.Collections.Concurrent;
using Melia.Shared.World;
using Melia.Zone.Network;
+using Melia.Zone.World.Actors.Components;
+using Melia.Zone.World.Actors.Effects;
using Melia.Zone.World.Maps;
namespace Melia.Zone.World.Actors
@@ -35,6 +37,11 @@ public interface IActor
///
Direction Direction { get; set; }
+ ///
+ /// Returns the actor's visibility.
+ ///
+ public ActorVisibility Visibility { get; set; }
+
///
/// Returns a list of effects that are attached to the actor.
///
@@ -51,11 +58,24 @@ public abstract class Actor : IActor
///
public ConcurrentBag AttachableEffects { get; } = new ConcurrentBag();
+ ///
+ /// Returns the effects component for this actor.
+ ///
+ public EffectsComponent Effects { get; }
+
///
/// Returns the actor's unique handle.
///
public int Handle { get; } = ZoneServer.Instance.World.CreateHandle();
+ ///
+ /// Creates a new actor instance.
+ ///
+ public Actor()
+ {
+ this.Effects = new EffectsComponent(this);
+ }
+
///
/// Returns the actor's display name.
///
@@ -81,6 +101,11 @@ public Map Map
///
public Direction Direction { get; set; }
+ ///
+ /// Gets or sets the actor's visibility.
+ ///
+ public ActorVisibility Visibility { get; set; } = ActorVisibility.Everyone;
+
///
/// Attaches an effect to the actor that is displayed alongside it.
@@ -95,6 +120,15 @@ public void AttachEffect(string packetString, float scale = 1)
if (this.Map != Map.Limbo)
Send.ZC_NORMAL.AttachEffect(this, effect.PacketString, effect.Scale);
}
+
+ ///
+ /// Adds an effect to the actor.
+ ///
+ /// The effect to add.
+ public void AddEffect(Effect effect)
+ {
+ this.Effects.AddEffect(effect);
+ }
}
///
@@ -123,4 +157,17 @@ public AttachableEffect(string packetString, float scale)
this.Scale = scale;
}
}
+
+ ///
+ /// Defines an actor's visibility.
+ ///
+ public enum ActorVisibility
+ {
+ NoOne,
+ Individual,
+ Party,
+ Track,
+ Everyone,
+ Always,
+ }
}
diff --git a/src/ZoneServer/World/Actors/Characters/Character.cs b/src/ZoneServer/World/Actors/Characters/Character.cs
index 0d2d659c9..d392c4846 100644
--- a/src/ZoneServer/World/Actors/Characters/Character.cs
+++ b/src/ZoneServer/World/Actors/Characters/Character.cs
@@ -957,6 +957,9 @@ public void LookAround()
Send.ZC_NORMAL.AttachEffect(this.Connection, monster, effect.PacketString, effect.Scale);
}
+ if (monster is Actor actor)
+ actor.Effects.ShowEffects(this.Connection);
+
if (monster is ICombatEntity entity)
{
Send.ZC_FACTION(this.Connection, monster, entity.Faction);
@@ -999,6 +1002,8 @@ public void LookAround()
Send.ZC_NORMAL.AttachEffect(this.Connection, character, effect.PacketString, effect.Scale);
}
+ character.Effects.ShowEffects(this.Connection);
+
if (character.Components.Get()?.Count != 0)
Send.ZC_BUFF_LIST(this.Connection, character);
}
@@ -1041,6 +1046,20 @@ public void CloseEyes()
}
}
+ ///
+ /// Returns if a character can see an actor.
+ ///
+ public bool CanSee(IActor actor)
+ {
+ if (actor.Visibility == ActorVisibility.Always)
+ return true;
+ if (actor == null)
+ return false;
+ if (!this.Position.InRange2D(actor.Position, Maps.Map.VisibleRange))
+ return false;
+ return true;
+ }
+
///
/// Sets direction and updates clients.
///
diff --git a/src/ZoneServer/World/Actors/Components/EffectsComponent.cs b/src/ZoneServer/World/Actors/Components/EffectsComponent.cs
new file mode 100644
index 000000000..80ac32b6c
--- /dev/null
+++ b/src/ZoneServer/World/Actors/Components/EffectsComponent.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using Melia.Zone.Network;
+using Melia.Zone.World.Actors.Characters;
+using Melia.Zone.World.Actors.Effects;
+using Yggdrasil.Geometry.Shapes;
+using Yggdrasil.Scheduling;
+
+namespace Melia.Zone.World.Actors.Components
+{
+ ///
+ /// Component that manages actor effects.
+ ///
+ public class EffectsComponent : IUpdateable
+ {
+ private readonly Dictionary _effects = new Dictionary();
+
+ ///
+ /// Returns the number of effects.
+ ///
+ public int Count
+ {
+ get
+ {
+ lock (_effects)
+ return _effects.Count;
+ }
+ }
+
+ ///
+ /// Returns the component's owner.
+ ///
+ public IActor Owner { get; }
+
+ ///
+ /// Creates a new effects component.
+ ///
+ /// The actor that owns this component.
+ public EffectsComponent(IActor owner)
+ {
+ this.Owner = owner;
+ }
+
+ ///
+ /// Adds an effect with an auto-generated name.
+ ///
+ /// The effect to add.
+ public void AddEffect(Effect effect)
+ {
+ lock (_effects)
+ {
+ var effectName = $"{_effects.Count}";
+ _effects.Add(effectName, effect);
+ this.BroadcastEffectAddition(effect);
+ }
+ }
+
+ ///
+ /// Sends an effect to all players that can currently see the owner.
+ ///
+ /// The effect to show.
+ private void BroadcastEffectAddition(Effect effect)
+ {
+ if (this.Owner?.Map == null)
+ return;
+
+ // Get all characters within a generous visibility range of the owner.
+ var charactersInRange = this.Owner.Map.GetActorsIn(new CircleF(this.Owner.Position, 1000f));
+
+ foreach (var character in charactersInRange)
+ {
+ // Check if the character is connected and can actually see the owner actor.
+ if (character.Connection != null && character.CanSee(this.Owner))
+ {
+ effect.ShowEffect(character.Connection, this.Owner);
+ }
+ }
+ }
+
+ ///
+ /// Shows all effects to a specific connection.
+ ///
+ /// The connection to show effects to.
+ public void ShowEffects(IZoneConnection connection)
+ {
+ lock (_effects)
+ {
+ foreach (var effect in _effects.Values)
+ effect.ShowEffect(connection, this.Owner);
+ }
+ }
+
+ ///
+ /// Removes an effect with a given name.
+ ///
+ /// The name of the effect to remove.
+ public void RemoveEffect(string effectName)
+ {
+ if (string.IsNullOrEmpty(effectName))
+ return;
+
+ lock (_effects)
+ {
+ if (_effects.TryGetValue(effectName, out var effect))
+ {
+ effect.OnRemove(this.Owner);
+ _effects.Remove(effectName);
+ }
+ }
+ }
+
+ ///
+ /// Updates the component, calling Update on all IUpdateable effects.
+ ///
+ /// Time elapsed since last update.
+ public void Update(TimeSpan elapsed)
+ {
+ lock (_effects)
+ {
+ foreach (var effect in _effects.Values)
+ {
+ if (effect is IUpdateable updateable)
+ updateable.Update(elapsed);
+ }
+ }
+ }
+ }
+}
diff --git a/src/ZoneServer/World/Actors/Effects/DirectionAPC.cs b/src/ZoneServer/World/Actors/Effects/DirectionAPC.cs
new file mode 100644
index 000000000..ce9934302
--- /dev/null
+++ b/src/ZoneServer/World/Actors/Effects/DirectionAPC.cs
@@ -0,0 +1,102 @@
+using System;
+using Melia.Zone.Network;
+using Yggdrasil.Scheduling;
+
+namespace Melia.Zone.World.Actors.Effects
+{
+ ///
+ /// Effect that animates an NPC along a track path.
+ ///
+ public class DirectionAPC : Effect, IUpdateable
+ {
+ private readonly static TimeSpan DefaultUpdateInterval = TimeSpan.FromSeconds(7);
+ private DateTime _lastUpdate;
+
+ ///
+ /// Gets or sets the update interval for the animation.
+ ///
+ public TimeSpan UpdateInterval { get; set; } = DefaultUpdateInterval;
+
+ ///
+ /// Gets the track string name.
+ ///
+ public string EffectString { get; }
+
+ ///
+ /// Gets the track string ID.
+ ///
+ public int EffectId { get; }
+
+ ///
+ /// Gets the starting track index.
+ ///
+ public int I1 { get; }
+
+ ///
+ /// Gets the ending track index.
+ ///
+ public int I2 { get; }
+
+ ///
+ /// Gets the actor this effect is applied to.
+ ///
+ public IActor Actor { get; private set; }
+
+ ///
+ /// Gets the current track index.
+ ///
+ public int TrackIndex { get; private set; }
+
+ ///
+ /// Creates a new DirectionAPC effect.
+ ///
+ /// The track animation string
+ /// Start index
+ /// End index
+ public DirectionAPC(string packetString, int i1, int i2)
+ {
+ if (!ZoneServer.Instance.Data.PacketStringDb.TryFind(packetString, out var data))
+ {
+ throw new ArgumentException($"Packet string '{packetString}' not found.");
+ }
+
+ this.EffectString = packetString;
+ this.EffectId = data.Id;
+ this.I1 = i1;
+ this.I2 = i2;
+ }
+
+ ///
+ /// Shows the effect by initializing the track animation.
+ ///
+ /// The connection to show the effect to.
+ /// The actor that owns the effect.
+ public override void ShowEffect(IZoneConnection conn, IActor actor)
+ {
+ this.Actor = actor;
+ this.TrackIndex = this.I1 - 1;
+ Send.ZC_DIRECTION_APC(conn, actor, this.EffectId, this.I1, this.I2, (float)ZoneServer.Instance.World.WorldTime.Elapsed.TotalSeconds);
+ }
+
+ ///
+ /// Updates the track animation.
+ ///
+ /// Time elapsed since last update.
+ public void Update(TimeSpan elapsed)
+ {
+ var now = DateTime.Now;
+ var sinceLastUpdate = now - _lastUpdate;
+
+ if (sinceLastUpdate >= this.UpdateInterval && this.Actor != null)
+ {
+ if (this.TrackIndex >= this.I2)
+ this.TrackIndex = 1;
+ else
+ this.TrackIndex += 1;
+
+ Send.ZC_NORMAL.NPC_PlayTrack(this.Actor, this.EffectString, this.I1, this.TrackIndex, (float)ZoneServer.Instance.World.WorldTime.Elapsed.TotalSeconds);
+ _lastUpdate = now;
+ }
+ }
+ }
+}
diff --git a/src/ZoneServer/World/Actors/Effects/Effect.cs b/src/ZoneServer/World/Actors/Effects/Effect.cs
new file mode 100644
index 000000000..d16dba71d
--- /dev/null
+++ b/src/ZoneServer/World/Actors/Effects/Effect.cs
@@ -0,0 +1,23 @@
+using Melia.Zone.Network;
+
+namespace Melia.Zone.World.Actors.Effects
+{
+ ///
+ /// Base class for actor effects.
+ ///
+ public abstract class Effect
+ {
+ ///
+ /// Shows an effect to a specific connection.
+ ///
+ /// The connection to show the effect to.
+ /// The actor that owns the effect.
+ public abstract void ShowEffect(IZoneConnection conn, IActor actor);
+
+ ///
+ /// Called when the effect is removed from its owner.
+ ///
+ /// The actor that owned the effect.
+ public virtual void OnRemove(IActor actor) { }
+ }
+}
diff --git a/src/ZoneServer/World/Actors/Effects/ReviveEffect.cs b/src/ZoneServer/World/Actors/Effects/ReviveEffect.cs
new file mode 100644
index 000000000..e235b63a5
--- /dev/null
+++ b/src/ZoneServer/World/Actors/Effects/ReviveEffect.cs
@@ -0,0 +1,20 @@
+using Melia.Zone.Network;
+
+namespace Melia.Zone.World.Actors.Effects
+{
+ ///
+ /// Effect that sends a revive packet for an actor.
+ ///
+ public class ReviveEffect : Effect
+ {
+ ///
+ /// Shows the effect by sending a revive packet.
+ ///
+ /// The connection to show the effect to.
+ /// The actor that owns the effect.
+ public override void ShowEffect(IZoneConnection conn, IActor actor)
+ {
+ Send.ZC_NORMAL.Revive(conn, actor);
+ }
+ }
+}
diff --git a/src/ZoneServer/World/Actors/Effects/SetTrackPosition.cs b/src/ZoneServer/World/Actors/Effects/SetTrackPosition.cs
new file mode 100644
index 000000000..aaa4ead3e
--- /dev/null
+++ b/src/ZoneServer/World/Actors/Effects/SetTrackPosition.cs
@@ -0,0 +1,20 @@
+using Melia.Zone.Network;
+
+namespace Melia.Zone.World.Actors.Effects
+{
+ ///
+ /// Effect that sets an NPC's track position.
+ ///
+ public class SetTrackPosition : Effect
+ {
+ ///
+ /// Shows the effect by setting the NPC's track position.
+ ///
+ /// The connection to show the effect to.
+ /// The actor that owns the effect.
+ public override void ShowEffect(IZoneConnection conn, IActor actor)
+ {
+ Send.ZC_NORMAL.SetNPCTrackPosition(conn, actor);
+ }
+ }
+}
diff --git a/src/ZoneServer/World/Actors/Monsters/Npc.cs b/src/ZoneServer/World/Actors/Monsters/Npc.cs
index e8a9610b7..c81d17c91 100644
--- a/src/ZoneServer/World/Actors/Monsters/Npc.cs
+++ b/src/ZoneServer/World/Actors/Monsters/Npc.cs
@@ -9,13 +9,14 @@
using System.Threading.Tasks;
using Melia.Zone.World.Actors.Pads;
using Melia.Zone.Skills;
+using Yggdrasil.Scheduling;
namespace Melia.Zone.World.Actors.Monsters
{
///
/// A non-player character that supports dialogues.
///
- public class Npc : MonsterInName, ITriggerableArea
+ public class Npc : MonsterInName, ITriggerableArea, IUpdateable
{
// TODO: Determine whether NPCs and mobs should actually be
// separate classes. NPCs don't typically fight, and many
@@ -144,6 +145,15 @@ public void SetTriggerArea(IShapeF area)
this.Area = area;
}
+ ///
+ /// Updates NPC and its components.
+ ///
+ ///
+ public void Update(TimeSpan elapsed)
+ {
+ this.Effects.Update(elapsed);
+ }
+
///
/// Makes the NPC say the given message, which will display via
/// chat bubble above their head.
diff --git a/src/ZoneServer/World/Maps/Map.cs b/src/ZoneServer/World/Maps/Map.cs
index d65b07dd7..7c2c29295 100644
--- a/src/ZoneServer/World/Maps/Map.cs
+++ b/src/ZoneServer/World/Maps/Map.cs
@@ -320,7 +320,7 @@ public Character[] GetCharacters(Func predicate)
///
///
public Character[] GetVisibleCharacters(Character character)
- => this.GetCharacters(a => a != character && character.Position.InRange2D(a.Position, VisibleRange));
+ => this.GetCharacters(a => a != character && character.CanSee(a));
///
/// Adds monster to map.
@@ -635,8 +635,7 @@ public IMonster[] GetMonsters(Func predicate)
///
///
public IMonster[] GetVisibleMonsters(Character character)
- // TODO: Move responsibility about visibility to Character.
- => this.GetMonsters(a => (a is not Npc npc || npc.State != NpcState.Invisible) && character.Position.InRange2D(a.Position, VisibleRange));
+ => this.GetMonsters(a => (a is not Npc npc || npc.State != NpcState.Invisible) && character.CanSee(a));
///
/// Removes all scripted entities, like NPCs, monsters, and warps.
diff --git a/src/ZoneServer/World/WorldManager.cs b/src/ZoneServer/World/WorldManager.cs
index d4b808465..4ed921f33 100644
--- a/src/ZoneServer/World/WorldManager.cs
+++ b/src/ZoneServer/World/WorldManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Threading;
using Melia.Shared.Network;
@@ -56,6 +57,11 @@ public class WorldManager
///
public GlobalVariables GlobalVariables { get; } = new();
+ ///
+ /// Returns the world's running time for animation synchronization.
+ ///
+ public Stopwatch WorldTime { get; } = new Stopwatch();
+
///
/// Returns a new handle to be used for a character or monster.
///
@@ -135,6 +141,7 @@ private void InitUpdatables()
///
internal void Start()
{
+ this.WorldTime.Start();
this.Heartbeat.Start();
}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_1.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_1.cs
new file mode 100644
index 000000000..5f22caa5f
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Novaha Assembly Hall
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Novaha Assembly Hall.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DAbbey641NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153102, "", "d_abbey_64_1", -1017.423, 366.9117, -465.3019, 0, "d_abbey_64_1_elt2", 3, 2);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_2.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_2.cs
new file mode 100644
index 000000000..00751f9d6
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Novaha Annex
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Novaha Annex.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DAbbey642NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153113, "", "d_abbey_64_2", 275.6379, 348.6844, -439.101, 90, "d_abbey_64_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_3.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_3.cs
new file mode 100644
index 000000000..6b5d81edf
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_abbey_64_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Novaha Institute
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Novaha Institute.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DAbbey643NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153114, "", "d_abbey_64_3", -1155.956, 411.8994, -1264.598, 90, "d_abbey_64_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_castle_67_1.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_castle_67_1.cs
new file mode 100644
index 000000000..9def584f9
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_castle_67_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Topes Fortress 1F
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Topes Fortress 1F.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DCastle671NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153129, "", "d_castle_67_1", 183.9423, 277.7617, 330.8154, 21, "d_castle_67_1_elt", 3, 2);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_castle_67_2.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_castle_67_2.cs
new file mode 100644
index 000000000..3068d4e39
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_castle_67_2.cs
@@ -0,0 +1,20 @@
+//--- Melia Script ----------------------------------------------------------
+// Topes Fortress 2F
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Topes Fortress 2F.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DCastle672NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153130, "", "d_castle_67_2", -741.084, 95.06264, 125.5274, 0, "d_castle_67_2_elt", 3, 2);
+ AddTrackNPC(153130, "", "d_castle_67_2", -865.5137, 93.15315, -926.0688, 16, "d_castle_67_2_elt2", 3, 2);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_cmine_66_1.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_cmine_66_1.cs
new file mode 100644
index 000000000..fe8f18160
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_cmine_66_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Nevellet Quarry 1F
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Nevellet Quarry 1F.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DCmine661NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(155110, "", "d_cmine_66_1", 77.5127, 413.2733, -77.08086, 0, "d_cmine_66_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_2.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_2.cs
new file mode 100644
index 000000000..f1ba19d1a
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Sausis Room 10
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Sausis Room 10.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DFantasylibrary482NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157051, "", "d_fantasylibrary_48_2", 60.01674, 69.90582, -182.7349, 90, "d_fantasylibrary_48_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_3.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_3.cs
new file mode 100644
index 000000000..7d973fc88
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Valandis Room 2
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Valandis Room 2.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DFantasylibrary483NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157052, "", "d_fantasylibrary_48_3", -321.4122, 138.6892, 209.0464, 90, "d_fantasylibrary_48_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_4.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_4.cs
new file mode 100644
index 000000000..bb2efabad
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_fantasylibrary_48_4.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Valandis Room 3
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Valandis Room 3.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DFantasylibrary484NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157053, "", "d_fantasylibrary_48_4", -1004.409, 6.635758, -709.1039, 90, "d_fantasylibrary_48_4_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_firetower_69_1.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_firetower_69_1.cs
new file mode 100644
index 000000000..e3075734a
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_firetower_69_1.cs
@@ -0,0 +1,22 @@
+//--- Melia Script ----------------------------------------------------------
+// Zima Suecourt
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Zima Suecourt.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DFiretower691NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(154081, "", "d_firetower_69_1", -1674.647, -875.7016, -1202.516, 1, "d_firetower_69_1_elt", 2, 1);
+ AddTrackNPC(154081, "", "d_firetower_69_1", -1535.553, -878.40466, -1129.915, 1, "d_firetower_69_1_elt", 3, 1);
+ AddTrackNPC(154083, "", "d_firetower_69_1", -1689.049, -873.08508, -965.8168, 1, "d_firetower_69_1_elt", 4, 1);
+ AddTrackNPC(154083, "", "d_firetower_69_1", -1553.533, -880.21301, -910.1417, 182, "d_firetower_69_1_elt", 5, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_firetower_69_2.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_firetower_69_2.cs
new file mode 100644
index 000000000..cc8cf53da
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_firetower_69_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Martuis Storage Room
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Martuis Storage Room.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DFiretower692NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157026, "", "d_firetower_69_2", -757.8323, 85.4979, 728.7798, 45, "d_firetower_69_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_limestonecave_55_1.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_limestonecave_55_1.cs
new file mode 100644
index 000000000..e522fb9e1
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_limestonecave_55_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Alembique Cave
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Alembique Cave.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DLimestonecave551NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(154099, "", "d_limestonecave_55_1", 1227.525, 151.018, 529.8058, 16, "d_limestonecave_55_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_1.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_1.cs
new file mode 100644
index 000000000..8943138e4
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Ashaq Underground Prison 1F
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Ashaq Underground Prison 1F.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DPrison621NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(154059, "", "d_prison_62_1", -241.3938, 200.532, 501.1691, 0, "d_prison_62_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_2.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_2.cs
new file mode 100644
index 000000000..73fe60870
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Ashaq Underground Prison 2F
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Ashaq Underground Prison 2F.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DPrison622NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(154058, "", "d_prison_62_2", 5.702232, -707.8696, -1245.999, 0, "d_prison_62_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_3.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_3.cs
new file mode 100644
index 000000000..abad36584
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_prison_62_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Ashaq Underground Prison 3F
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Ashaq Underground Prison 3F.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DPrison623NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(154058, "", "d_prison_62_3", -324.5829, 1013.862, 329.7611, 0, "d_prison_62_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/dungeons/d_underfortress_68_2.cs b/system/scripts/zone/content/r1/npcs/dungeons/d_underfortress_68_2.cs
new file mode 100644
index 000000000..97fbc5b96
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/dungeons/d_underfortress_68_2.cs
@@ -0,0 +1,21 @@
+//--- Melia Script ----------------------------------------------------------
+// Sicarius 2F
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Sicarius 2F.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class DUnderfortress682NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153135, "", "d_underfortress_68_2", 600.5497, 205.7321, 37.91431, 0, "d_underfortress_68_2_elt", 3, 2);
+ AddTrackNPC(153135, "", "d_underfortress_68_2", 600.5497, 205.7321, 37.91431, 0, "d_underfortress_68_2_elt", 3, 2);
+ AddTrackNPC(153135, "", "d_underfortress_68_2", 830.5077, 195.7104, -1507.612, 0, "d_underfortress_68_2_elt2", 3, 2);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_3cmlake_26_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_3cmlake_26_1.cs
new file mode 100644
index 000000000..29c478bb2
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_3cmlake_26_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Lanko 26 Waters
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Lanko 26 Waters.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class F3cmlake261NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(155160, "", "f_3cmlake_26_1", 948.2599, -117.9686, 444.7431, 0, "f_3cmlake_26_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_bracken_42_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_bracken_42_1.cs
new file mode 100644
index 000000000..1c9bf2ac9
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_bracken_42_1.cs
@@ -0,0 +1,20 @@
+//--- Melia Script ----------------------------------------------------------
+// Khonot Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Khonot Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FBracken421NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157042, "", "f_bracken_42_1", 782.5125, 558.6927, -747.0397, 0, "f_bracken_42_1_elt", 2, 1);
+ AddTrackNPC(157043, "", "f_bracken_42_1", 1067.31, 557.06, -425.56, 0, "f_bracken_42_1_elt2", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_bracken_43_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_bracken_43_2.cs
new file mode 100644
index 000000000..cfd7c266e
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_bracken_43_2.cs
@@ -0,0 +1,20 @@
+//--- Melia Script ----------------------------------------------------------
+// Phamer Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Phamer Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FBracken432NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153179, "", "f_bracken_43_2", 1369.781, 116.1511, 470.741, 0, "f_bracken_43_2_elt", 2, 1);
+ AddTrackNPC(153180, "", "f_bracken_43_2", 552.7917, 35.09259, -574.3962, 354, "f_bracken_43_2_elt2", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_bracken_43_4.cs b/system/scripts/zone/content/r1/npcs/fields/f_bracken_43_4.cs
new file mode 100644
index 000000000..aa6915f90
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_bracken_43_4.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Mollogheo Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Mollogheo Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FBracken434NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153181, "", "f_bracken_43_4", 665.4066, 59.12576, 327.8538, 0, "f_bracken_43_4_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_1.cs
new file mode 100644
index 000000000..49f184935
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Kateen Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Kateen Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FBracken631NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153107, "", "f_bracken_63_1", -268.1401, 544.2999, 995.2676, 21, "f_bracken_63_1_elt", 3, 2);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_2.cs
new file mode 100644
index 000000000..7b3171609
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Knidos Jungle
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Knidos Jungle.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FBracken632NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153112, "", "f_bracken_63_2", -47.54993, 253.4295, -541.7952, 0, "f_bracken_63_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_3.cs b/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_3.cs
new file mode 100644
index 000000000..9c8d3b171
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_bracken_63_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Dadan Jungle
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Dadan Jungle.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FBracken633NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153095, "", "f_bracken_63_3", -252.8264, 189.2868, -89.98244, 111, "f_bracken_63_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_castle_20_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_castle_20_1.cs
new file mode 100644
index 000000000..a4dfa0b90
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_castle_20_1.cs
@@ -0,0 +1,20 @@
+//--- Melia Script ----------------------------------------------------------
+// Outer Wall District 9
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Outer Wall District 9.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCastle201NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157027, "", "f_castle_20_1", 405.7464, 150.6457, -274.809, 0, "f_castle_20_1_elt", 2, 1);
+ AddTrackNPC(157028, "", "f_castle_20_1", -576.8862, 237.7089, -320.7311, 90, "f_castle_20_1_elt2", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_castle_20_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_castle_20_2.cs
new file mode 100644
index 000000000..d62959039
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_castle_20_2.cs
@@ -0,0 +1,20 @@
+//--- Melia Script ----------------------------------------------------------
+// Inner Wall District 9
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Inner Wall District 9.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCastle202NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157029, "", "f_castle_20_2", -1006.002, 1.829224, -609.7711, 16, "f_castle_20_2_elt", 2, 1);
+ AddTrackNPC(157029, "", "f_castle_20_2", -894.3446, -120.3677, 549.2271, 0, "f_castle_20_2_elt2", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_castle_20_3.cs b/system/scripts/zone/content/r1/npcs/fields/f_castle_20_3.cs
new file mode 100644
index 000000000..c2d5b0a01
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_castle_20_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Inner Wall District 8
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Inner Wall District 8.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCastle203NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157030, "", "f_castle_20_3", 467.1729, 139.2464, -586.9828, 0, "f_castle_20_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_castle_20_4.cs b/system/scripts/zone/content/r1/npcs/fields/f_castle_20_4.cs
new file mode 100644
index 000000000..f57ce61fc
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_castle_20_4.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// City Wall District 8
+//--- Description -----------------------------------------------------------
+// NPCs found in and around City Wall District 8.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCastle204NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157025, "", "f_castle_20_4", 1157.179, 126.4701, 271.2875, 0, "d_castle_20_4_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_castle_65_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_castle_65_1.cs
new file mode 100644
index 000000000..f4ff8ad6f
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_castle_65_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Delmore Hamlet
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Delmore Hamlet.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCastle651NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(155112, "", "f_castle_65_1", -728.6979, -8.345245, 768.4816, 0, "f_castle_65_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_castle_65_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_castle_65_2.cs
new file mode 100644
index 000000000..863f74b80
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_castle_65_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Delmore Manor
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Delmore Manor.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCastle652NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(155108, "", "f_castle_65_2", -849.7505, 220.4114, 516.4036, 0, "f_castle_65_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_castle_65_3.cs b/system/scripts/zone/content/r1/npcs/fields/f_castle_65_3.cs
new file mode 100644
index 000000000..0e5436f3d
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_castle_65_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Delmore Outskirts
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Delmore Outskirts.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCastle653NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(155109, "", "f_castle_65_3", 123.7928, 96.6724, 200.1542, 0, "f_castle_65_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_coral_32_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_coral_32_2.cs
new file mode 100644
index 000000000..b0998d1fa
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_coral_32_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Igti Coast
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Igti Coast.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCoral322NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157003, "", "f_coral_32_2", -641.0241, -36.33413, 1405.18, 21, "f_coral_32_2_elt", 3, 2);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_coral_35_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_coral_35_2.cs
new file mode 100644
index 000000000..db3bb4cec
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_coral_35_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Vera Coast
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Vera Coast.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCoral352NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(156034, "", "f_coral_35_2", 401.4194, 224.4277, 717.4001, 0, "f_coral_35_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_coral_44_3.cs b/system/scripts/zone/content/r1/npcs/fields/f_coral_44_3.cs
new file mode 100644
index 000000000..df7ec05db
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_coral_44_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Epherotao Coast
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Epherotao Coast.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FCoral443NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157050, "", "f_coral_44_3", 464.66, 92.97, 518.12, 335, "f_coral_44_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_dcapital_103.cs b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_103.cs
new file mode 100644
index 000000000..7b34fd744
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_103.cs
@@ -0,0 +1,20 @@
+//--- Melia Script ----------------------------------------------------------
+// Taniel I Commemorative Orb
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Taniel I Commemorative Orb.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FDcapital103NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157032, "", "f_dcapital_103", 1260.842, 214.2436, -324.7393, 8, "f_dcapital_103_elt", 2, 1);
+ AddTrackNPC(157033, "", "f_dcapital_103", -401.9065, 174.6531, -97.95161, 0, "f_dcapital_103_elt2", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_dcapital_105.cs b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_105.cs
new file mode 100644
index 000000000..71202b01d
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_105.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Baltinel Memorial
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Baltinel Memorial.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FDcapital105NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153231, "", "f_dcapital_105", -264.1042, 111.0862, -237.836, 0, "f_dcapital_105_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_dcapital_106.cs b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_106.cs
new file mode 100644
index 000000000..adc07582c
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_106.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Gliehel Memorial
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Gliehel Memorial.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FDcapital106NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153230, "", "f_dcapital_106", 392.5825, 71.17463, 988.9101, 21, "f_dcapital_106_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_dcapital_20_5.cs b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_20_5.cs
new file mode 100644
index 000000000..7c579d3c1
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_20_5.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Jeromel Park
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Jeromel Park.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FDcapital205NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157019, "", "f_dcapital_20_5", 929.8597, 294.7133, -722.7009, 0, "f_dcapital_20_5_elt", 2, 5);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_dcapital_20_6.cs b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_20_6.cs
new file mode 100644
index 000000000..d0fca8f9c
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_dcapital_20_6.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Jonael Commemorative Orb
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Jonael Commemorative Orb.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FDcapital206NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157031, "", "f_dcapital_20_6", -755.0917, 283.1046, 1777.638, 0, "f_dcapital_20_6_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_flash_63.cs b/system/scripts/zone/content/r1/npcs/fields/f_flash_63.cs
new file mode 100644
index 000000000..861e68361
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_flash_63.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Downtown
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Downtown.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FFlash63NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(147427, "", "f_flash_63", 897.8192, 233.7511, 654.0224, 357.82477, "flash_elevator", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_gele_57_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_gele_57_1.cs
new file mode 100644
index 000000000..2a3c7dfa3
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_gele_57_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Srautas Gorge
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Srautas Gorge.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FGele571NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153006, "", "f_gele_57_1", -305.9306, 168.8233, -402.949, 0, "f_gele_57_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_gele_57_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_gele_57_2.cs
new file mode 100644
index 000000000..5db9a3517
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_gele_57_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Gele Plateau
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Gele Plateau.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FGele572NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153007, "", "f_gele_57_2", -85.66, 381.08, 841.97, 0, "f_gele57_2_cablecar", 2, 5);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_huevillage_58_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_huevillage_58_1.cs
new file mode 100644
index 000000000..64b773a3b
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_huevillage_58_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Veja Ravine
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Veja Ravine.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FHuevillage581NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153008, "", "f_huevillage_58_1", 638.2, 129.74, 468.58, 0, "f_huevillage58_1_cablecar", 2, 5);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_maple_25_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_maple_25_1.cs
new file mode 100644
index 000000000..cc6a68cb7
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_maple_25_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Nheto Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Nheto Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FMaple251NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157034, "", "f_maple_25_1", -953.6499, -38.68602, 177.3624, 342, "f_maple_25_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_maple_25_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_maple_25_2.cs
new file mode 100644
index 000000000..f01be29c2
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_maple_25_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Tiltas Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Tiltas Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FMaple252NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157035, "", "f_maple_25_2", -78.02134, 34.58647, 382.6509, 320, "f_maple_25_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_maple_25_3.cs b/system/scripts/zone/content/r1/npcs/fields/f_maple_25_3.cs
new file mode 100644
index 000000000..21cfb37cb
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_maple_25_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Lhadar Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Lhadar Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FMaple253NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157036, "", "f_maple_25_3", -917.34, 36.80652, -444.9715, 0, "f_maple_25_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_nicopolis_81_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_nicopolis_81_2.cs
new file mode 100644
index 000000000..f5475a1ee
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_nicopolis_81_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Feline Post Town
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Feline Post Town.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FNicopolis812NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153232, "", "f_nicopolis_81_2", 60.4, 2.22, -1645, 0, "f_nicopolis_81_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_nicopolis_81_3.cs b/system/scripts/zone/content/r1/npcs/fields/f_nicopolis_81_3.cs
new file mode 100644
index 000000000..bfd9d3415
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_nicopolis_81_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Spell Tome Town
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Spell Tome Town.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FNicopolis813NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153233, "", "f_nicopolis_81_3", -372.14, -157.52, -888.32, 1, "f_nicopolis_81_3_elt", 4, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_orchard_32_4.cs b/system/scripts/zone/content/r1/npcs/fields/f_orchard_32_4.cs
new file mode 100644
index 000000000..5a9b2b859
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_orchard_32_4.cs
@@ -0,0 +1,20 @@
+//--- Melia Script ----------------------------------------------------------
+// Seir Rainforest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Seir Rainforest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FOrchard324NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(156037, "", "f_orchard_32_4", 1402.254, 135.6041, 557.9661, 0, "f_orchard_32_4_wheel", 2, 1);
+ AddTrackNPC(156038, "", "f_orchard_32_4", -333.8946, 19.81506, 796.1085, 90, "f_orchard_32_4_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_orchard_34_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_orchard_34_2.cs
new file mode 100644
index 000000000..62b56bf1e
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_orchard_34_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Ruklys Hall
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Ruklys Hall.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FOrchard342NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(155059, "", "f_orchard_34_2", -1761.933, -357.2179, 384.1256, 90, "f_orchard_34_2_elevator", 3, 2);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_rokas_27.cs b/system/scripts/zone/content/r1/npcs/fields/f_rokas_27.cs
new file mode 100644
index 000000000..d9d151d92
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_rokas_27.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Akmens Ridge
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Akmens Ridge.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FRokas27NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153009, "", "f_rokas_27", 393.83, 1297.32, -1456.52, 250, "f_rokas27_cablecar", 2, 5);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_22_2.cs b/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_22_2.cs
new file mode 100644
index 000000000..7dbcf02ec
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_22_2.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Tekel Shelter
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Tekel Shelter.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FWhitetrees222NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(153189, "", "f_whitetrees_22_2", 990.0172, 125.708, -499.8661, 351, "f_whitetrees_22_2_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_23_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_23_1.cs
new file mode 100644
index 000000000..fa29335fe
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_23_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Emmet Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Emmet Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FWhitetrees231NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157041, "", "f_whitetrees_23_1", 527.8957, -140.5882, 190.1657, 43, "f_whitetrees_23_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_23_3.cs b/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_23_3.cs
new file mode 100644
index 000000000..fc6bf81d3
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_23_3.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Syla Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Syla Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FWhitetrees233NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157037, "", "f_whitetrees_23_3", -997.1872, 160.0814, 367.3382, 38, "f_whitetrees_23_3_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_56_1.cs b/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_56_1.cs
new file mode 100644
index 000000000..dc64b953e
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/fields/f_whitetrees_56_1.cs
@@ -0,0 +1,19 @@
+//--- Melia Script ----------------------------------------------------------
+// Mishekan Forest
+//--- Description -----------------------------------------------------------
+// NPCs found in and around Mishekan Forest.
+//---------------------------------------------------------------------------
+
+using Melia.Shared.Game.Const;
+using Melia.Zone.Scripting;
+using static Melia.Zone.Scripting.Shortcuts;
+
+public class FWhitetrees561NpcScript : GeneralScript
+{
+ protected override void Load()
+ {
+ // Track NPCs
+ //---------------------------------------------------------------------------
+ AddTrackNPC(157038, "", "f_whitetrees_56_1", 1384.889, 68.06953, 243.3077, 10, "f_whitetrees_56_1_elt", 2, 1);
+ }
+}
diff --git a/system/scripts/zone/content/r1/npcs/scripts.txt b/system/scripts/zone/content/r1/npcs/scripts.txt
new file mode 100644
index 000000000..23f9c35a8
--- /dev/null
+++ b/system/scripts/zone/content/r1/npcs/scripts.txt
@@ -0,0 +1,5 @@
+// Melia
+// Script List File
+//---------------------------------------------------------------------------
+
+./**/*
\ No newline at end of file
diff --git a/system/scripts/zone/content/r1/scripts.txt b/system/scripts/zone/content/r1/scripts.txt
index 4b456b27d..3ffb7a3e0 100644
--- a/system/scripts/zone/content/r1/scripts.txt
+++ b/system/scripts/zone/content/r1/scripts.txt
@@ -4,3 +4,4 @@
require "mobs/scripts.txt"
require "warps/scripts.txt"
+require "npcs/scripts.txt"