Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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.Pets
- {
- /// <summary>
- /// Represents a computer controlled virtual user with an artifical intelligence (AI). The bot walks around in virtual rooms on specified coordinates, interacts with other virtual users and serves drinks and food.
- /// </summary>
- internal class virtualPet
- {
- #region Declares
- /// <summary>
- /// The database ID of the pet.
- /// </summary>
- internal int ID;
- /// <summary>
- /// The ID of the bot in the virtual room.
- /// </summary>
- internal int roomUID;
- /// <summary>
- /// The virtual room the bot roams in.
- /// </summary>
- internal virtualRoom Room;
- /// <summary>
- /// The name of the bot.
- /// </summary>
- internal string Name;
- /// <summary>
- /// The name of the bot.
- /// </summary>
- internal string Colour;
- /// <summary>
- /// The bot's figure string.
- /// </summary>
- internal string Figure
- {
- get
- {
- return Type.Substring(3, 1) + " " + Race + " " + Colour;
- }
- set
- {
- Figure = value;
- }
- }
- /// <summary>
- /// The bot's figure string.
- /// </summary>
- internal string Race;
- /// <summary>
- /// The bot's figure string.
- /// </summary>
- internal string Type;
- /// <summary>
- /// The X position of the bot in the virtual room.
- /// </summary>
- internal int X;
- /// <summary>
- /// The Y position of the bot in the virtual room.
- /// </summary>
- internal int Y;
- /// <summary>
- /// The height of the bot in the virtual room.
- /// </summary>
- internal double H;
- /// <summary>
- /// The rotation of the bot's head in the virtual room.
- /// </summary>
- internal byte Z1;
- /// <summary>
- /// The rotation of the bot's body in the virtual room.
- /// </summary>
- internal byte Z2;
- /// <summary>
- /// Used for pathfinding. The X coordinate of the bot's target square in the virtual room.
- /// </summary>
- internal int goalX;
- /// <summary>
- /// Used for pathfinding. The Y coordinate of the bot's target square in the virtual room.
- /// </summary>
- internal int goalY;
- private delegate void statusVoid(string Key, string Value, int Length);
- /// <summary>
- /// Handles the random determining of actions.
- /// </summary>
- private Thread aiHandler;
- /// <summary>
- /// Contains the texts that the bot can 'say' on random.
- /// </summary>
- private string[] Sayings;
- /// <summary>
- /// Contains the texts that the bot can 'shout' on random.
- /// </summary>
- private string[] Shouts;
- /// <summary>
- /// Contains the coordinate's where the bot can walk to. Ignored if freeroam is enabled.
- /// </summary>
- private Coord[] Coords;
- /// <summary>
- /// Contains the chat triggers where the bot reacts on.
- /// </summary>
- private chatTrigger[] chatTriggers;
- #endregion
- #region Constructors/destructors
- /// <summary>
- /// Contains the bot's animation statuses.
- /// </summary>
- private Hashtable Statuses;
- /// <summary>
- /// Initializes a new virtualBot object, loading the walk squares, chat texts etc.
- /// </summary>
- /// <param name="botID">The database ID of the bot.</param>
- /// <param name="roomUID">The ID that identifies this bot in room.</param>
- /// <param name="Room">The virtualRoom object where the bot is in.</param>
- internal virtualPet(int petID, int roomUID, virtualRoom Room, int mX, int mY)
- {
- this.roomUID = roomUID;
- this.Room = Room;
- this.ID = petID;
- DataRow dRow;
- using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient())
- {
- dRow = dbClient.getRow("SELECT ownerid,name,type,colour,race,x,y,z FROM pets WHERE id = '" + petID + "'");
- dbClient.runQuery("UPDATE pets SET roomid = '" + Room.roomID + "' WHERE id = '" + ID + "'");
- }
- this.Name = Convert.ToString(dRow["name"]);
- this.Type = Convert.ToString(dRow["type"]);
- this.Race = Convert.ToString(dRow["race"]);
- this.Colour = Convert.ToString(dRow["colour"]);
- if (mX == 0 && mY == 0)
- {
- this.X = Convert.ToInt32(dRow["x"]);
- this.Y = Convert.ToInt32(dRow["y"]);
- this.Z1 = Convert.ToByte(dRow["z"]);
- }
- else
- {
- this.X = mX;
- this.Y = mY;
- this.Z1 = 1;
- }
- this.Z2 = Z1;
- this.goalX = -1;
- DataColumn dCol;
- using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient())
- {
- dCol = dbClient.getColumn("SELECT text FROM pets_texts WHERE animal = '" + Type + "' AND type = 'say'");
- }
- this.Sayings = (string[])dataHandling.dColToArray(dCol);
- using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient())
- {
- dCol = dbClient.getColumn("SELECT text FROM pets_texts WHERE animal = '" + Type + "' AND type = 'shout'");
- }
- this.Shouts = (string[])dataHandling.dColToArray(dCol);
- DataTable dTable;
- //using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient())
- //{
- // dTable = dbClient.getTable("SELECT words, replies, action FROM pets_texts_triggers");
- //}
- //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 = '" + petID + "'");
- }
- 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();
- }
- /// <summary>
- /// Safely shuts this virtualBot down and tidies up all resources.
- /// </summary>
- internal void Kill()
- {
- using (DatabaseClient dbClient = (Eucalypt.dbManager.GetClient()))
- {
- dbClient.runQuery("UPDATE pets SET x = '" + X + "', y = '" + Y + "', z = '" + Z1 + "' WHERE id = '" + ID + "'");
- }
- try { aiHandler.Abort(); }
- catch { }
- aiHandler = null;
- Room = null;
- Statuses = null;
- Coords = null;
- Sayings = null;
- Shouts = null;
- chatTriggers = null;
- }
- #endregion
- #region Bot properties
- /// <summary>
- /// The details string of the bot, containing room identifier ID, name, motto, figure etc.
- /// </summary>
- internal string detailsString
- {
- get
- {
- string s = "i:" + roomUID + Convert.ToChar(13) + "n:" + roomUID + Convert.ToChar(4) + Name + Convert.ToChar(13) + "f:" + Figure + Convert.ToChar(13) + "l:" + X + " " + Y + " " + H + Convert.ToChar(13);
- s += "c:" + Convert.ToChar(13);
- return s;
- }
- }
- /// <summary>
- /// The status string of the bot, containing positions, movements, statuses (animations) etc.
- /// </summary>
- internal string statusString
- {
- get
- {
- string s = roomUID + " " + X + "," + Y + "," + H.ToString().Replace(",", ".") + "," + Z1 + "," + Z2 + "/";
- foreach (string Key in Statuses.Keys)
- {
- s += Key;
- string Value = (string)Statuses[Key];
- if (Value != "")
- s += " " + Value;
- s += "/";
- }
- return s;
- }
- }
- #endregion
- #region Actions
- /// <summary>
- /// Invoked by a virtualRoomUser. There is checked if this bot reacts on a certain chat message, if so, then replies/orders etc are processed.
- /// </summary>
- /// <param name="roomUser">The virtualRoomUser object that interacts with this bot by saying a message.</param>
- /// <param name="Message">The message that the virtualRoomUser said to this bot.</param>
- internal void Interact(virtualRoomUser roomUser, string Message)
- {
- Message = Message.ToLower();
- string[] messageWords = Message.Split(' ');
- if (/*chatTriggers != null && */messageWords[0] == this.Name)
- {
- //foreach (chatTrigger Trigger in chatTriggers)
- //{
- // for (int i = 0; i < messageWords.Length; i++)
- // {
- // if (Trigger.containsWord(messageWords[i]))
- // {
- // this.Z1 = Rotation.Calculate(X, Y, roomUser.X, roomUser.Y);
- // this.Z2 = this.Z1;
- // Room.sendSaying(this, Trigger.Reply);
- // return; // One trigger per time
- // }
- // }
- //}
- switch (messageWords[1])
- {
- case "spill død":
- case "død":
- case "play dead":
- case "dã¸d":
- {
- Statuses.Remove("sit");
- Statuses.Remove("jmp");
- addStatus("ded", "");
- break;
- }
- case "jump":
- case "hopp":
- {
- Statuses.Remove("sit");
- Statuses.Remove("ded");
- addStatus("jmp", "");
- break;
- }
- case "kom":
- {
- Coord Next = new Coord();
- int[] Borders = Room.getMapBorders();
- Next = new Coord(roomUser.X - 1, roomUser.Y);
- goalX = Next.X;
- goalY = Next.Y;
- break;
- }
- }
- }
- }
- /// <summary>
- /// Rotates the bot to a certain X and Y coordinate and refreshes it in the room. If the bot is sitting, then rotating will be ignored.
- /// </summary>
- /// <param name="toX">The X coordinate to face.</param>
- /// <param name="toY">The Y coordinate to face.</param>
- internal void Rotate(int toX, int toY)
- {
- Rotate(Rotation.Calculate(X, Y, toX, toY));
- }
- /// <summary>
- /// Sets a new rotation for the bot and refreshes it in the room. If the bot is sitting, then rotating will be ignored.
- /// </summary>
- /// <param name="R">The new rotation to use.</param>
- internal void Rotate(byte R)
- {
- if (R != Z1 && Statuses.ContainsKey("sit") == false)
- {
- Z1 = R;
- Z2 = R;
- Refresh();
- }
- }
- /// <summary>
- /// Returns a Coord object with the X and Y of the walkcoord that is as closest to the given position.
- /// </summary>
- /// <param name="X">The X position.</param>
- /// <param name="Y">The Y position.</param>
- 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
- /// <summary>
- /// Adds a status key and a value to the bot's statuses. If the status is already inside, then the previous one will be removed.
- /// </summary>
- /// <param name="Key">The key of the status.</param>
- /// <param name="Value">The value of the status.</param>
- internal void addStatus(string Key, string Value)
- {
- if (Statuses.ContainsKey(Key))
- Statuses.Remove(Key);
- Statuses.Add(Key, Value);
- }
- /// <summary>
- /// Removes a certain status from the bot's statuses.
- /// </summary>
- /// <param name="Key">The key of the status to remove.</param>
- internal void removeStatus(string Key)
- {
- try
- {
- if (Statuses.ContainsKey(Key))
- Statuses.Remove(Key);
- }
- catch { }
- }
- /// <summary>
- /// Returns a bool that indicates if the bot has a certain status at the moment.
- /// </summary>
- /// <param name="Key">The key of the status to check.</param>
- internal bool containsStatus(string Key)
- {
- return Statuses.ContainsKey(Key);
- }
- /// <summary>
- /// Refreshes the status of the bot in the virtual room.
- /// </summary>
- internal void Refresh()
- {
- Room.Refresh(this);
- }
- /// <summary>
- /// Adds a status to the bot, keeps it for a specified amount of time [in ms] and removes the status. Refreshes at add and remove.
- /// </summary>
- /// <param name="Key">The key of the status, eg, 'sit'.</param>
- /// <param name="Value">The value of the status, eg, '1.0'.</param>
- /// <param name="Length">The amount of milliseconsd to keep the status before removing it again.</param>
- 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
- /// <summary>
- /// Ran on a thread. Handles the bot's artifical intelligence, by interacting with users and using random values etc.
- /// </summary>
- private void AI()
- {
- int lastMessageID = -1;
- Random RND = new Random(roomUID * DateTime.Now.Millisecond);
- //try
- {
- while (true)
- {
- int ACTION = RND.Next(0, 6);
- switch (ACTION)
- {
- case 1: // Move
- {
- Statuses.Remove("jmp");
- Statuses.Remove("sit");
- Statuses.Remove("ded");
- Coord Next = new Coord();
- int[] Borders = Room.getMapBorders();
- Next = new Coord(RND.Next(0, Borders[0]), RND.Next(0, Borders[1]));
- 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;
- }
- case 5: // Status
- {
- /* if (RND.Next(0, 2) == 0)
- {
- Statuses.Remove("sit");
- Statuses.Remove("ded");
- handleStatus("jmp", "", 4000);
- }
- else
- {
- Statuses.Remove("sit");
- Statuses.Remove("jmp");
- addStatus("ded", "");
- Refresh();
- }*/
- break;
- }
- }
- Thread.Sleep(3000);
- Out.WriteTrace("Bot AI loop");
- }
- }
- //catch { aiHandler.Abort(); }
- }
- #endregion
- #region Private objects
- /// <summary>
- /// Represents a trigger that can be invoked by a chat message. Results in a reply and/or an order confirmation.
- /// </summary>
- private class chatTrigger
- {
- /// <summary>
- /// A System.String array with words that invoke this trigger.
- /// </summary>
- private string[] Words;
- /// <summary>
- /// A System.String array with replies that are used when this trigger is invoked.
- /// </summary>
- private string[] Replies;
- internal chatTrigger(string[] Words, string[] Replies)
- {
- this.Words = Words;
- this.Replies = Replies;
- }
- /// <summary>
- /// Returns a boolean that indicates if this trigger replies on a certain word.
- /// </summary>
- /// <param name="Word">The word to check.</param>
- 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;
- }
- /// <summary>
- /// Returns a random reply from the replies array.
- /// </summary>
- internal string Reply
- {
- get
- {
- return Replies[new Random(DateTime.Now.Millisecond).Next(0, Replies.Length)];
- }
- }
- }
- #endregion
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement