@@ -15,7 +15,10 @@ namespace Intersect.Client.Entities;
1515public partial class Critter : Entity
1616{
1717 private readonly MapCritterAttribute mAttribute ;
18- private long mLastMove = - 1 ;
18+
19+ // Critter's Movement
20+ private long _lastMove = - 1 ;
21+ private byte _randomMoveRange ;
1922
2023 public Critter ( MapInstance map , byte x , byte y , MapCritterAttribute att ) : base ( Guid . NewGuid ( ) , null , EntityType . GlobalEntity )
2124 {
@@ -50,65 +53,65 @@ public Critter(MapInstance map, byte x, byte y, MapCritterAttribute att) : base(
5053
5154 public override bool Update ( )
5255 {
53- if ( base . Update ( ) )
56+ if ( ! base . Update ( ) )
5457 {
55- if ( mLastMove < Timing . Global . MillisecondsUtc )
56- {
57- switch ( mAttribute . Movement )
58- {
59- case 0 : //Move Randomly
60- MoveRandomly ( ) ;
61- break ;
62- case 1 : //Turn?
63- DirectionFacing = Randomization . NextDirection ( ) ;
64- break ;
65-
66- }
67-
68- mLastMove = Timing . Global . MillisecondsUtc + mAttribute . Frequency + Globals . Random . Next ( ( int ) ( mAttribute . Frequency * .5f ) ) ;
69- }
58+ return false ;
59+ }
7060
61+ // Only skip if we are NOT in the middle of a range-walk AND the frequency timer is active
62+ if ( _randomMoveRange <= 0 && _lastMove >= Timing . Global . MillisecondsUtc )
63+ {
7164 return true ;
7265 }
7366
74- return false ;
67+ switch ( mAttribute . Movement )
68+ {
69+ case 0 : // Move Randomly
70+ MoveRandomly ( ) ;
71+ break ;
72+ case 1 : // Turn Randomly
73+ DirectionFacing = Randomization . NextDirection ( ) ;
74+ // Set pause after turning
75+ _lastMove = Timing . Global . MillisecondsUtc + mAttribute . Frequency + Globals . Random . Next ( ( int ) ( mAttribute . Frequency * .5f ) ) ;
76+ break ;
77+ }
78+
79+ return true ;
7580 }
7681
7782 private void MoveRandomly ( )
7883 {
79- DirectionMoving = Randomization . NextDirection ( ) ;
80- var tmpX = ( sbyte ) X ;
81- var tmpY = ( sbyte ) Y ;
82- IEntity ? blockedBy = null ;
83-
84+ // Don't start a new step if currently moving between tiles
8485 if ( IsMoving || MoveTimer >= Timing . Global . MillisecondsUtc )
8586 {
8687 return ;
8788 }
8889
90+ // No range left: pick a new direction and range
91+ if ( _randomMoveRange <= 0 )
92+ {
93+ DirectionFacing = Randomization . NextDirection ( ) ;
94+ _randomMoveRange = ( byte ) Randomization . Next ( 1 , 5 ) ;
95+ }
96+
8997 var deltaX = 0 ;
9098 var deltaY = 0 ;
91-
92- switch ( DirectionMoving )
99+ switch ( DirectionFacing )
93100 {
94101 case Direction . Up :
95- deltaX = 0 ;
96102 deltaY = - 1 ;
97103 break ;
98104
99105 case Direction . Down :
100- deltaX = 0 ;
101106 deltaY = 1 ;
102107 break ;
103108
104109 case Direction . Left :
105110 deltaX = - 1 ;
106- deltaY = 0 ;
107111 break ;
108112
109113 case Direction . Right :
110114 deltaX = 1 ;
111- deltaY = 0 ;
112115 break ;
113116
114117 case Direction . UpLeft :
@@ -132,59 +135,37 @@ private void MoveRandomly()
132135 break ;
133136 }
134137
135- if ( deltaX != 0 || deltaY != 0 )
136- {
137- var newX = tmpX + deltaX ;
138- var newY = tmpY + deltaY ;
139- var isBlocked = - 1 ==
140- IsTileBlocked (
141- new Point ( newX , newY ) ,
142- Z ,
143- MapId ,
144- ref blockedBy ,
145- true ,
146- true ,
147- mAttribute . IgnoreNpcAvoids
148- ) ;
149- var playerOnTile = PlayerOnTile ( MapId , newX , newY ) ;
150-
151- if ( isBlocked && newX >= 0 && newX < Options . Instance . Map . MapWidth && newY >= 0 && newY < Options . Instance . Map . MapHeight &&
152- ( ! mAttribute . BlockPlayers || ! playerOnTile ) )
153- {
154- tmpX += ( sbyte ) deltaX ;
155- tmpY += ( sbyte ) deltaY ;
156- IsMoving = true ;
157- DirectionFacing = DirectionMoving ;
138+ var newX = ( sbyte ) X + deltaX ;
139+ var newY = ( sbyte ) Y + deltaY ;
140+ IEntity ? blockedBy = null ;
158141
159- if ( deltaX == 0 )
160- {
161- OffsetX = 0 ;
162- }
163- else
164- {
165- OffsetX = deltaX > 0 ? - Options . Instance . Map . TileWidth : Options . Instance . Map . TileWidth ;
166- }
142+ // Boundary checks
143+ var isBlocked = - 1 == IsTileBlocked ( new Point ( newX , newY ) , Z , MapId , ref blockedBy , true , true , mAttribute . IgnoreNpcAvoids ) ;
144+ var playerOnTile = PlayerOnTile ( MapId , newX , newY ) ;
167145
168- if ( deltaY == 0 )
169- {
170- OffsetY = 0 ;
171- }
172- else
173- {
174- OffsetY = deltaY > 0 ? - Options . Instance . Map . TileHeight : Options . Instance . Map . TileHeight ;
175- }
176- }
177- }
178-
179- if ( IsMoving )
146+ if ( isBlocked && ! playerOnTile &&
147+ newX >= 0 && newX < Options . Instance . Map . MapWidth &&
148+ newY >= 0 && newY < Options . Instance . Map . MapHeight )
180149 {
181- X = ( byte ) tmpX ;
182- Y = ( byte ) tmpY ;
150+ X = ( byte ) newX ;
151+ Y = ( byte ) newY ;
152+ IsMoving = true ;
153+ OffsetX = deltaX == 0 ? 0 : ( deltaX > 0 ? - Options . Instance . Map . TileWidth : Options . Instance . Map . TileWidth ) ;
154+ OffsetY = deltaY == 0 ? 0 : ( deltaY > 0 ? - Options . Instance . Map . TileHeight : Options . Instance . Map . TileHeight ) ;
183155 MoveTimer = Timing . Global . MillisecondsUtc + ( long ) GetMovementTime ( ) ;
156+ _randomMoveRange -- ;
157+
158+ // Critter's last step: set an idle pause timer
159+ if ( _randomMoveRange <= 0 )
160+ {
161+ _lastMove = Timing . Global . MillisecondsUtc + mAttribute . Frequency + Globals . Random . Next ( ( int ) ( mAttribute . Frequency * .5f ) ) ;
162+ }
184163 }
185- else if ( DirectionMoving != DirectionFacing )
164+ else
186165 {
187- DirectionFacing = DirectionMoving ;
166+ // Blocked by something: end range early and trigger pause
167+ _randomMoveRange = 0 ;
168+ _lastMove = Timing . Global . MillisecondsUtc + mAttribute . Frequency ;
188169 }
189170 }
190171
0 commit comments