using System; using System.Data; using System.Text; using System.Threading; using System.Collections; using Holo.Virtual.Users; using Holo.Virtual.Rooms.Pathfinding; using Ion.Storage; namespace Holo.Virtual.Rooms.Bots { internal class virtualBot { #region Declares internal int roomUID; internal virtualRoom Room; internal string Name; internal string Mission; internal string Figure; internal int X; internal int Y; internal double H; internal byte Z1; internal byte Z2; internal int goalX; internal int goalY; internal bool freeRoam; internal string noShoutingMessage; private delegate void statusVoid(string Key, string Value, int Length); private Thread aiHandler; private string[] Sayings; private string[] Shouts; private Coord[] Coords; private chatTrigger[] chatTriggers; private virtualRoomUser Customer; private chatTrigger customerTrigger; #endregion #region Constructors/destructors private Hashtable Statuses; internal virtualBot(int botID, int roomUID, virtualRoom Room) { this.roomUID = roomUID; this.Room = Room; DataRow dRow; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dRow = dbClient.getRow("SELECT name,mission,figure,x,y,z,freeroam,message_noshouting FROM roombots WHERE id = '" + botID + "'"); } this.Name = Convert.ToString(dRow[0]); this.Mission = Convert.ToString(dRow[1]); this.Figure = Convert.ToString(dRow[2]); this.X = Convert.ToInt32(dRow[3]); this.Y = Convert.ToInt32(dRow[4]); this.Z1 = Convert.ToByte(dRow[5]); this.Z2 = Z1; this.goalX = -1; this.freeRoam = (Convert.ToString(dRow[6]) == "1"); this.noShoutingMessage = Convert.ToString(dRow[7]); DataColumn dCol; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dCol = dbClient.getColumn("SELECT text FROM roombots_texts WHERE id = '" + botID + "' AND type = 'say'"); } this.Sayings = (string[])dataHandling.dColToArray(dCol); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dCol = dbClient.getColumn("SELECT text FROM roombots_texts WHERE id = '" + botID + "' AND type = 'shout'"); } this.Shouts = (string[])dataHandling.dColToArray(dCol); DataTable dTable; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dTable = dbClient.getTable("SELECT words, replies, serve_replies, serve_item FROM roombots_texts_triggers WHERE id = '" + botID + "'"); } this.chatTriggers = new chatTrigger[dTable.Rows.Count]; int i = 0; foreach (DataRow dbRow in dTable.Rows) { this.chatTriggers[i] = new chatTrigger((Convert.ToString(dbRow["words"]).ToLower()).Split('}'), (Convert.ToString(dbRow["replies"])).Split('}'), (Convert.ToString(dbRow["serve_replies"])).Split('}'), Convert.ToString(dbRow["serve_item"])); i++; } using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dTable = dbClient.getTable("SELECT x,y FROM roombots_coords WHERE id = '" + botID + "'"); } Coords = new Coord[dTable.Rows.Count]; i = 0; foreach (DataRow dbRow in dTable.Rows) { Coords[i] = new Coord(Convert.ToInt32(dbRow["x"]), Convert.ToInt32(dbRow["y"])); i++; } Statuses = new Hashtable(); aiHandler = new Thread(new ThreadStart(AI)); aiHandler.Priority = ThreadPriority.BelowNormal; aiHandler.Start(); } internal void Kill() { try { aiHandler.Abort(); } catch { } aiHandler = null; Room = null; Statuses = null; Coords = null; Sayings = null; Shouts = null; chatTriggers = null; Customer = null; customerTrigger = null; } #endregion #region Bot properties internal string detailsString { get { return Encoding.encodeVL64(roomUID) + Name + Convert.ToChar(2) + Mission + " " + Convert.ToChar(2) + Figure + Convert.ToChar(2) + Encoding.encodeVL64(roomUID) + Encoding.encodeVL64(X) + Encoding.encodeVL64(Y) + H + Convert.ToChar(2) + "IK"; } } internal string statusString { get { string s = Encoding.encodeVL64(roomUID) + Encoding.encodeVL64(X) + Encoding.encodeVL64(Y) + H.ToString().Replace(",", ".") + Convert.ToChar(2) + Encoding.encodeVL64(Z1) + Encoding.encodeVL64(Z2) + "/"; foreach (string Key in Statuses.Keys) { s += Key; string Value = (string)Statuses[Key]; if (Value != "") s += " " + Value; s += "/"; } return s; } } #endregion #region Actions internal void Interact(virtualRoomUser roomUser, string Message) { Message = Message.ToLower(); string[] messageWords = Message.Split(' '); if (chatTriggers != null) { foreach (chatTrigger Trigger in chatTriggers) { for (int i = 0; i < messageWords.Length; i++) { if (Trigger.containsWord(messageWords[i])) { if (Trigger.serveItem != "") // Serve an item, walk up to the customer and hand over the beverage { if (Customer != null) // The bot is currently serving a different room user, ignore this trigger return; Coord Closest = getClosestWalkCoordTo(roomUser.X, roomUser.Y); if (Closest.X == -1) // Can't serve this user (no square close enough) return; Room.sendSaying(this, Trigger.Reply); goalX = Closest.X; goalY = Closest.Y; this.Customer = roomUser; this.customerTrigger = Trigger; roomUser.User.statusID = "Gb"; roomUser.User.statusCount = int.Parse(Trigger.serveItem); Room.sendData(roomUser.User.statusID + Encoding.encodeVL64(roomUser.roomUID) + Encoding.encodeVL64(roomUser.User.statusCount)); } else { this.Z1 = Rotation.Calculate(X, Y, roomUser.X, roomUser.Y); this.Z2 = this.Z1; Room.sendSaying(this, Trigger.Reply); } return; } } } } } internal void checkOrders() { if (Customer != null) { { goalX = -1; Rotate(Customer.X, Customer.Y); removeStatus("carryd"); Room.sendSaying(this, customerTrigger.serveReply); if (Customer.statusManager.containsStatus("sit") == false) { Customer.Z1 = Rotation.Calculate(Customer.X, Customer.Y, X, Y); Customer.Z2 = Customer.Z1; } Customer.statusManager.carryItem(int.Parse(customerTrigger.serveItem)); } { Customer = null; customerTrigger = null; } } } internal void Rotate(int toX, int toY) { Rotate(Rotation.Calculate(X, Y, toX, toY)); } internal void Rotate(byte R) { if (R != Z1 && Statuses.ContainsKey("sit") == false) { Z1 = R; Z2 = R; Refresh(); } } internal Coord getClosestWalkCoordTo(int X, int Y) { int minDistance = 6; Coord Closest = new Coord(-1, 0); foreach (Coord Coord in Coords) { int curDistance = Math.Abs(X - Coord.X) + Math.Abs(Y - Coord.Y); if (curDistance < minDistance) { minDistance = curDistance; Closest = Coord; } } return Closest; } #endregion #region Status management internal void addStatus(string Key, string Value) { if (Statuses.ContainsKey(Key)) Statuses.Remove(Key); Statuses.Add(Key, Value); } internal void removeStatus(string Key) { try { if (Statuses.ContainsKey(Key)) Statuses.Remove(Key); } catch { } } internal bool containsStatus(string Key) { return Statuses.ContainsKey(Key); } internal void Refresh() { Room.Refresh(this); } internal void handleStatus(string Key, string Value, int Length) { if (Statuses.ContainsKey(Key)) Statuses.Remove(Key); new statusVoid(HANDLESTATUS).BeginInvoke(Key, Value, Length, null, null); } private void HANDLESTATUS(string Key, string Value, int Length) { try { Statuses.Add(Key, Value); Refresh(); Thread.Sleep(Length); Statuses.Remove(Key); Refresh(); } catch { } } #endregion #region Misc private void AI() { int lastMessageID = -1; Random RND = new Random(roomUID * DateTime.Now.Millisecond); { while (true) { if (Customer != null) // Currently serving a different user continue; int ACTION = RND.Next(0, 6); switch (ACTION) { case 1: // Move { Coord Next = new Coord(); if (freeRoam) { int[] Borders = Room.getMapBorders(); Next = new Coord(RND.Next(0, Borders[0]), RND.Next(0, Borders[1])); } else Next = Coords[RND.Next(0, Coords.Length)]; if (Next.X == X && Next.Y == Y) // Coord didn't changed { Z1 = (byte)RND.Next(0, 10); Z2 = Z1; Refresh(); } else { goalX = Next.X; goalY = Next.Y; } break; } case 2: // Rotate { byte R = (byte)RND.Next(0, 10); while (R == Z2) R = (byte)RND.Next(0, 10); Rotate(R); break; } case 3: // Shout { if (Shouts.Length > 0) { int messageID = RND.Next(0, Shouts.Length); if (Shouts.Length > 1) // More than one shout assigned { while (messageID == lastMessageID) // Avoid shouting the same sentence two times in a row messageID = RND.Next(0, Shouts.Length); lastMessageID = messageID; } Room.sendShout(this, Shouts[messageID]); } break; } case 4: // Say { if (Sayings.Length > 0) { int messageID = RND.Next(0, Sayings.Length); if (Sayings.Length > 1) // More than one saying assigned { while (messageID == lastMessageID) // Avoid saying the same sentence two times in a row messageID = RND.Next(0, Sayings.Length); lastMessageID = messageID; } Room.sendSaying(this, Sayings[messageID]); } break; } } Thread.Sleep(3000); } } } #endregion #region Private objects private class chatTrigger { private string[] Words; private string[] Replies; private string[] serveReplies; internal string serveItem; internal chatTrigger(string[] Words, string[] Replies, string[] serveReplies, string serveItem) { this.Words = Words; this.Replies = Replies; this.serveReplies = serveReplies; this.serveItem = serveItem; } internal bool containsWord(string Word) { if (Word.Substring(Word.Length - 1, 1) == "?") Word = Word.Substring(0, Word.Length - 1); for (int i = 0; i < Words.Length; i++) if (Words[i] == Word) return true; return false; } internal string Reply { get { return Replies[new Random(DateTime.Now.Millisecond).Next(0, Replies.Length)]; } } internal string serveReply { get { return serveReplies[new Random(DateTime.Now.Millisecond).Next(0, serveReplies.Length)]; } } } #endregion } }