context: /*
      Copyright 2010 MCSharp team (Modified for use with MCZall/MCLawl/MCGalaxy)
      
      Dual-licensed under the    Educational Community License, Version 2.0 and
      the GNU General Public License, Version 3 (the "Licenses"); you may
      not use this file except in compliance with the Licenses. You may
      obtain a copy of the Licenses at
      
      http://www.opensource.org/licenses/ecl2.php
      http://www.gnu.org/licenses/gpl-3.0.html
      
      Unless required by applicable law or agreed to in writing,
      software distributed under the Licenses are distributed on an "AS IS"
      BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
      or implied. See the Licenses for the specific language governing
      permissions and limitations under the Licenses.
   */
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Threading;
  using System.Timers;
  
  namespace MCGalaxy {
      
      public sealed class PlayerBot {
          
  	    [Obsolete("Use PlayerBot.Bots.Items instead")]
          public static List<PlayerBot> playerbots;
          public static VolatileArray<PlayerBot> Bots = new VolatileArray<PlayerBot>(true);
  
          public bool hunt = false, kill = false;
  
          public string AIName = "";
          public string name, skinName;
          public string model = "humanoid";
          public byte id;
          public string color;
          public Level level;
          public int currentPoint = 0;
          public int countdown = 0;
          public bool nodUp = false;
          public List<Pos> Waypoints = new List<Pos>();
          public struct Pos { public string type, newscript; public int seconds, rotspeed; public ushort x, y, z; public byte rotx, roty; }
  
          public ushort[] pos = new ushort[3], oldpos = new ushort[3], foundPos = new ushort[3];
          public byte[] rot = new byte[2], oldrot = new byte[2], foundRot = new byte[2];
          bool movement = false;
          public int movementSpeed = 24;
          bool jumping = false;
          int currentjump = 0;
  
          System.Timers.Timer botTimer = new System.Timers.Timer(100);
          System.Timers.Timer moveTimer = new System.Timers.Timer(100 / 24);
          System.Timers.Timer jumpTimer = new System.Timers.Timer(95);
  
          #region == constructors ==
          public PlayerBot(string n, Level lvl, ushort x, ushort y, ushort z, byte rotx, byte roty) {
              name = n;
              skinName = n;
              color = "&1";
              id = FreeId();
              
              level = lvl;
              SetPos(x, y, z, rotx, roty);
  
              botTimer.Elapsed += BotTimerFunc;
              botTimer.Start();
              moveTimer.Elapsed += MoveTimerFunc;
              moveTimer.Start();
          }
          
          void BotTimerFunc(object sender, ElapsedEventArgs e) {
              int currentNum, foundNum = (32 * 75);
              Random rand = new Random();
              ushort x = (ushort)Math.Round((decimal)pos[0] / 32);
              ushort y = (ushort)((pos[1] - 33) / 32);
              ushort z = (ushort)Math.Round((decimal)pos[2] / 32);
  
              if (kill)
              {
              	Player[] players = PlayerInfo.Online.Items; 
                  foreach (Player p in players)
                  {
                      if ((ushort)(p.pos[0] / 32) == x)
                      {
                          if (Math.Abs((ushort)(p.pos[1] / 32) - y) < 2)
                          {
                              if ((ushort)(p.pos[2] / 32) == z)
                              {
                                  p.HandleDeath(Block.Zero);
                              }
                          }
                      }
                  }
              }
              movement = false;
  
              if (Waypoints.Count == 0)
              {
              	if (hunt) {
              		Player[] players = PlayerInfo.Online.Items;
              		foreach (Player p in players) {
                          if (p.level != level || p.invincible) continue;
                          
                          currentNum = Math.Abs(p.pos[0] - pos[0]) + Math.Abs(p.pos[1] - pos[1]) + Math.Abs(p.pos[2] - pos[2]);
                          if (currentNum < foundNum)
                          {
                              foundNum = currentNum;
                              foundPos = p.pos;
                              foundRot = p.rot;
                              movement = true;
                              rot[1] = (byte)(255 - foundRot[1]);
                              if (foundRot[0] < 128) rot[0] = (byte)(foundRot[0] + 128);
                              else rot[0] = (byte)(foundRot[0] - 128);
                          }
                      }
              	}
              }
              else
              {
                  bool skip = false;
                  
  
                  retry: switch (Waypoints[currentPoint].type)
                  {
                      case "walk":
                          foundPos[0] = Waypoints[currentPoint].x;
                          foundPos[1] = Waypoints[currentPoint].y;
                          foundPos[2] = Waypoints[currentPoint].z;
                          movement = true;
  
                          if ((ushort)(pos[0] / 32) == (ushort)(Waypoints[currentPoint].x / 32))
                          {
                              if ((ushort)(pos[2] / 32) == (ushort)(Waypoints[currentPoint].z / 32))
                              {
                                  rot[0] = Waypoints[currentPoint].rotx;
                                  rot[1] = Waypoints[currentPoint].roty;
                                  currentPoint++;
                                  movement = false;
  
                                  if (currentPoint == Waypoints.Count) currentPoint = 0;
                                  if (!skip) { skip = true; goto retry; }
                              }
                          }
                          break;
                      case "teleport":
                          pos[0] = Waypoints[currentPoint].x;
                          pos[1] = Waypoints[currentPoint].y;
                          pos[2] = Waypoints[currentPoint].z;
                          rot[0] = Waypoints[currentPoint].rotx;
                          rot[1] = Waypoints[currentPoint].roty;
                          currentPoint++;
                          if (currentPoint == Waypoints.Count) currentPoint = 0;
                          return;
                      case "wait":
                          if (countdown != 0)
                          {
                              countdown--;
                              if (countdown == 0)
                              {
                                  currentPoint++;
                                  if (currentPoint == Waypoints.Count) currentPoint = 0;
                                  if (!skip) { skip = true; goto retry; }
                              }
                          }
                          else
                          {
                              countdown = Waypoints[currentPoint].seconds;
                          }
                          return;
                      case "nod":
                          if (countdown != 0)
                          {
                              countdown--;
  
                              if (nodUp)
                              {
                                  if (rot[1] > 32 && rot[1] < 128) nodUp = !nodUp;
                                  else
                                  {
                                      if (rot[1] + (byte)Waypoints[currentPoint].rotspeed > 255) rot[1] = 0;
                                      else rot[1] += (byte)Waypoints[currentPoint].rotspeed;
                                  }
                              }
                              else
                              {
                                  if (rot[1] > 128 && rot[1] < 224) nodUp = !nodUp;
                                  else
                                  {
                                      if (rot[1] - (byte)Waypoints[currentPoint].rotspeed < 0) rot[1] = 255;
                                      else rot[1] -= (byte)Waypoints[currentPoint].rotspeed;
                                  }
                              }
  
                              if (countdown == 0)
                              {
                                  currentPoint++;
                                  if (currentPoint == Waypoints.Count) currentPoint = 0;
                                  if (!skip) { skip = true; goto retry; }
                              }
                          }
                          else
                          {
                              countdown = Waypoints[currentPoint].seconds;
                          }
                          return;
                      case "spin":
                          if (countdown != 0)
                          {
                              countdown--;
  
                              if (rot[0] + (byte)Waypoints[currentPoint].rotspeed > 255) rot[0] = 0;
                              else if (rot[0] + (byte)Waypoints[currentPoint].rotspeed < 0) rot[0] = 255;
                              else rot[0] += (byte)Waypoints[currentPoint].rotspeed;
  
                              if (countdown == 0)
                              {
                                  currentPoint++;
                                  if (currentPoint == Waypoints.Count) currentPoint = 0;
                                  if (!skip) { skip = true; goto retry; }
                              }
                          }
                          else
                          {
                              countdown = Waypoints[currentPoint].seconds;
                          }
                          return;
                      case "speed":
                          movementSpeed = (int)Math.Round((decimal)((decimal)24 / (decimal)100 * (decimal)Waypoints[currentPoint].seconds));
                          if (movementSpeed == 0) movementSpeed = 1;
  
                          currentPoint++;
                          if (currentPoint == Waypoints.Count) currentPoint = 0;
                          if (!skip) { skip = true; goto retry; }
                          return;
                      case "reset":
                          currentPoint = 0;
                          return;
                      case "remove":
                          PlayerBot.Remove(this);
                          return;
                      case "linkscript":
                          if (File.Exists("bots/" + Waypoints[currentPoint].newscript))
                          {
                              Command.all.Find("botset").Use(null, this.name + " " + Waypoints[currentPoint].newscript);
                              return;
                          }
  
                          currentPoint++;
                          if (currentPoint == Waypoints.Count) currentPoint = 0;
                          if (!skip) { skip = true; goto retry; }
                          return;
                      case "jump":
                          jumpTimer.Elapsed += delegate
                          {
                              currentjump++;
                              switch (currentjump)
                              {
                                  case 1:
                                      case 2: pos[1] += 24; break;
                                      case 3: break;
                                      case 4: pos[1] -= 24; break;
                                      case 5: pos[1] -= 24; jumping = false; currentjump = 0; jumpTimer.Stop(); break;
                              }
                          };
                          jumpTimer.Start();
  
                          currentPoint++;
                          if (currentPoint == Waypoints.Count) currentPoint = 0;
                          if (!skip) { skip = true; goto retry; }
                          break;
                  }
  
                  if (currentPoint == Waypoints.Count) currentPoint = 0;
              }
  
              if (!movement && Waypoints.Count > 0)
              {
                  if (rot[0] < 245) rot[0] += 8;
                  else rot[0] = 0;
  
                  if (rot[1] > 32 && rot[1] < 64) rot[1] = 224;
                  else if (rot[1] > 250) rot[1] = 0;
                  else rot[1] += 4;
              }
          }
          
          void MoveTimerFunc(object sender, ElapsedEventArgs e) {
              moveTimer.Interval = Server.updateTimer.Interval / movementSpeed;
              if (!movement) return;
              int newNum; Random rand = new Random();
  
              if ((pos[1] - 19) % 32 != 0 && !jumping)
              {
                  pos[1] = (ushort)((pos[1] + 19) - (pos[1] % 32));
              }
  
              ushort x = (ushort)Math.Round((decimal)(pos[0] - 16) / 32);
  
gt:             ushort y = (ushort)((pos[1] - 64) / 32);