Hi,

I noticed that mobiles in general don't use their run effect (animation). They seem to be always walking, even if I improve their movement speed, they just walk very fast (actually giving the impression of teleporting towards a target) in warmode.

I want the monsters, bandits and animals to use their run animation. Just like a player does.
I know how to modify their default active and passive speed, but can't figure out how to get rid of this weird forced walk effect...

Any ideas?
 
The client is responsible for the walking/running animations, if you [move any mobile to a tile next to it, you'll see the client makes it look like it's "walking".

I believe in order for the client to interpret a one-tile move as a running movement, it would have to know about it for creatures - this could maybe be done by including the Direction.Running flag when the AI tells the creature to move. If I remember correctly, AI just uses the direction as a way to point the creature before moving it.

This is just a theory though, if it works, let me know :p
I'll test it myself at some point tonight.
 
They only run if they are fast enough, so to speak.
Yes, I have a mob with speed ActiveSpeed: 0.150, PassiveSpeed: 0.4 and still it just stays in WarMode and sort of flows towards the enemy in combat position instead of a clear run animation. I was wondering if it's something with my animations, but when I reverse the logic in Voxpire's code mobiles do run when idle. Just not in WarMode
 
Hey Voxpire, I was looking at the merge request, and I noticed that it only looks like it uses the run animation when at or exceeding run speed. Shouldn't it use the run animation whenever it exceeds walking speed instead to prevent 'bouncing/teleporting'?
 
A few things:

1) Does this move creatures? If so, more edits might be needed to cover all movement types.

if (m_Path.Follow(run, 1))

2) How about these two lines instead of your version?

bool mounted = m_Mobile.Mounted || m_Mobile.Flying;
bool running = (mounted && delay < Mobile.WalkMount) || (!mounted && delay < Mobile.WalkFoot);

(Your version down here)

var mounted = m_Mobile.Mounted || m_Mobile.Flying;
var running = (mounted && delay <= Mobile.WalkMount) || (!mounted && delay <= Mobile.RunFoot);

It seems almost certain the issue is arising from that pathing stuff in walkmobilerange(). I don't really know how that stuff is working. Simply overriding bRun to true doesn't work, so it is not properly implementing the run flag.
 
Last edited:
The edits I implemented work fine, they match what would be observed by a player's movement.

Take a look at how the Wanderer handles its movement without AI, it uses a similar technique with appending the Running direction flag.
If you make a wanderer use a human body, it will run properly, same for any NPC using the new AI edits.

I did notice something though, the client doesn't seem to have running animations for most bodies when they are in war mode, so they still appear to be walking.
 
I did notice something though, the client doesn't seem to have running animations for most bodies when they are in war mode, so they still appear to be walking.
That must be the reason I couldn't see them running. Do you know if there's a way to force the client to use normal running animation instead of a dedicated, non existent warmode-running animation?
 
That must be the reason I couldn't see them running. Do you know if there's a way to force the client to use normal running animation instead of a dedicated, non existent warmode-running animation?

Unfortunately not, unless there's a way to never notify the client when a BaseCreature changes to War Mode.
If the client doesn't think the mobile is in War Mode, then it won't use those animations.
 
The edits I implemented work fine, they match what would be observed by a player's movement.

Take a look at how the Wanderer handles its movement without AI, it uses a similar technique with appending the Running direction flag.
If you make a wanderer use a human body, it will run properly, same for any NPC using the new AI edits.

I did notice something though, the client doesn't seem to have running animations for most bodies when they are in war mode, so they still appear to be walking.

No running animations for warmode, huh. Seems like a hell of an oversight. And not just reusing the normal running animations either. Seems like that would be the thing to do.

If a non-mounted creature is moving at 201-399 ms, it should use the run animation, rather than walk, right? Because Walk speed uses 400 ms to execute, so even holding the button down, the fastest speed is 400 ms, right? In player behavior, it would be like repeatedly tapping to move while running?

Unfortunately not, unless there's a way to never notify the client when a BaseCreature changes to War Mode.
If the client doesn't think the mobile is in War Mode, then it won't use those animations.

I noticed in a lot of places that it has it set to not run within 5 tiles of the target, and claims that this is 'like OSI'. What if this relates to warmode being activated on OSI? ie if it's more than X tiles away, warmode is false, but if within X tiles, it's true.
I don't recall OSI's behavior, so does it do this, or does it just walk all the time, or something else? It also might just be intended for following the master.

Edit: Thinking back, I recall getting mobiles to run back in runUO2.5/.6. There was an issue with them 'bouncing' when they stopped to fight, though.
[doublepost=1491083786][/doublepost]Here's my WalkMobileRange that makes them run. Perhaps you can suss out the difference that made it work. Note that the turning shennanigans were my ad hoc solution to make them stop bouncing if they were. Perhaps someone better with coding can make it unnecessary to do the turning while preserving the running.

Code:
//GS
     public virtual bool ShouldRun()
     {
       if ( m_Mobile.AllowedStealthSteps > 0 )
         return false;

       return m_Mobile.CanRun;
     }

     public virtual bool WalkMobileRange(Mobile m, int iWantDist)
     {
       bool bRun = ShouldRun();
       return WalkMobileRange(m, 1, bRun, iWantDist, iWantDist);
     }

     public virtual bool WalkMobileRange(Mobile m, int iWantDistMin, int iWantDistMax)
     {
       bool bRun = ShouldRun();
       return WalkMobileRange(m, 1, bRun, iWantDistMin, iWantDistMax);
     }
    
     public virtual bool WalkMobileRange(Mobile m, bool bRun, int iWantDistMin, int iWantDistMax)
     {
       return WalkMobileRange(m, 1, bRun, iWantDistMin, iWantDistMax);
     }
    
     public virtual bool WalkMobileRange(Mobile f, int iSteps, bool bRun, int iWantDistMin, int iWantDistMax)
     {
       BaseCreature m = m_Mobile as BaseCreature;

       if (m.Deleted)
         return false;

       if ( f == null || f.Deleted || !f.Alive || f.Map != m.Map )
         return false;

       int iOldDist = (int)m.GetDistanceToSqrt(f);

       // Already where I want to be
       if ( iOldDist >= iWantDistMin && iOldDist <= iWantDistMax )
       {
         CheckTurn(f);
         return true;
       }

       // I'm either too close or too far
       // I'm unable to move!
       if ( BlockingMove() || m.DisallowAllMoves)
       {
         CheckTurn(f);
         return false;
       }

       // Walk to my target
       for (int i = 0; i < iSteps; i++)
       {
         // Get the current distance
         int iCurrDist = (int)m.GetDistanceToSqrt(f);

         if (iCurrDist < iWantDistMin || iCurrDist > iWantDistMax)
         {
           bool needCloser = (iCurrDist > iWantDistMax);

           if (needCloser && m_Path != null && m_Path.Goal == f)
           {
             if (m_Path.Follow(bRun, 1))
               m_Path = null;
           }
           else
           {
             Direction dirTo;

             if (needCloser)
               dirTo = m.GetDirectionTo(f);
             else
               dirTo = f.GetDirectionTo(m);

             // Add the run flag
             if (bRun)
               dirTo = dirTo | Direction.Running;

             if (!DoMove(dirTo, true))
             {
               if (needCloser)
               {
                 m_Path = new PathFollower(m, f);
                 m_Path.Mover = new MoveMethod(DoMoveImpl);

                 if (m_Path.Follow(bRun, 1))
                   m_Path = null;
               }
               else
               {
                 m.Direction = m.GetDirectionTo(f);
                 m_Path = null;
               }
             }
             else
             {
               m_Path = null;
             }
           }
         }
       }

       // Am I where I want to be now?
       int iNewDist = (int)m.GetDistanceToSqrt(f);

       if (iNewDist >= iWantDistMin && iNewDist <= iWantDistMax)
         return true;
       return false;
     }

     public virtual void CheckTurn( Mobile f )
     {
       BaseCreature m = m_Mobile as BaseCreature;
       if ( f == null )
         return;
      
       if ( Core.TickCount <= m.LastMoveTime + 1000 )
         return;

       if ( Core.TickCount <= NextTurn )
         return;

       Direction d = m.GetDirectionTo(f);
       if ( d != m.Direction && (BlockingMove() || m.DisallowAllMoves || Core.TickCount >= m.LastMoveTime + 2000) )
       {
         NextTurn = Core.TickCount + 1000;
         m.Direction = d;
       }
       else if ( Core.TickCount < m.LastMoveTime + 2000 )
       {
         d = (Direction)((int)d + Utility.RandomList(-1, +1));
         Timer.DelayCall(TimeSpan.FromMilliseconds(1), new TimerStateCallback(Turn), f);
         NextTurn = Core.TickCount + 1000;
         m.Direction = d;
       }
     }

     public virtual void Turn(object o)
     {
       BaseCreature m = m_Mobile as BaseCreature;
       if ( m == null || m.Deleted || !m.Alive || m.Map == null || m.Map == Map.Internal )
         return;
       Mobile f = o as Mobile;
       if ( f == null || f.Deleted || !f.Alive || f.Map == null || f.Map == Map.Internal )
         return;
       if ( m.Map != f.Map )
         return;
       m.Direction = m.GetDirectionTo(f);  
     }

     public virtual bool BlockingMove()
     {
       if ( m_Mobile.Spell == null || !m_Mobile.Spell.IsCasting || m_Mobile.Target != null )
         return false;
       if ( m_Mobile.Spell != null && m_Mobile.Spell.IsCasting )
         return true;
       return false;
     }
 
Last edited:
I think I remember SunUO using normal running animations until a mob had to walk. I'll have a look if it disabled WarMode in combat if the enemy was further than a few tiles or something
 
Can anyone confirm it's fixed in newer ServUO releases than 54? I'm planning on merging the newest repo, but need to prepare a few file.

Weird thing I noticed is that mobiles still run when they are running away with low hp, but not when they run towards the enemy. WarMode has nothing to do with it since mobiles running away still have WarMode on, event guarding pets have WarMode on and they seem to run fine. Really strange
 
Back