using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using Zeta;
using Zeta.Common;
using Zeta.CommonBot;
using Zeta.Common.Plugins;
using Zeta.Internals;
using Zeta.Internals.Actors;
using Zeta.Internals.Service;
namespace Eax.Plugins
{
public class Unstucker : IPlugin
{
private bool IsRestarting { get; set; }
private bool IsChecking { get; set; }
private int MoveTries { get; set; }
private int MoveTriesMax { get; set; }
private DateTime LastCheckTime { get; set; }
private DateTime LastLogTime { get; set; }
private List<Vector3> LoggedPositions { get; set; }
public string Author { get { return "eax"; } }
public string Description { get { return "Unstucks you when you're stuck."; } }
public string Name { get { return "Unstucker v" + Version.ToString(); } }
public Version Version { get { return new Version(1, 8); } }
public Window DisplayWindow { get { return null; } }
private void Log(string message)
{
Logging.Write(string.Format("[{0}] {1}", Name, message));
}
private static float GetMaxDistanceTraveled(List<Vector3> positions)
{
float max = 0F;
for (int i = 0; i < positions.Count - 1; ++i)
for (int j = 1; j < positions.Count; ++j)
max = Math.Max(max, Math.Abs(positions[i].Distance(positions[j])));
return max;
}
public void OnInitialize()
{
IsRestarting = false;
IsChecking = false;
LastCheckTime = DateTime.Now;
LastLogTime = DateTime.Now;
MoveTries = 0;
MoveTriesMax = 5;
LoggedPositions = new List<Vector3>();
}
public void RemoveAllBehavior()
{
ProfileManager.CurrentProfileBehavior.ResetCachedDone();
}
public void OnPulse()
{
// if we're not in game and not in the process of restarting, do nothing
if (!ZetaDia.IsInGame || !ZetaDia.Me.IsValid)
{
LastCheckTime = DateTime.Now;
LastLogTime = DateTime.Now;
LoggedPositions.Clear();
return;
}
// Did I invoke Restart and finally got to the Town?
if( ZetaDia.Me.IsInTown && IsRestarting )
{
// Leave the game and reset everything
Log( "Leaving the game." );
Clear();
ZetaDia.Service.Games.LeaveGame();
return;
}
// if it's been 4 seconds since we've logged a position, then we log a new position
if (DateTime.Now.Subtract(LastLogTime).TotalSeconds > 4)
{
LastLogTime = DateTime.Now;
LoggedPositions.Add(ZetaDia.Actors.Me.Position);
}
// if it's been 30 seconds since we've last evaluated the logged positions, evaluate the logged positions
if (!IsChecking && (LoggedPositions.Count > 5) && (DateTime.Now.Subtract(LastCheckTime).TotalSeconds > 30))
{
// we want to prevent this section from being executed twice - can that even happen with one thread?
IsChecking = true;
var rnd = new Random();
// if our person has not traveled 10 yards or whatever in the last 30 seconds, we're stuck
if (GetMaxDistanceTraveled(LoggedPositions) < 10f)
{
Log("Seems the bot just got stuck.");
IsRestarting = true;
var v = ZetaDia.Me.Position;
var oldPosition = v;
do {
if (MoveTries > MoveTriesMax)
{
Log("Random moving was unsuccessful - moving to town and restarting bot.");
Log( "Using Town Portal." );
RemoveAllBehavior();
ZetaDia.Me.UseTownPortal();
return;
}
v.X = (DateTime.Now.Millisecond % 2 == 0) ? v.X + rnd.Next(500, 6500) : v.X - rnd.Next(500, 6500);
v.Y = (DateTime.Now.Millisecond % 2 == 0) ? v.Y + rnd.Next(500, 6500) : v.Y - rnd.Next(500, 6500);
v.Z = (DateTime.Now.Millisecond % 2 == 0) ? v.Z + rnd.Next(500, 6500) : v.Z - rnd.Next(500, 6500);
Log("Moving Char randomly to: " + v.ToString());
ZetaDia.Me.UsePower(SNOPower.Walk, v, ZetaDia.Me.WorldDynamicId, 2, -1);
MoveTries++;
Thread.Sleep(rnd.Next(1000, 3000)); // Is there a better way via api?
} while (ZetaDia.Me.Position == oldPosition);
IsRestarting = false;
}
Clear();
}
}
private void Clear()
{
MoveTries = 0;
IsChecking = false;
LastCheckTime = DateTime.Now;
LastLogTime = DateTime.Now;
LoggedPositions.Clear();
}
public void OnShutdown()
{
}
public void OnEnabled()
{
Log("Enabled.");
}
public void OnDisabled()
{
Log("Disabled.");
}
public bool Equals(IPlugin other)
{
return (other.Name == Name) && (other.Version == Version);
}
}
}