@@ -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,141 +53,93 @@ public Critter(MapInstance map, byte x, byte y, MapCritterAttribute att) : base(
5053
5154 public override bool Update ( )
5255 {
53- if ( base . Update ( ) )
54- {
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- }
56+ if ( ! base . Update ( ) ) return false ;
7057
58+ // Only skip if we are NOT in the middle of a range-walk AND the frequency timer is active
59+ if ( _randomMoveRange <= 0 && _lastMove >= Timing . Global . MillisecondsUtc )
60+ {
7161 return true ;
7262 }
7363
74- return false ;
64+ switch ( mAttribute . Movement )
65+ {
66+ case 0 : // Move Randomly
67+ MoveRandomly ( ) ;
68+ break ;
69+ case 1 : // Turn Randomly
70+ DirectionFacing = Randomization . NextDirection ( ) ;
71+ // Set pause after turning
72+ _lastMove = Timing . Global . MillisecondsUtc + mAttribute . Frequency + Globals . Random . Next ( ( int ) ( mAttribute . Frequency * .5f ) ) ;
73+ break ;
74+ }
75+
76+ return true ;
7577 }
7678
7779 private void MoveRandomly ( )
7880 {
79- DirectionMoving = Randomization . NextDirection ( ) ;
80- var tmpX = ( sbyte ) X ;
81- var tmpY = ( sbyte ) Y ;
82- IEntity ? blockedBy = null ;
83-
81+ // Don't start a new step if currently mid-animation (sliding between tiles)
8482 if ( IsMoving || MoveTimer >= Timing . Global . MillisecondsUtc )
8583 {
8684 return ;
8785 }
8886
87+ // Path Selection: If no range left, pick a new direction and range
88+ if ( _randomMoveRange <= 0 )
89+ {
90+ DirectionFacing = Randomization . NextDirection ( ) ;
91+ _randomMoveRange = ( byte ) Randomization . Next ( 1 , 5 ) ; // 1-4 tiles
92+ }
93+
8994 var deltaX = 0 ;
9095 var deltaY = 0 ;
91-
92- switch ( DirectionMoving )
96+ switch ( DirectionFacing )
9397 {
94- case Direction . Up :
95- deltaX = 0 ;
96- deltaY = - 1 ;
97- break ;
98-
99- case Direction . Down :
100- deltaX = 0 ;
101- deltaY = 1 ;
102- break ;
103-
104- case Direction . Left :
105- deltaX = - 1 ;
106- deltaY = 0 ;
107- break ;
98+ case Direction . Up : deltaY = - 1 ; break ;
99+ case Direction . Down : deltaY = 1 ; break ;
100+ case Direction . Left : deltaX = - 1 ; break ;
101+ case Direction . Right : deltaX = 1 ; break ;
102+ case Direction . UpLeft : deltaX = - 1 ; deltaY = - 1 ; break ;
103+ case Direction . UpRight : deltaX = 1 ; deltaY = - 1 ; break ;
104+ case Direction . DownLeft : deltaX = - 1 ; deltaY = 1 ; break ;
105+ case Direction . DownRight : deltaX = 1 ; deltaY = 1 ; break ;
106+ }
108107
109- case Direction . Right :
110- deltaX = 1 ;
111- deltaY = 0 ;
112- break ;
108+ var newX = ( sbyte ) X + deltaX ;
109+ var newY = ( sbyte ) Y + deltaY ;
110+ IEntity ? blockedBy = null ;
113111
114- case Direction . UpLeft :
115- deltaX = - 1 ;
116- deltaY = - 1 ;
117- break ;
112+ // Collision and Map Boundary Check
113+ var isBlocked = - 1 == IsTileBlocked ( new Point ( newX , newY ) , Z , MapId , ref blockedBy , true , true , mAttribute . IgnoreNpcAvoids ) ;
114+ var playerOnTile = PlayerOnTile ( MapId , newX , newY ) ;
118115
119- case Direction . UpRight :
120- deltaX = 1 ;
121- deltaY = - 1 ;
122- break ;
116+ if ( isBlocked && ! playerOnTile &&
117+ newX >= 0 && newX < Options . Instance . Map . MapWidth &&
118+ newY >= 0 && newY < Options . Instance . Map . MapHeight )
119+ {
120+ // Execute Step
121+ X = ( byte ) newX ;
122+ Y = ( byte ) newY ;
123+ IsMoving = true ;
123124
124- case Direction . DownLeft :
125- deltaX = - 1 ;
126- deltaY = 1 ;
127- break ;
125+ // Visual offsets for smooth sliding animation [web:7]
126+ OffsetX = deltaX == 0 ? 0 : ( deltaX > 0 ? - Options . Instance . Map . TileWidth : Options . Instance . Map . TileWidth ) ;
127+ OffsetY = deltaY == 0 ? 0 : ( deltaY > 0 ? - Options . Instance . Map . TileHeight : Options . Instance . Map . TileHeight ) ;
128128
129- case Direction . DownRight :
130- deltaX = 1 ;
131- deltaY = 1 ;
132- break ;
133- }
129+ MoveTimer = Timing . Global . MillisecondsUtc + ( long ) GetMovementTime ( ) ;
130+ _randomMoveRange -- ;
134131
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 ) )
132+ // If this was the last step, set the IDLE pause timer
133+ if ( _randomMoveRange <= 0 )
153134 {
154- tmpX += ( sbyte ) deltaX ;
155- tmpY += ( sbyte ) deltaY ;
156- IsMoving = true ;
157- DirectionFacing = DirectionMoving ;
158-
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- }
167-
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- }
135+ _lastMove = Timing . Global . MillisecondsUtc + mAttribute . Frequency + Globals . Random . Next ( ( int ) ( mAttribute . Frequency * .5f ) ) ;
176136 }
177137 }
178-
179- if ( IsMoving )
180- {
181- X = ( byte ) tmpX ;
182- Y = ( byte ) tmpY ;
183- MoveTimer = Timing . Global . MillisecondsUtc + ( long ) GetMovementTime ( ) ;
184- }
185- else if ( DirectionMoving != DirectionFacing )
138+ else
186139 {
187- DirectionFacing = DirectionMoving ;
140+ // Blocked: End range early and trigger pause
141+ _randomMoveRange = 0 ;
142+ _lastMove = Timing . Global . MillisecondsUtc + mAttribute . Frequency ;
188143 }
189144 }
190145
0 commit comments