Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Intersect (Core)/Enums/NpcMovement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,12 @@ public enum NpcMovement
StandStill,

Static,

HorizontalPatrol,

VerticalPatrol,

BackslashPatrol,

ForwardslashPatrol,
}
133 changes: 57 additions & 76 deletions Intersect.Client.Core/Entities/Critter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ namespace Intersect.Client.Entities;
public partial class Critter : Entity
{
private readonly MapCritterAttribute mAttribute;
private long mLastMove = -1;

// Critter's Movement
private long _lastMove = -1;
private byte _randomMoveRange;

public Critter(MapInstance map, byte x, byte y, MapCritterAttribute att) : base(Guid.NewGuid(), null, EntityType.GlobalEntity)
{
Expand Down Expand Up @@ -50,65 +53,65 @@ public Critter(MapInstance map, byte x, byte y, MapCritterAttribute att) : base(

public override bool Update()
{
if (base.Update())
if (!base.Update())
{
if (mLastMove < Timing.Global.MillisecondsUtc)
{
switch (mAttribute.Movement)
{
case 0: //Move Randomly
MoveRandomly();
break;
case 1: //Turn?
DirectionFacing = Randomization.NextDirection();
break;

}

mLastMove = Timing.Global.MillisecondsUtc + mAttribute.Frequency + Globals.Random.Next((int)(mAttribute.Frequency * .5f));
}
return false;
}

// Only skip if we are NOT in the middle of a range-walk AND the frequency timer is active
if (_randomMoveRange <= 0 && _lastMove >= Timing.Global.MillisecondsUtc)
{
return true;
}

return false;
switch (mAttribute.Movement)
{
case 0: // Move Randomly
MoveRandomly();
break;
case 1: // Turn Randomly
DirectionFacing = Randomization.NextDirection();
// Set pause after turning
_lastMove = Timing.Global.MillisecondsUtc + mAttribute.Frequency + Globals.Random.Next((int)(mAttribute.Frequency * .5f));
break;
}

return true;
}

private void MoveRandomly()
{
DirectionMoving = Randomization.NextDirection();
var tmpX = (sbyte)X;
var tmpY = (sbyte)Y;
IEntity? blockedBy = null;

// Don't start a new step if currently moving between tiles
if (IsMoving || MoveTimer >= Timing.Global.MillisecondsUtc)
{
return;
}

// No range left: pick a new direction and range
if (_randomMoveRange <= 0)
{
DirectionFacing = Randomization.NextDirection();
_randomMoveRange = (byte)Randomization.Next(1, 5);
}

var deltaX = 0;
var deltaY = 0;

switch (DirectionMoving)
switch (DirectionFacing)
{
case Direction.Up:
deltaX = 0;
deltaY = -1;
break;

case Direction.Down:
deltaX = 0;
deltaY = 1;
break;

case Direction.Left:
deltaX = -1;
deltaY = 0;
break;

case Direction.Right:
deltaX = 1;
deltaY = 0;
break;

case Direction.UpLeft:
Expand All @@ -132,59 +135,37 @@ private void MoveRandomly()
break;
}

if (deltaX != 0 || deltaY != 0)
{
var newX = tmpX + deltaX;
var newY = tmpY + deltaY;
var isBlocked = -1 ==
IsTileBlocked(
new Point(newX, newY),
Z,
MapId,
ref blockedBy,
true,
true,
mAttribute.IgnoreNpcAvoids
);
var playerOnTile = PlayerOnTile(MapId, newX, newY);

if (isBlocked && newX >= 0 && newX < Options.Instance.Map.MapWidth && newY >= 0 && newY < Options.Instance.Map.MapHeight &&
(!mAttribute.BlockPlayers || !playerOnTile))
{
tmpX += (sbyte)deltaX;
tmpY += (sbyte)deltaY;
IsMoving = true;
DirectionFacing = DirectionMoving;
var newX = (sbyte)X + deltaX;
var newY = (sbyte)Y + deltaY;
IEntity? blockedBy = null;

if (deltaX == 0)
{
OffsetX = 0;
}
else
{
OffsetX = deltaX > 0 ? -Options.Instance.Map.TileWidth : Options.Instance.Map.TileWidth;
}
// Boundary checks
var isBlocked = -1 == IsTileBlocked(new Point(newX, newY), Z, MapId, ref blockedBy, true, true, mAttribute.IgnoreNpcAvoids);
var playerOnTile = PlayerOnTile(MapId, newX, newY);

if (deltaY == 0)
{
OffsetY = 0;
}
else
{
OffsetY = deltaY > 0 ? -Options.Instance.Map.TileHeight : Options.Instance.Map.TileHeight;
}
}
}

if (IsMoving)
if (isBlocked && !playerOnTile &&
newX >= 0 && newX < Options.Instance.Map.MapWidth &&
newY >= 0 && newY < Options.Instance.Map.MapHeight)
{
X = (byte)tmpX;
Y = (byte)tmpY;
X = (byte)newX;
Y = (byte)newY;
IsMoving = true;
OffsetX = deltaX == 0 ? 0 : (deltaX > 0 ? -Options.Instance.Map.TileWidth : Options.Instance.Map.TileWidth);
OffsetY = deltaY == 0 ? 0 : (deltaY > 0 ? -Options.Instance.Map.TileHeight : Options.Instance.Map.TileHeight);
MoveTimer = Timing.Global.MillisecondsUtc + (long)GetMovementTime();
_randomMoveRange--;

// Critter's last step: set an idle pause timer
if (_randomMoveRange <= 0)
{
_lastMove = Timing.Global.MillisecondsUtc + mAttribute.Frequency + Globals.Random.Next((int)(mAttribute.Frequency * .5f));
}
}
else if (DirectionMoving != DirectionFacing)
else
{
DirectionFacing = DirectionMoving;
// Blocked by something: end range early and trigger pause
_randomMoveRange = 0;
_lastMove = Timing.Global.MillisecondsUtc + mAttribute.Frequency;
}
}

Expand Down
4 changes: 4 additions & 0 deletions Intersect.Editor/Localization/Strings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4582,6 +4582,10 @@ public partial struct NpcEditor
{1, @"Turn Randomly"},
{2, @"Stand Still"},
{3, @"Static"},
{4, @"Horizontal Patrol"},
{5, @"Vertical Patrol"},
{6, @"Backslash Patrol (\)"},
{7, @"Forwardslash Patrol (/)"},
};

public static LocalizedString mpregen = @"MP (%):";
Expand Down
Loading
Loading