Im trying to understand this new change with Time and Framework 4..

Why was the NextReacquireTime changed from DateTime to a long?

Now this has broken a few of my AI scripts, since I was using the DateTime NextReacquireTime to compare to DateTime.Now on a couple methods,

I had this code;
if (m_Mobile.NextReacquireTime > DateTime.Now)
return false;

However, being NextReacquireTime is a long, it can not be converted/compared to DateTime..

I remember Voxpire posting something Mark wrote up explaining the change and how to update/convert new time handling, but can not find where that was.

Can anyone offer any sort of insight on this? I am wondering if I should use TimeSpan ReacquireDelay, but that is not really the same.

I will probably figure it out by time anyone posts. but it might help others out non the less.
 
Hey Dian. What were you using NextAcquireTime to check? Was it for a spell, skill, item use, etc...? There may be another variable that you can use instead. NextActionTime, NextCombatTime, NextSkillTime, NextSpellTime, all of these you might be able to use depending on what you want your script to do.
 
Here is a simple AI for HellHound. I cant even remember now if I made this, or got it somewhere.. but whatever.
As you can see, towards the lower half, is the line of code I posted above..
if (m_Mobile.NextReacquireTime > DateTime.Now)
{
return false;
}

I am converting my older RUO 2.2 server to ServUO, and this is causing some flak in several scripts. I have not really studied this area yet, so I figured I would post it here while I am working out other issues.. Maybe you or someone can see whats going on, and what would be best to convert it to.

Still wondering though, why the NextReacquireTime was changed from a DateTime to a long to begin with.. why was that necessary?

Thanks

C#:
using System;
using System.Collections.Generic;
using Server.Targeting;
using Server.Network;

namespace Server.Mobiles
{
  public class DireWolfAI : BaseAI
  {
  public DireWolfAI(BaseCreature m) : base(m)
  {
  }

  public override bool DoActionWander()
  {

  if (AcquireMyFocusMob(3, m_Mobile.FightMode))
  {
  Action = ActionType.Combat;
  m_Mobile.FightMode = FightMode.Closest;
  }
  if (AcquireMyFocusMob(6, m_Mobile.FightMode))
  {
  m_Mobile.Combatant = m_Mobile.FocusMob;
  Action = ActionType.Combat;
  m_Mobile.FightMode = FightMode.Closest;

  m_Mobile.DebugSay("I have noticed someone, my guard is up.");
  }
  else
  {
  Action = ActionType.Wander;
  m_Mobile.FightMode = FightMode.Aggressor;
  base.DoActionWander();
  }
  return true;
  }

  public override bool DoActionCombat()
  {
  Mobile combatant = m_Mobile.Combatant;

  if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map)
  {
  m_Mobile.DebugSay("My combatant is gone..");

  Action = ActionType.Wander;

  return true;
  }
  else
  {
  if (m_Mobile.GetDistanceToSqrt(combatant) > 11) // If target has run farther than 11 tiles away..
  {
  m_Mobile.DebugSay("I cannot find {0}", combatant.Name);

  Action = ActionType.Wander;
  m_Mobile.FightMode = FightMode.Closest;

  return true;
  }
  else
  {
  if (m_Mobile.Debug)
  m_Mobile.DebugSay("I should be closer to {0}", combatant.Name);
  }
  }

  if (!m_Mobile.Controlled && !m_Mobile.Summoned)
  {
  double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;

  if (hitPercent < 0.1)
  {
  m_Mobile.DebugSay("I am low on health!");
  Action = ActionType.Flee;
  }
  }

  return true;
  }

  public override bool DoActionGuard()
  {
  return base.DoActionGuard();
  }

  public override bool DoActionFlee()
  {
  //  AcquireFocusMob(m_Mobile.RangePerception * 2, m_Mobile.FightMode, true, false, true);

  m_Mobile.FightMode = FightMode.Aggressor;

  if (m_Mobile.FocusMob == null)
  m_Mobile.FocusMob = m_Mobile.Combatant;

  return base.DoActionFlee();
  }

  public override bool DoActionBackoff()
  {
  double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;

  if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1) // Less than 10% health
  {
  Action = ActionType.Flee;
  }
  else
  {
  if (!AcquireMyFocusMob(6, m_Mobile.FightMode))
  {
  if (WalkMobileRange(m_Mobile.FocusMob, 1, Utility.RandomBool(), m_Mobile.RangePerception, m_Mobile.RangePerception * 2))
  {
  m_Mobile.DebugSay("Well, here I am safe");
  Action = ActionType.Wander;
  }
  else
  {
  Action = ActionType.Combat;
  }
  }
  else
  {
  m_Mobile.DebugSay("I have lost my focus, lets relax");
  Action = ActionType.Wander;
  }
  }

  return true;
  }

  public override bool DoActionWanderSlow()
  {
  return base.DoActionWander(); // Temp re-route untill method is created.
  }

  public virtual bool AcquireMyFocusMob(int iRange, FightMode acqType)
  {
  TimeSpan reacquireDelay = TimeSpan.FromSeconds(5); //a custom reacquire delay (Dian)

  if (m_Mobile.Deleted)
  return false;

  if (m_Mobile.BardProvoked)
  {
  if (m_Mobile.BardTarget == null || m_Mobile.BardTarget.Deleted)
  {
  m_Mobile.FocusMob = null;
  return false;
  }
  else
  {
  m_Mobile.FocusMob = m_Mobile.BardTarget;
  return (m_Mobile.FocusMob != null);
  }

  }
  else if (m_Mobile.Controlled)
  {
  if (m_Mobile.ControlTarget == null || m_Mobile.ControlTarget.Deleted || !m_Mobile.ControlTarget.Alive || m_Mobile.ControlTarget.IsDeadBondedPet || !m_Mobile.InRange(m_Mobile.ControlTarget, m_Mobile.RangePerception * 2))
  {
  m_Mobile.FocusMob = null;
  return false;
  }
  else
  {
  m_Mobile.FocusMob = m_Mobile.ControlTarget;
  return (m_Mobile.FocusMob != null);
  }
  }

  if (m_Mobile.ConstantFocus != null)
  {
  m_Mobile.DebugSay("Acquired my constant focus");
  m_Mobile.FocusMob = m_Mobile.ConstantFocus;
  return true;
  }

  if (acqType == FightMode.None)
  {
  m_Mobile.FocusMob = null;
  return false;
  }

  if (m_Mobile.Aggressors.Count == 0 && m_Mobile.Aggressed.Count == 0)
  {
  m_Mobile.FocusMob = null;
  return false;
  }

  // We dont ReAcquire a new FocusMob untill the following property of NextReacquireTime is older than DateTime.Now
  if (m_Mobile.NextReacquireTime > DateTime.Now)
  {
  return false;
  }

  // NextReacquireTime adjusts only after the above 'IF' statement is false
  m_Mobile.NextReacquireTime = DateTime.Now + reacquireDelay;

  m_Mobile.DebugSay("Acquiring...");

  Map map = m_Mobile.Map;

  if (map != null)
  {
  Mobile newFocusMob = null;
  //  double val = double.MinValue;

  IPooledEnumerable eable = map.GetMobilesInRange(m_Mobile.Location, iRange);

  foreach (Mobile m in eable)
  {
  bool bCheckIt = false;

  //
  // Basic check
  // Of the Mobiles in range, if one or more are Players...
  if (m.Player)
  {
  // And, Accesslevel equals Player, they are alive, not blessed, not deleted, excluding myself, and I am permitted to 'see' the other players..
  if (m.AccessLevel == AccessLevel.Player && m.Alive && !m.Blessed && !m.Deleted && m != m_Mobile && m_Mobile.CanSee(m))
  {
  newFocusMob = m;
  bCheckIt = true;
  }
  }

  // If passed this far, and I am not Controlled, but I am a Summoned Pet (like from a spell, SummonDeamon)
  if (bCheckIt && !m_Mobile.Controlled && m_Mobile.Summoned && m_Mobile.SummonMaster != null)
  {
  // If so, do not focus on my creator/owners..
  bCheckIt = (m != m_Mobile.SummonMaster && Server.Spells.SpellHelper.ValidIndirectTarget(m_Mobile.SummonMaster, m));

  if (bCheckIt && m is PlayerMobile && m_Mobile.IsAnimatedDead)
  bCheckIt = false;
  }

  //
  // Team check
  //

  if (bCheckIt)
  {
  bCheckIt = false;
  // If there is an aggressor in range, bCheckit is true, so continue..
  for (int a = 0; !bCheckIt && a < m_Mobile.Aggressors.Count; ++a)
  bCheckIt = (((AggressorInfo)m_Mobile.Aggressors[a]).Attacker == m);
  // If there is an old aggressor in range, bCheckit is true, so continue..
  for (int a = 0; !bCheckIt && a < m_Mobile.Aggressed.Count; ++a)
  bCheckIt = (((AggressorInfo)m_Mobile.Aggressed[a]).Defender == m);
  }

  if (bCheckIt && !m_Mobile.CanBeHarmful(m, false))
  bCheckIt = false;

  }

  eable.Free();

  m_Mobile.FocusMob = newFocusMob;
  }

  return (m_Mobile.FocusMob != null);
  }
  }
}
 
I see your problem now. I don't have an answer as to why they changed NextAcquireTime to a long, but after some reviewing of code in ServUO I might have a solution for you.

Try replacing these lines:
Code:
// We dont ReAcquire a new FocusMob untill the following property of NextReacquireTime is older than DateTime.Now
  if (m_Mobile.NextReacquireTime > DateTime.Now)
  {
  return false;
  }

  // NextReacquireTime adjusts only after the above 'IF' statement is false
  m_Mobile.NextReacquireTime = DateTime.Now + reacquireDelay;

with this:

Code:
      if (m_Mobile.NextReacquireTime > Core.TickCount)
       {
         m_Mobile.FocusMob = null;
         return false;
       }

       m_Mobile.NextReacquireTime = Core.TickCount + (int)m_Mobile.ReacquireDelay.TotalMilliseconds;

I found that code in BaseAI from ServUO and it seems to show how to use NextReacquireTime as a long.
 
Thanks, Vi

I will check that out. Its just odd that NextReacquireTime was even altered. I mean, its meant to hold a time stamp after all. I know theres other ways to do what I have there, like you posted might just be it, but just strange why it changed.

I will let you know if it works out.. of course now I guess I will have to debug my Mobile's to see if it actually does what its meant to do..
 
Okay.. so now that I am using Core.TickCounts, how does that compare now..

If before I was using;
m_Mobile.NextReacquireTime = DateTime.Now + reacquireDelay;

how many TickCounts would work out to one second ? I guess I am going to be adding in Miliseconds then? Is that 100 TickCounts equal to one second, or is that 600 Miliseconds?

Feeling newbish at the moment, lol,
 
My other AI snippet that is same but different issue.
The line mid/center`ish...

if ( (m_Mobile.LastMoveTime + TimeSpan.FromSeconds( 1.0 )) < DateTime.Now )

C#:
     public override bool DoActionCombat()
     {
       if ( SiezePersuit || m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted || !m_Mobile.Combatant.Alive || m_Mobile.Combatant.IsDeadBondedPet )
       {
         m_Mobile.DebugSay( "My combatant is gone, so my guard is up" );
         m_Mobile.FocusMob = null;
         m_Mobile.Combatant = null;
         Action = ActionType.Guard;
         return true;
       }

       if ( (m_Mobile.LastMoveTime + TimeSpan.FromSeconds( 1.0 )) < DateTime.Now )
       {

     //     WalkMobileRange( Mobile, iSteps, bool bRun, iWantDistMin, iWantDistMax
         if (WalkMobileRange(m_Mobile.Combatant, 1, true, 2, 6 ) ) //m_Mobile.Weapon.MaxRange ))
         {
           // Be sure to face the combatant
           m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location);
         }
         else
         {
           if ( m_Mobile.Combatant != null )
           {
             if ( m_Mobile.Debug )
               m_Mobile.DebugSay( "I am still not in range of {0}", m_Mobile.Combatant.Name);
             
             // Let guards keep running after mobiles, even if well off the screen
             if ( (int) m_Mobile.GetDistanceToSqrt( m_Mobile.Combatant ) > m_Mobile.RangePerception + 25 )
             {
               if ( m_Mobile.Debug )
                 m_Mobile.DebugSay( "I have lost {0}", m_Mobile.Combatant.Name);

               m_Mobile.Combatant = null;
               Action = ActionType.Guard;
               return true;
             }
           }
         }
       }
 
I think I got it.. Do you think this is doing about the same as above??

C#:
     public override bool DoActionCombat()
     {
       if ( SiezePersuit || m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted || !m_Mobile.Combatant.Alive || m_Mobile.Combatant.IsDeadBondedPet )
       {
         m_Mobile.DebugSay( "My combatant is gone, so my guard is up" );
         m_Mobile.FocusMob = null;
         m_Mobile.Combatant = null;
         Action = ActionType.Guard;
         return true;
       }

       //if ( (m_Mobile.LastMoveTime + TimeSpan.FromSeconds( 1.0 )) < DateTime.Now )
  if(m_Mobile.LastMoveTime < Core.TickCount)
       {

     //     WalkMobileRange( Mobile, iSteps, bool bRun, iWantDistMin, iWantDistMax
         if (WalkMobileRange(m_Mobile.Combatant, 1, true, 2, 6 ) ) //m_Mobile.Weapon.MaxRange ))
         {
           // Be sure to face the combatant
           m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location);
         }
         else
         {
           if ( m_Mobile.Combatant != null )
           {
             if ( m_Mobile.Debug )
               m_Mobile.DebugSay( "I am still not in range of {0}", m_Mobile.Combatant.Name);
            
             // Let guards keep running after mobiles, even if well off the screen
             if ( (int) m_Mobile.GetDistanceToSqrt( m_Mobile.Combatant ) > m_Mobile.RangePerception + 25 )
             {
               if ( m_Mobile.Debug )
                 m_Mobile.DebugSay( "I have lost {0}", m_Mobile.Combatant.Name);

               m_Mobile.Combatant = null;
               Action = ActionType.Guard;
               return true;
             }
           }
         }
       }

  m_Mobile.LastMoveTime = Core.TickCount + (int)TimeSpan.FromSeconds(1.0).TotalMilliseconds;
 
how many TickCounts would work out to one second ?

This is a good question. It varies, depending on the machine that is running ServUO. If you want to test your machine to see how many ticks happen in 1 second on your machine, there is a static function from http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.frequency.aspx which I'll copy/paste here for easy use:
Code:
public static void DisplayTimerProperties()
{
// Display the timer frequency and resolution.
if (Stopwatch.IsHighResolution)
{
Console.WriteLine("Operations timed using the system's high-resolution performance counter.");
}
else
{
Console.WriteLine("Operations timed using the DateTime class.");
}

long frequency = Stopwatch.Frequency;
Console.WriteLine(" Timer frequency in ticks per second = {0}",
frequency);
long nanosecPerTick = (1000L*1000L*1000L) / frequency;
Console.WriteLine(" Timer is accurate within {0} nanoseconds",
nanosecPerTick);
}

Knowing the exact number of ticks per second on your machine may help the rest of your AI problems.

As for Mobile.LastMoveTime, I found this if statement in ArcherAI that may be of use:
Code:
if (Core.TickCount - m_Mobile.LastMoveTime > 1000)
 
Hmm good catch, since this AI is my ArcharGuardAI, and used bits of the ArcherAI in it. I will look at it, it might just be what I need, already done :)
 
Yep, seems that was the same change I needed that you found, Vi :)

Those were the last conflicts with my conversion :D Finally got a clean compile of the server after about 5 days now, lol.
Now I can move on to doing some serialization manipulation to my RUO2.2 server saves... yipppie! :confused:
 
Back