using System; using System.Data; using System.Text; using System.Threading; using System.Collections; using System.Collections.Generic; using Holo.Managers; using Holo.Virtual.Users; using Holo.Virtual.Rooms.Bots; using Holo.Virtual.Rooms.FantasyBots; using Holo.Virtual.Rooms.Pets; using Holo.Virtual.Rooms.Items; using Microsoft.VisualBasic; using Ion.Storage; using Holo.Source.Managers; namespace Holo.Virtual.Rooms { public class virtualRoom { #region Declares internal int roomID; internal bool DiveDoorOpen = true; internal string emitter; internal bool isPublicroom; internal FloorItemManager floorItemManager; internal WallItemManager wallItemManager; private bool CycleThread = true; private bool StatusThingy = true; private string _publicroomItems; private string _Heightmap; internal bool hasSwimmingPool; private Dictionary _magicTiles = new Dictionary(); private squareState[,] sqSTATE; private byte[,] sqITEMROT; public byte[,] sqFLOORHEIGHT; private double[,] sqITEMHEIGHT; public bool[,] sqUNIT; private furnitureStack[,] sqSTACK; public enum squareState { Open = 0, Blocked = 1, Seat = 2, Bed = 3, Rug = 4, Roller = 5, Food = 6 }; squareTrigger[,] sqTRIGGER; internal Hashtable _Users; private Hashtable _Bots; internal Hashtable _Pets; internal Hashtable _FBots; private HashSet _activeGroups; private Thread _statusHandler; private StringBuilder _statusUpdates; internal int doorX; internal int doorY; private byte doorZ; private int doorH; internal bool HasMoodLight = false; private Thread specialCastHandler; private Thread Pinger; private int RoomVote; internal virtualRoomUser Diver; internal int DiverID; #endregion internal void sendDataToRights(string Data) { try { foreach (virtualRoomUser roomUser in _Users.Values) if (roomUser.User._hasRights || roomUser.User._isOwner || rankManager.containsRight(roomUser.User, "fuse_pick_up_any_furni", roomUser.userID)) roomUser.User.sendData(Data); } catch { } } #region Constructors/Destructors public virtualRoom(int roomID, bool isPublicroom) { this.roomID = roomID; this.isPublicroom = isPublicroom; string roomModel; DataRow dRow; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { roomModel = dbClient.getString("SELECT model FROM rooms WHERE id = '" + roomID + "' LIMIT 1"); } doorX = modeldataManager.door_x(roomModel); doorY = modeldataManager.door_y(roomModel); doorH = modeldataManager.door_h(roomModel); doorZ = modeldataManager.door_z(roomModel); _Heightmap = modeldataManager.Heightmap(roomModel); string[] tmpHeightmap = _Heightmap.Split("\r".ToCharArray()); int colX = tmpHeightmap[0].Length; int colY = tmpHeightmap.Length - 1; sqSTATE = new squareState[colX, colY]; sqFLOORHEIGHT = new byte[colX, colY]; sqITEMROT = new byte[colX, colY]; sqITEMHEIGHT = new double[colX, colY]; sqUNIT = new bool[colX, colY]; sqSTACK = new furnitureStack[colX, colY]; sqTRIGGER = new squareTrigger[colX, colY]; for (int y = 0; y < colY; y++) { for (int x = 0; x < colX; x++) { try { string _SQ = tmpHeightmap[y].Substring(x, 1).Trim().ToLower(); if (_SQ == "x") sqSTATE[x, y] = squareState.Blocked; else { sqSTATE[x, y] = squareState.Open; try { sqFLOORHEIGHT[x, y] = byte.Parse(_SQ); } catch { } } } catch { } } } if (isPublicroom) { string[] Items = (modeldataManager.publicroom_items(roomModel).Split("\r".ToCharArray())); _publicroomItems += Encoding.encodeVL64(Items.Length); for (int i = 0; i < Items.Length; i++) { string[] itemData = Items[i].Split(' '); int X = int.Parse(itemData[2]); int Y = int.Parse(itemData[3]); squareState sType = (squareState)int.Parse(itemData[6]); sqSTATE[X, Y] = sType; if (sType == squareState.Seat) { sqITEMROT[X, Y] = byte.Parse(itemData[5]); sqITEMHEIGHT[X, Y] = 1.0; } _publicroomItems += Encoding.encodeVL64(0) + itemData[0] + Convert.ToChar(2) + itemData[1] + Convert.ToChar(2) + Encoding.encodeVL64(int.Parse(itemData[2])) + Encoding.encodeVL64(int.Parse(itemData[3])) + Encoding.encodeVL64(int.Parse(itemData[4])) + Encoding.encodeVL64(int.Parse(itemData[5])); } DataTable dTable; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dTable = dbClient.getTable("SELECT object,x,y,goalx,goaly,stepx,stepy,roomid,state FROM room_modeldata_triggers WHERE model = '" + roomModel + "'"); } foreach (DataRow dbRow in dTable.Rows) { sqTRIGGER[Convert.ToInt32(dbRow["x"]), Convert.ToInt32(dbRow["y"])] = new squareTrigger(Convert.ToString(dbRow["object"]), Convert.ToInt32(dbRow["goalx"]), Convert.ToInt32(dbRow["goaly"]), Convert.ToInt32(dbRow["stepx"]), Convert.ToInt32(dbRow["stepy"]), (Convert.ToInt32(dbRow["state"]) == 1), Convert.ToInt32(dbRow["roomid"])); } bool result = false; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { result = dbClient.findsResult("SELECT specialcast_interval FROM room_modeldata WHERE model = '" + roomModel + "' AND specialcast_interval > 0"); } if (result) { specialCastHandler = new Thread(new ParameterizedThreadStart(handleSpecialCasts)); specialCastHandler.Priority = ThreadPriority.Lowest; specialCastHandler.Start(roomModel); } using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { if (modeldataManager.swimmingpool(roomModel) == 1) hasSwimmingPool = true; else hasSwimmingPool = false; } } else { floorItemManager = new FloorItemManager(this); wallItemManager = new WallItemManager(this); DataTable dTable; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dTable = dbClient.getTable("SELECT furniture.id, furniture.tid, furniture.x, furniture.y, furniture.z, furniture.h, furniture.var, furniture.wallpos, furniture.teleportid FROM rooms, furniture WHERE furniture.roomid = rooms.id AND rooms.id = '" + roomID + "' ORDER BY rooms.id ASC"); } foreach (DataRow dbRow in dTable.Rows) if (Convert.ToString(dbRow["wallpos"]) == "") // Flooritem floorItemManager.addItem(Convert.ToInt32(dbRow["id"]), Convert.ToInt32(dbRow["tid"]), Convert.ToInt32(dbRow["x"]), Convert.ToInt32(dbRow["y"]), Convert.ToInt32(dbRow["z"]), Convert.ToDouble(dbRow["h"]), Convert.ToString(dbRow["var"]), Convert.ToInt32(dbRow["teleportid"])); else wallItemManager.addItem(Convert.ToInt32(dbRow["id"]), Convert.ToInt32(dbRow["tid"]), Convert.ToString(dbRow["wallpos"]), Convert.ToString(dbRow["var"]), false); } _Users = new Hashtable(); _Bots = new Hashtable(); _Pets = new Hashtable(); _FBots = new Hashtable(); ; loadBots(); loadPets(); _activeGroups = new HashSet(); _statusUpdates = new StringBuilder(); _statusHandler = new Thread(new ThreadStart(cycleStatuses)); if (!_statusHandler.IsAlive) _statusHandler.Start(); sqSTATE[doorX, doorY] = squareState.Open; Pinger = new Thread(new ThreadStart(UserChecker)); Pinger.Start(); } internal void AddVote(bool Vote, int userID) { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { if (Vote) //+1 { if (dbClient.findsResult("SELECT userid FROM room_votes WHERE userid = '" + userID + "' AND roomid = '" + roomID + "'") == false) { dbClient.runQuery("INSERT INTO room_votes (userid,roomid,vote) VALUES ('" + userID + "','" + roomID + "','1')"); RoomVote++; } } else //-1 { if (dbClient.findsResult("SELECT userid FROM room_votes WHERE userid = '" + userID + "' AND roomid = '" + roomID + "'") == false) { dbClient.runQuery("INSERT INTO room_votes (userid,roomid,vote) VALUES ('" + userID + "','" + roomID + "','-1')"); RoomVote--; } } dbClient.runQuery("UPDATE rooms SET votes = '" + RoomVote + "' WHERE id = '" + roomID + "'"); } } internal void RemoveVote() { RoomVote--; } internal int VoteCount() { return RoomVote; } ~virtualRoom() { roomManager.removeRoom(roomID); GC.Collect(); } #endregion internal int checkEmotion(virtualRoomUser sourceUser, string Message) { string[] GestureList = { "sml", "agr", "sad", "srp" }; string[] Gestures_sml = { ":)", ":D" }; string[] Gestures_agr = { ">:(", ":@", ":/" }; string[] Gestures_sad = { ":(", ":'(" }; string[] Gestures_srp = { ":o", ":O", ":0" }; string[][] Gestures = { Gestures_sml, Gestures_agr, Gestures_sad, Gestures_srp }; for (int i = 0; i < Gestures.Length; i++) { string[] currentGestures = Gestures[i]; string[] splitMessage = Message.Split(currentGestures, StringSplitOptions.None); if (splitMessage.Length > 1) { string Gesture = GestureList[i]; sourceUser.statusManager.handleStatus("gest", Gesture, 5000); } } return 0; } #region Virtual content properties internal string Heightmap { get { return _Heightmap; } } internal string Flooritems { get { if (isPublicroom) return "H"; return floorItemManager.Items; } } internal string Wallitems { get { if (isPublicroom) return ""; return wallItemManager.Items; } } internal string PublicroomItems { get { return _publicroomItems; } } #endregion #region Virtual user management #region User and bot adding/removing internal void addUser(virtualUser User) { int newX_Teleporter = 0; int newY_Teleporter = 0; if (User._teleporterID == 0 && (User._ROOMACCESS_PRIMARY_OK == false || User._ROOMACCESS_SECONDARY_OK == false)) return; User.statusManager = new virtualRoomUserStatusManager(User.userID, this.roomID); User.roomUser = new virtualRoomUser(User.userID, roomID, getFreeRoomIdentifier(), User, User.statusManager); if (User._teleporterID == 0) { if (User.isInvisible == false) { User.roomUser.X = this.doorX; User.roomUser.Y = this.doorY; User.roomUser.Z1 = this.doorZ; User.roomUser.Z2 = this.doorZ; User.roomUser.H = this.doorH; } } else { floorItem Teleporter = floorItemManager.getItem(User._teleporterID); User.roomUser.X = Teleporter.X; User.roomUser.Y = Teleporter.Y; User.roomUser.H = Teleporter.H; User.roomUser.Z1 = Teleporter.Z; User.roomUser.Z2 = Teleporter.Z; newX_Teleporter = Teleporter.X; newY_Teleporter = Teleporter.Y; if (Teleporter.Z == 4) { newY_Teleporter = Teleporter.Y + 1; } if (Teleporter.Z == 2) { newX_Teleporter = Teleporter.X + 1; } } User.roomUser.goalX = -1; _Users.Add(User.roomUser.roomUID, User.roomUser); if (User._teleporterID > 0) { sendData("AX" + User._teleporterID + Convert.ToChar(2) + 2 + Convert.ToChar(2), 250); sendData("AX" + User._teleporterID + Convert.ToChar(2) + 1 + Convert.ToChar(2), 450); sendData("AX" + User._teleporterID + Convert.ToChar(2) + 0 + Convert.ToChar(2), 800); } if (this.isPublicroom == false) { if (User._hasRights) if (User._isOwner == false) { User.statusManager.addStatus("flatctrl", "onlyfurniture"); } if (User._isOwner) User.statusManager.addStatus("flatctrl", "useradmin"); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { User.roomUser.hasVoted = dbClient.findsResult("SELECT userid FROM room_votes WHERE userid = '" + User.userID + "' AND roomid = '" + this.roomID + "'"); } } else { if (this.hasSwimmingPool) // This room has a swimming pool { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { User.roomUser.swimOutfit = dbClient.getString("SELECT figure_swim FROM users WHERE id = '" + User.userID + "'"); } } if (this.DiveDoorOpen == false) sendSpecialCast("door", "close"); } if(User.isInvisible == false) sendData(@"@\I" + User.roomUser.detailsString); if (User._groupID > 0 && _activeGroups.Contains(User._groupID) == false) { string groupBadge; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { groupBadge = dbClient.getString("SELECT badge FROM groups_details WHERE id = '" + User._groupID + "'"); } sendData("Du" + "I" + Encoding.encodeVL64(User._groupID) + groupBadge + Convert.ToChar(2)); _activeGroups.Add(User._groupID); } if (newX_Teleporter > 0 && newY_Teleporter > 0) moveUser(User.roomUser, newX_Teleporter, newY_Teleporter, true); roomManager.updateRoomVisitorCount(this.roomID, this._Users.Count); } internal void refreshActions(int roomUID) { virtualRoomUser roomUser = (virtualRoomUser)_Users[roomUID]; foreach (virtualRoomUser rUser in _Users.Values) { if (rUser.roomUID != roomUID) { roomUser.User.sendData(rUser.User.statusID + Encoding.encodeVL64(rUser.roomUID) + Encoding.encodeVL64(rUser.User.statusCount)); } } } internal void removePet(int roomUID) { if (_Pets.Contains(roomUID) == false) return; virtualPet roomPet = (virtualPet)_Pets[roomUID]; roomPet.Kill(); _Pets.Remove(roomUID); if (_Pets.Count == 0) { _Pets.Clear(); } } internal void removeUser(int roomUID, bool sendKick, string moderatorMessage) { if (_Users.Contains(roomUID) == false) return; virtualRoomUser roomUser = (virtualRoomUser)_Users[roomUID]; if (sendKick) { roomUser.User.sendData("@R"); if (moderatorMessage != "") roomUser.User.sendAlert(moderatorMessage); } sqUNIT[roomUser.X, roomUser.Y] = false; roomUser.User.statusManager.Clear(); roomUser.User.statusManager = null; roomUser.User._roomID = 0; roomUser.User._inPublicroom = false; roomUser.User._ROOMACCESS_PRIMARY_OK = false; roomUser.User._ROOMACCESS_SECONDARY_OK = false; roomUser.User._isOwner = false; roomUser.User._hasRights = false; roomUser.User.Room = null; roomUser.User.roomUser = null; if (roomUser.User._tradePartnerRoomUID != -1) roomUser.User.abortTrade(true); _Users.Remove(roomUID); if (_Users.Count > 0) // Still users in room { if (roomUser.User._groupID > 0) { bool removeBadge = true; try { foreach (virtualRoomUser rUser in _Users.Values) { if (rUser.roomUID != roomUser.roomUID && rUser.User._groupID == roomUser.User._groupID) { removeBadge = false; break; } } } catch { } if (removeBadge) _activeGroups.Remove(roomUser.User._groupID); } sendData("@]" + roomUID + Convert.ToChar(2)); roomManager.updateRoomVisitorCount(this.roomID, _Users.Count); } else { _Users.Clear(); _Bots.Clear(); _FBots.Clear(); _Pets.Clear(); _statusUpdates = null; if (isPublicroom == false) { floorItemManager.Clear(); wallItemManager.Clear(); } else { StatusThingy = false; } roomManager.removeRoom(this.roomID); CycleThread = false; } } internal bool containsUser(int roomUID) { return _Users.ContainsKey(roomUID); } internal ICollection Users { get { return _Users.Values; } } #endregion #region Properties and providers private int getFreeRoomIdentifier() { int i = 0; while (true) { if (_Bots.ContainsKey(i) == false && _Users.ContainsKey(i) == false && _Pets.ContainsKey(i) == false && _FBots.ContainsKey(i) == false) return i; else i++; } } private int getRandomRoomIdentifier() { if (_Users.Count > 0) { while (true) { int rndID = new Random(DateTime.Now.Millisecond).Next(0, _Users.Count); if (_Bots.ContainsKey(rndID) || _Users.ContainsKey(rndID) || _Pets.ContainsKey(rndID) || _FBots.ContainsKey(rndID)) return rndID; } } else return -1; } internal virtualUser getUser(int roomUID) { return ((virtualRoomUser)_Users[roomUID]).User; } internal virtualRoomUser getRoomUser(int roomUID) { return ((virtualRoomUser)_Users[roomUID]); } internal string dynamicUnits { get { int inCount = 0; StringBuilder userList = new StringBuilder(); foreach (virtualPet roomPet in _Pets.Values) { inCount++; userList.Append(roomPet.detailsString); } foreach (virtualBot roomBot in _Bots.Values) { inCount++; userList.Append(roomBot.detailsString); } foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { inCount++; userList.Append(roomUser.detailsString); } foreach (virtualFantasyBot roomBot in _FBots.Values) { inCount++; userList.Append(roomBot.detailsString); } return Encoding.encodeVL64(inCount) + userList.ToString(); } } internal string dynamicStatuses { get { int cntUsers = 0; StringBuilder Statuses = new StringBuilder(); foreach (virtualPet roomPet in _Pets.Values) { cntUsers++; Statuses.Append(roomPet.statusString + Convert.ToChar(2)); } foreach (virtualBot roomBot in _Bots.Values) { cntUsers++; Statuses.Append(roomBot.statusString + Convert.ToChar(2)); } foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { cntUsers++; Statuses.Append(roomUser.statusString + Convert.ToChar(2)); } foreach (virtualFantasyBot roomBot in _FBots.Values) { cntUsers++; Statuses.Append(roomBot.statusString + Convert.ToChar(2)); } return Encoding.encodeVL64(cntUsers) + Statuses.ToString(); } } internal string Userlist { get { StringBuilder listBuilder = new StringBuilder(Encoding.encodeVL64(this.roomID) + Encoding.encodeVL64(_Users.Count)); foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) listBuilder.Append(roomUser.User._Username + Convert.ToChar(2)); return listBuilder.ToString(); } } internal string Groups { get { StringBuilder listBuilder = new StringBuilder(Encoding.encodeVL64(_activeGroups.Count)); StringBuilder sb = new StringBuilder(); foreach (int groupID in _activeGroups) sb.Append(" OR id = '" + groupID + "'"); sb.Append(" OR"); DataTable dTable; int countGroups = 0; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.AddParamWithValue("tablename", sb.ToString().Substring(3)); dTable = dbClient.getTable("SELECT id,badge FROM groups_details WHERE @tablename 'a' = 'b'"); } foreach (DataRow dRow in dTable.Rows) { countGroups++; listBuilder.Append(Encoding.encodeVL64(Convert.ToInt32(dRow["id"])) + Convert.ToString(dRow["badge"]) + Convert.ToChar(2)); } return Encoding.encodeVL64(countGroups) + listBuilder.ToString(); } } #endregion #region User data distribution internal void sendData(string Data) { try { foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) roomUser.User.sendData(Data); } catch { } } internal void sendData(string Data, int msSleep) { new sendDataSleep(SENDDATASLEEP).BeginInvoke(Data, msSleep, null, null); } private delegate void sendDataSleep(string Data, int msSleep); private void SENDDATASLEEP(string Data, int msSleep) { Thread.Sleep(msSleep); foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) roomUser.User.sendData(Data); } internal void sendData(int userID, string Data) { foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (roomUser.userID == userID) { roomUser.User.sendData(Data); return; } } } internal void sendData(string Username, string Data) { foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (roomUser.User._Username == Username) { roomUser.User.sendData(Data); return; } } } internal void sendSpecialCast(string Emitter, string Cast) { sendData("AG" + Emitter + Convert.ToChar(32) + Cast); } internal void sendNewVoteAmount(int voteAmount) { string Data = "EY" + Encoding.encodeVL64(voteAmount); lock (_Users) { foreach (virtualRoomUser roomUser in _Users.Values) { if (roomUser.hasVoted) roomUser.User.sendData(Data); } } } #endregion private void UserChecker() { while (true) { foreach (virtualRoomUser EndUsera in ((Hashtable)_Users.Clone()).Values) { virtualUser EndUser = EndUsera.User; if (EndUser.Room == null) { try { removeUser(EndUser.roomUser.roomUID, true, ""); } catch { } } } Thread.Sleep(5000); } } private void InitMagicTiles() { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { DataTable dTable = dbClient.getTable("SELECT toid,fromx,fromy,tox,toy,toh,toz,tostatus,tomode FROM room_magicTiles WHERE fromid = '" + roomID + "'"); foreach (DataRow dbRow in dTable.Rows) { magicTile mTile = new magicTile(Convert.ToString(dbRow["tomode"]), Convert.ToString(dbRow["tostatus"]), Convert.ToInt32(dbRow["toid"]), Convert.ToInt32(dbRow["tox"]), Convert.ToInt32(dbRow["toy"]), Convert.ToByte(dbRow["toz"]), Convert.ToInt32(dbRow["toh"])); _magicTiles.Add(new Pathfinding.Coord(Convert.ToInt32(dbRow["fromx"]), Convert.ToInt32(dbRow["fromy"])), mTile); } dTable = dbClient.getTable("SELECT fromid,fromx,fromy,fromh,fromz,tox,toy,fromstatus,frommode FROM room_magicTiles WHERE toid = '" + roomID + "'"); Pathfinding.Coord mCord; foreach (DataRow dbRow in dTable.Rows) { mCord = new Pathfinding.Coord(Convert.ToInt32(dbRow["tox"]), Convert.ToInt32(dbRow["toy"])); if (_magicTiles.ContainsKey(mCord)) continue; magicTile mTile = new magicTile(Convert.ToString(dbRow["frommode"]), Convert.ToString(dbRow["fromstatus"]), Convert.ToInt32(dbRow["fromid"]), Convert.ToInt32(dbRow["fromx"]), Convert.ToInt32(dbRow["fromy"]), Convert.ToByte(dbRow["fromz"]), Convert.ToInt32(dbRow["fromh"])); _magicTiles.Add(mCord, mTile); } } } internal bool walkthrough(int roomID) { DataRow dRow; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dRow = dbClient.getRow("SELECT allow_walkthrough FROM rooms WHERE id = '" + roomID + "' LIMIT 1"); } if (dRow["allow_walkthrough"] == "1" || Convert.ToInt32(dRow["allow_walkthrough"]) == 1 || dRow[0] == "1" || Convert.ToInt32(dRow[0]) == 1 || isPublicroom == true) return false; return true; } /* private double getItemHeight(int nextX, int nextY, int roomID) { DataTable dTable; DataTable dTable2; double ItemHeight = 0.00; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dTable = dbClient.getTable("SELECT h FROM furniture WHERE x = '" + nextX + "' AND y = '" + nextY + "' AND roomid = '" + roomID + "' ORDER BY h DESC LIMIT 1"); /*if (dTable.Rows.Count > 1) { foreach (DataRow dRow in dTable.Rows) { dTable2 = dbClient.getTable("SELECT top FROM catalogue_items WHERE tid = '" + dRow["tid"] + "'"); foreach (DataRow dRow2 in dTable2.Rows) { ItemHeight = ItemHeight + Convert.ToDouble(dRow2["top"]); } } } if (dTable.Rows.Count > 0) { foreach (DataRow dRow in dTable.Rows) ItemHeight = ItemHeight + Convert.ToDouble(dRow["h"]); } } return ItemHeight; } */ private double checkItemHeight(int nextX, int nextY, int roomID) { DataTable dTable; DataTable dTable2; double ItemHeight = 0.00; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dTable = dbClient.getTable("SELECT h FROM furniture WHERE x = '" + nextX + "' AND y = '" + nextY + "' AND roomid = '" + roomID + "' ORDER BY h DESC LIMIT 1"); /*if (dTable.Rows.Count > 1) { foreach (DataRow dRow in dTable.Rows) { dTable2 = dbClient.getTable("SELECT top FROM catalogue_items WHERE tid = '" + dRow["tid"] + "'"); foreach (DataRow dRow2 in dTable2.Rows) { ItemHeight = ItemHeight + Convert.ToDouble(dRow2["top"]); } } }*/ if (dTable.Rows.Count > 0) { foreach (DataRow dRow in dTable.Rows) ItemHeight = ItemHeight + Convert.ToDouble(dRow["h"]); } } return ItemHeight; } internal bool hasFurni(int nextX, int nextY, int roomID) { DataTable dTable; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dTable = dbClient.getTable("SELECT * FROM furniture WHERE x = '" + nextX + "' AND y = '" + nextY + "' AND roomid = '" + roomID + "' ORDER BY h DESC LIMIT 1"); } if (dTable.Rows.Count > 0) return true; return false; } #region User and bot status management private void cycleStatuses() { TimeSpan cycleTime; while (CycleThread) { DateTime cycleStart = DateTime.Now; try { List toRemove = new List(); lock (_Users) { foreach (virtualRoomUser roomUser in _Users.Values) #region Virtual user status handling { if (roomUser.goalX == -1) // No destination set, user is not walking/doesn't start to walk, advance to next user continue; if (roomUser.walkDoor) // User has clicked the door to leave the room (and got stuck while walking or reached destination) { toRemove.Add(roomUser.roomUID); goto endLoop; } squareState[,] stateMap = (squareState[,])sqSTATE.Clone(); try { if (stateMap[roomUser.goalX, roomUser.goalY] == squareState.Seat || stateMap[roomUser.goalX, roomUser.goalY] == squareState.Bed || stateMap[roomUser.goalX, roomUser.goalY] == squareState.Roller || stateMap[roomUser.goalX, roomUser.goalY] == squareState.Food || roomUser.User.frontFurnis == true) stateMap[roomUser.goalX, roomUser.goalY] = squareState.Open; if (sqUNIT[roomUser.goalX, roomUser.goalY]) stateMap[roomUser.goalX, roomUser.goalY] = squareState.Blocked; } catch { } roomUser.statusManager.removeStatus("mv"); // Use AStar pathfinding to get the next step to the goal int[] nextCoords = new Pathfinding.Pathfinder(stateMap, sqFLOORHEIGHT, sqUNIT).getNext(roomUser.X, roomUser.Y, roomUser.goalX, roomUser.goalY); if (nextCoords != null) { int nextX_Check = nextCoords[0]; int nextY_Check = nextCoords[1]; double nextHeight_Check = 0; squareState nextState_Check = sqSTATE[nextX_Check, nextY_Check]; if (nextState_Check != squareState.Open) // Check if the tile has a furniture with a height on nextHeight_Check = sqITEMHEIGHT[nextX_Check, nextY_Check]; else nextHeight_Check = (double)sqFLOORHEIGHT[nextX_Check, nextY_Check]; if (Convert.ToInt32(nextHeight_Check) - Convert.ToInt32(roomUser.H) > 1 && roomUser.User._noHeightLimit == false) { roomUser.goalX = -1; roomUser.goalY = -1; nextCoords = null; } } if (nextCoords == null) // No next steps found, destination reached/stuck { if (roomUser.User.isToExit == true) { roomUser.User.sendData("@R"); roomUser.User.isToExit = false; roomUser.User.leaveCurrentRoom("", false); } if (roomUser.X == roomUser.goalX && roomUser.Y == roomUser.goalY && _magicTiles.ContainsKey(new Pathfinding.Coord(roomUser.X, roomUser.Y))) { magicTile mTile = (magicTile)_magicTiles[new Pathfinding.Coord(roomUser.X, roomUser.Y)]; roomUser.User.spawnLoc[0].X = mTile.toX; roomUser.User.spawnLoc[0].Y = mTile.toY; roomUser.User.spawnLoc[1].X = mTile.toZ; roomUser.User.spawnLoc[1].Y = mTile.toH; roomUser.User.spawnStatus = mTile.toStatus; roomUser.User.sendData("D^" + mTile.toMode + Encoding.encodeVL64(mTile.toID)); } if (sqTRIGGER[roomUser.X, roomUser.Y] != null) { squareTrigger Trigger = sqTRIGGER[roomUser.X, roomUser.Y]; if (this.hasSwimmingPool == true) // This virtual room has a swimming pool { #region Swimming pool triggers { if (Trigger.Object == "curtains1" || Trigger.Object == "curtains2") // User has entered a swimming pool clothing booth { roomUser.walkLock = true; roomUser.User.sendData("A`"); sendSpecialCast(Trigger.Object, "close"); } if (roomUser.swimOutfit != "") // User wears a swim outfit and hasn't entered a swimming pool clothing booth { if (Trigger.Object.Contains("Splash")) // User has entered/left a swimming pool { sendData("AG" + Trigger.Object); if (Trigger.Object.Substring(8) == "enter") { roomUser.statusManager.dropCarrydItem(); roomUser.statusManager.addStatus("swim", ""); } else roomUser.statusManager.removeStatus("swim"); moveUser(roomUser, Trigger.stepX, Trigger.stepY, false); roomUser.goalX = Trigger.goalX; roomUser.goalY = Trigger.goalY; } if (Trigger.Object == "play") // User has entered the diving board elevator { if (DiveDoorOpen == false) { roomUser.goalX = 26; roomUser.goalY = 5; } else { /* Diver = roomUser; DiverID = roomUser.roomUID; roomUser.walkLock = true; roomUser.Diving = true; DiveDoorOpen = false; roomUser.goalX = 26; roomUser.goalY = 3; moveUser(roomUser, 26, 3, true); sendSpecialCast("door", "close"); sqUNIT[26, 4] = true; roomUser.User.sendData("A}"); */ } roomUser.goalX = 26; roomUser.goalY = 5; moveUser(roomUser, 26, 5, true); sendSpecialCast("door", "close"); } } } } #endregion else { if (Trigger.Object == "warp") // El usuario se encuentra en una ubicacion de teleport { if (isPublicroom) { removeUser(roomID, false, ""); roomUser.User.sendData("D^" + "I" + Encoding.encodeVL64(Trigger.roomID)); } else { removeUser(roomID, false, ""); roomUser.User.sendData("D^" + "H" + Encoding.encodeVL64(Trigger.roomID)); } } } } roomUser.goalX = -1; // Next time the thread cycles this user, it won't attempt to walk since destination has been reached _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } else // Next steps found by pathfinder { int nextX = nextCoords[0]; int nextY = nextCoords[1]; squareState nextState = sqSTATE[nextX, nextY]; if (stateMap[nextX, nextY] == squareState.Blocked && roomUser.User.frontFurnis == true) stateMap[nextX, nextY] = squareState.Open; sqUNIT[roomUser.X, roomUser.Y] = false; // Free last position, allow other users to use that spot again sqUNIT[nextX, nextY] = walkthrough(roomUser.roomID); // Block the spot of the next steps roomUser.Z1 = Pathfinding.Rotation.Calculate(roomUser.X, roomUser.Y, nextX, nextY); // Calculate the users new rotation roomUser.Z2 = roomUser.Z1; roomUser.statusManager.removeStatus("sit"); roomUser.statusManager.removeStatus("lay"); double nextHeight = 0; if (nextState == squareState.Rug || nextState == squareState.Food) // If next step is on a rug, then set user's height to that of the rug [floating stacked rugs in mid-air, petals etc] nextHeight = sqITEMHEIGHT[nextX, nextY] + checkItemHeight(nextX, nextY, roomUser.roomID); else if (nextState == squareState.Roller) nextHeight = sqITEMHEIGHT[nextX, nextY] + checkItemHeight(nextX, nextY, roomUser.roomID) + 0.45; else nextHeight = (double)sqFLOORHEIGHT[nextX, nextY]; if (roomUser.User.frontFurnis == true && hasFurni(nextX, nextY, roomUser.roomID) == true) nextHeight = nextHeight + 1.00; // Add the walk status to users status manager + add users whole status string to stringbuilder if the user is allowed to walk roomUser.statusManager.addStatus("mv", nextX + "," + nextY + "," + nextHeight.ToString().Replace(',', '.')); _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); // Set new coords for virtual room user roomUser.X = nextX; roomUser.Y = nextY; roomUser.H = nextHeight; if (roomUser.User.isToExit == true && roomUser.X == doorX + 1 && roomUser.Y == doorY) { roomUser.User.sendData("@R"); roomUser.User.isToExit = false; roomUser.User.leaveCurrentRoom("", false); } if (nextState == squareState.Seat) // The next steps are on a seat, seat the user, prepare the sit status for next cycle of thread { roomUser.Z1 = sqITEMROT[nextX, nextY]; // roomUser.Z2 = roomUser.Z1; roomUser.statusManager.addStatus("sit", sqITEMHEIGHT[nextX, nextY].ToString().Replace(',', '.')); } else if (nextState == squareState.Bed) { roomUser.Z1 = sqITEMROT[nextX, nextY]; // roomUser.Z2 = roomUser.Z1; roomUser.statusManager.addStatus("lay", sqITEMHEIGHT[nextX, nextY].ToString().Replace(',', '.')); } else if (nextState == squareState.Roller) { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { DataRow dRow = dbClient.getRow("SELECT * FROM furniture WHERE tid > 464 AND tid < 475 AND roomid = '" + roomID + "' AND x = '" + roomUser.X + "' AND y = '" + roomUser.Y + "' LIMIT 1"); if (Convert.ToInt32(dRow["z"]) == 6) roomUser.goalX = roomUser.X - 1; else if (Convert.ToInt32(dRow["z"]) == 2) roomUser.goalX = roomUser.X + 1; else roomUser.goalX = roomUser.X; if (Convert.ToInt32(dRow["z"]) == 0) roomUser.goalY = roomUser.Y - 1; else if (Convert.ToInt32(dRow["z"]) == 4) roomUser.goalY = roomUser.Y + 1; else roomUser.goalY = roomUser.Y; roomUser.Z1 = byte.Parse(dRow["z"].ToString() + 1); roomUser.Z2 = roomUser.Z1; } } } } } endLoop: foreach (int toKick in toRemove) { removeUser(toKick, true, ""); } toRemove.Clear(); } catch { } #endregion #region Roombot walking foreach (virtualBot roomBot in _Bots.Values) { if (roomBot.goalX == -1) continue; // If the goal is a seat, then allow to 'walk' on the seat, so seat the user squareState[,] stateMap = (squareState[,])sqSTATE.Clone(); try { if (stateMap[roomBot.goalX, roomBot.goalY] == squareState.Seat) stateMap[roomBot.goalX, roomBot.goalY] = squareState.Open; if (sqUNIT[roomBot.goalX, roomBot.goalY]) stateMap[roomBot.goalX, roomBot.goalY] = squareState.Blocked; } catch { } int[] nextCoords = new Pathfinding.Pathfinder(stateMap, sqFLOORHEIGHT, sqUNIT).getNext(roomBot.X, roomBot.Y, roomBot.goalX, roomBot.goalY); roomBot.removeStatus("mv"); if (nextCoords == null) // No next steps found, destination reached/stuck { if (roomBot.X == roomBot.goalX && roomBot.Y == roomBot.goalY) { roomBot.checkOrders(); } roomBot.goalX = -1; _statusUpdates.Append(roomBot.statusString + Convert.ToChar(2)); } else { int nextX = nextCoords[0]; int nextY = nextCoords[1]; sqUNIT[roomBot.X, roomBot.Y] = false; // Free last position, allow other users to use that spot again sqUNIT[nextX, nextY] = false; // Free the spot of the next steps (For PublicRooms BETA) roomBot.Z1 = Pathfinding.Rotation.Calculate(roomBot.X, roomBot.Y, nextX, nextY); // Calculate the bot's new rotation roomBot.Z2 = roomBot.Z1; roomBot.removeStatus("sit"); double nextHeight = (double)sqFLOORHEIGHT[nextX, nextY]; if (sqSTATE[nextX, nextY] == squareState.Rug) // If next step is on a rug, then set bot's height to that of the rug [floating stacked rugs in mid-air, petals etc] nextHeight = sqITEMHEIGHT[nextX, nextY]; else nextHeight = (double)sqFLOORHEIGHT[nextX, nextY]; roomBot.addStatus("mv", nextX + "," + nextY + "," + nextHeight.ToString().Replace(',', '.')); _statusUpdates.Append(roomBot.statusString + Convert.ToChar(2)); // Set new coords for the bot roomBot.X = nextX; roomBot.Y = nextY; roomBot.H = nextHeight; if (sqSTATE[nextX, nextY] == squareState.Seat) // The next steps are on a seat, seat the bot, prepare the sit status for next cycle of thread { roomBot.Z1 = sqITEMROT[nextX, nextY]; // roomBot.Z2 = roomBot.Z1; roomBot.addStatus("sit", sqITEMHEIGHT[nextX, nextY].ToString().Replace(',', '.')); } } } #endregion #region Pet walking foreach (virtualPet roomPet in _Pets.Values) { if (roomPet.goalX == -1) continue; squareState[,] stateMap = (squareState[,])sqSTATE.Clone(); try { if (stateMap[roomPet.goalX, roomPet.goalY] == squareState.Seat || stateMap[roomPet.goalX, roomPet.goalY] == squareState.Roller || stateMap[roomPet.goalX, roomPet.goalY] == squareState.Food) stateMap[roomPet.goalX, roomPet.goalY] = squareState.Open; if (sqUNIT[roomPet.goalX, roomPet.goalY]) stateMap[roomPet.goalX, roomPet.goalY] = squareState.Blocked; } catch { } int[] nextCoords = new Pathfinding.Pathfinder(stateMap, sqFLOORHEIGHT, sqUNIT).getNext(roomPet.X, roomPet.Y, roomPet.goalX, roomPet.goalY); roomPet.removeStatus("mv"); if (nextCoords == null) // No next steps found, destination reached/stuck { roomPet.goalX = -1; _statusUpdates.Append(roomPet.statusString + Convert.ToChar(2)); } else { int nextX = nextCoords[0]; int nextY = nextCoords[1]; sqUNIT[roomPet.X, roomPet.Y] = false; // Free last position, allow other users to use that spot again sqUNIT[nextX, nextY] = walkthrough(roomPet.roomID); // Block the spot of the next steps roomPet.Z1 = Pathfinding.Rotation.Calculate(roomPet.X, roomPet.Y, nextX, nextY); // Calculate the bot's new rotation roomPet.Z2 = roomPet.Z1; roomPet.removeStatus(); double nextHeight = (double)sqFLOORHEIGHT[nextX, nextY]; if (sqSTATE[nextX, nextY] == squareState.Rug || sqSTATE[nextX, nextY] == squareState.Food) // If next step is on a rug, then set bot's height to that of the rug [floating stacked rugs in mid-air, petals etc] nextHeight = sqITEMHEIGHT[nextX, nextY] + checkItemHeight(nextX, nextY, roomPet.roomID); else if (sqSTATE[nextX, nextY] == squareState.Roller) nextHeight = checkItemHeight(nextX, nextY, roomPet.roomID); else nextHeight = (double)sqFLOORHEIGHT[nextX, nextY]; roomPet.addStatus("mv", nextX + "," + nextY + "," + nextHeight.ToString().Replace(',', '.')); _statusUpdates.Append(roomPet.statusString + Convert.ToChar(2)); // Set new coords for the bot roomPet.X = nextX; roomPet.Y = nextY; roomPet.H = nextHeight; if (sqSTATE[nextX, nextY] == squareState.Seat) // The next steps are on a seat, seat the bot, prepare the sit status for next cycle of thread { roomPet.Z1 = sqITEMROT[nextX, nextY]; // roomPet.Z2 = roomPet.Z1; roomPet.addStatus("sit", sqITEMHEIGHT[nextX, nextY].ToString().Replace(',', '.')); } else if (sqSTATE[nextX, nextY] == squareState.Food) // The next steps are on a seat, seat the bot, prepare the sit status for next cycle of thread { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { roomPet.Z1 = Convert.ToByte(Convert.ToInt32(sqITEMROT[nextX, nextY] + 1)); roomPet.Z2 = roomPet.Z1; roomPet.addStatus("eat", ""); dbClient.runQuery("UPDATE pets SET hungry = hungry + 10 WHERE id = '" + roomPet.ID + "' AND hungry < 101 LIMIT 1"); roomPet.Hungry = roomPet.Hungry + 10; } } else if (sqSTATE[nextX, nextY] == squareState.Roller) { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { DataRow dRow = dbClient.getRow("SELECT * FROM furniture WHERE tid > 464 AND tid < 475 AND roomid = '" + roomID + "' AND x = '" + roomPet.X + "' AND y = '" + roomPet.Y + "' LIMIT 1"); if (Convert.ToInt32(dRow["z"]) == 6) roomPet.goalX = roomPet.X - 1; else if (Convert.ToInt32(dRow["z"]) == 2) roomPet.goalX = roomPet.X + 1; else roomPet.goalX = roomPet.X; if (Convert.ToInt32(dRow["z"]) == 0) roomPet.goalY = roomPet.Y - 1; else if (Convert.ToInt32(dRow["z"]) == 4) roomPet.goalY = roomPet.Y + 1; else roomPet.goalY = roomPet.Y; roomPet.Z1 = byte.Parse(dRow["z"].ToString() + 1); roomPet.Z2 = roomPet.Z1; } } else { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { DataColumn dColumn = dbClient.getColumn("SELECT * FROM furniture WHERE tid > 53 AND tid < 59 AND roomid = '" + roomPet.roomID + "' ORDER BY RAND() LIMIT 1"); foreach (DataRow dRow in dColumn.Table.Rows) { if (dColumn.Table.Columns.Count != 0 && Convert.ToInt32(dRow["x"]) == roomPet.X && Convert.ToInt32(dRow["y"]) == roomPet.Y) { roomPet.Z1 = (byte)Convert.ToInt32(dRow["z"]); roomPet.Z2 = roomPet.Z1; roomPet.addStatus("pla", ""); roomPet.Room.sendData("AX" + Convert.ToInt32(dRow["id"]) + Convert.ToChar(2) + 1 + Convert.ToChar(2)); } } } } } } #endregion #region Room Fantasy Bot walking foreach (virtualFantasyBot roomBot in _FBots.Values) { if (roomBot.goalX == -1) continue; // If the goal is a seat, then allow to 'walk' on the seat, so seat the user squareState[,] stateMap = (squareState[,])sqSTATE.Clone(); try { if (stateMap[roomBot.goalX, roomBot.goalY] == squareState.Seat) stateMap[roomBot.goalX, roomBot.goalY] = squareState.Open; if (sqUNIT[roomBot.goalX, roomBot.goalY]) stateMap[roomBot.goalX, roomBot.goalY] = squareState.Blocked; } catch { } int[] nextCoords = new Pathfinding.Pathfinder(stateMap, sqFLOORHEIGHT, sqUNIT).getNext(roomBot.X, roomBot.Y, roomBot.goalX, roomBot.goalY); roomBot.removeStatus("mv"); if (nextCoords == null) // No next steps found, destination reached/stuck { roomBot.goalX = -1; _statusUpdates.Append(roomBot.statusString + Convert.ToChar(2)); } else { int nextX = nextCoords[0]; int nextY = nextCoords[1]; sqUNIT[roomBot.X, roomBot.Y] = false; // Free last position, allow other users to use that spot again sqUNIT[nextX, nextY] = false; // Free the spot of the next steps (For PublicRooms BETA) roomBot.Z1 = Pathfinding.Rotation.Calculate(roomBot.X, roomBot.Y, nextX, nextY); // Calculate the bot's new rotation roomBot.Z2 = roomBot.Z1; roomBot.removeStatus("sit"); double nextHeight = (double)sqFLOORHEIGHT[nextX, nextY]; if (sqSTATE[nextX, nextY] == squareState.Rug) // If next step is on a rug, then set bot's height to that of the rug [floating stacked rugs in mid-air, petals etc] nextHeight = sqITEMHEIGHT[nextX, nextY]; else nextHeight = (double)sqFLOORHEIGHT[nextX, nextY]; roomBot.addStatus("mv", nextX + "," + nextY + "," + nextHeight.ToString().Replace(',', '.')); _statusUpdates.Append(roomBot.statusString + Convert.ToChar(2)); // Set new coords for the bot roomBot.X = nextX; roomBot.Y = nextY; roomBot.H = nextHeight; if (sqSTATE[nextX, nextY] == squareState.Seat) // The next steps are on a seat, seat the bot, prepare the sit status for next cycle of thread { roomBot.Z1 = sqITEMROT[nextX, nextY]; // roomBot.Z2 = roomBot.Z1; roomBot.addStatus("sit", sqITEMHEIGHT[nextX, nextY].ToString().Replace(',', '.')); } } } #endregion // Send statuses to all room users [if in stringbuilder] try { int movingUserAmount = 0; if (_statusUpdates.Length > 0) { movingUserAmount = _statusUpdates.ToString().Split('\x02').Length / 2; sendData("@b" + Encoding.encodeVL64(movingUserAmount) + _statusUpdates.ToString()); _statusUpdates = new StringBuilder(); } } catch { } DateTime Stop = DateTime.Now; cycleTime = (DateTime.Now - cycleStart); if ((410 - cycleTime.TotalMilliseconds) > 0) Thread.Sleep(410 - cycleTime.Milliseconds); } } internal void Refresh(virtualRoomUser roomUser) { if (roomUser.goalX == -1) _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } internal void Refresh(virtualBot roomBot) { try { if (roomBot.goalX == -1) _statusUpdates.Append(roomBot.statusString + Convert.ToChar(2)); } catch { } } internal void Refresh(virtualFantasyBot roomBot) { try { if (roomBot.goalX == -1) _statusUpdates.Append(roomBot.statusString + Convert.ToChar(2)); } catch { } } internal void Refresh(virtualPet roomPet) { try { if (roomPet.goalX == -1) { this._statusUpdates.Append(roomPet.statusString + Convert.ToChar(2)); } } catch { } } internal void refreshCoord(int X, int Y) { foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (roomUser.X == X && roomUser.Y == Y) { if (sqSTATE[X, Y] == squareState.Seat) // Seat here { if (roomUser.statusManager.containsStatus("sit") == false) // User is not sitting yet { roomUser.Z1 = sqITEMROT[X, Y]; roomUser.Z2 = roomUser.Z1; roomUser.statusManager.addStatus("sit", sqITEMHEIGHT[X, Y].ToString().Replace(',', '.')); Refresh(roomUser); } } else if (sqSTATE[X, Y] == squareState.Roller) // Roller here { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { DataRow dRow = dbClient.getRow("SELECT * FROM furniture WHERE tid > 464 AND tid < 475 AND roomid = '" + roomID + "' AND x = '" + roomUser.X + "' AND y = '" + roomUser.Y + "' LIMIT 1"); if (Convert.ToInt32(dRow["z"]) == 6) roomUser.goalX = roomUser.X - 1; else if (Convert.ToInt32(dRow["z"]) == 2) roomUser.goalX = roomUser.X + 1; else roomUser.goalX = roomUser.X; if (Convert.ToInt32(dRow["z"]) == 0) roomUser.goalY = roomUser.Y - 1; else if (Convert.ToInt32(dRow["z"]) == 4) roomUser.goalY = roomUser.Y + 1; else roomUser.goalY = roomUser.Y; roomUser.Z1 = byte.Parse(dRow["z"].ToString() + 1); roomUser.Z2 = roomUser.Z1; Refresh(roomUser); } } else if (sqSTATE[X, Y] == squareState.Bed) // Bed here { if (roomUser.statusManager.containsStatus("bed") == false) // User is not laying yet { roomUser.Z1 = sqITEMROT[X, Y]; roomUser.Z2 = roomUser.Z1; roomUser.statusManager.addStatus("lay", sqITEMHEIGHT[X, Y].ToString().Replace(',', '.')); Refresh(roomUser); } } else { roomUser.statusManager.removeStatus("sit"); roomUser.statusManager.removeStatus("lay"); roomUser.H = sqFLOORHEIGHT[X, Y]; Refresh(roomUser); } return; } } } #region Single step walking internal void moveUser(virtualRoomUser roomUser, int toX, int toY, bool secondRefresh) { new userMover(MOVEUSER).BeginInvoke(roomUser, toX, toY, secondRefresh, null, null); } private delegate void userMover(virtualRoomUser roomUser, int toX, int toY, bool secondRefresh); private void MOVEUSER(virtualRoomUser roomUser, int toX, int toY, bool secondRefresh) { try { sqUNIT[roomUser.X, roomUser.Y] = false; sqUNIT[toX, toY] = walkthrough(roomUser.roomID); roomUser.Z1 = Pathfinding.Rotation.Calculate(roomUser.X, roomUser.Y, toX, toY); roomUser.Z2 = roomUser.Z1; roomUser.statusManager.removeStatus("sit"); Refresh(roomUser); double nextHeight = 0; if (sqSTATE[toX, toY] == squareState.Rug || sqSTATE[toX, toY] == squareState.Food) nextHeight = sqITEMHEIGHT[toX, toY] + checkItemHeight(toX, toY, roomUser.roomID); else if (sqSTATE[toX, toY] == squareState.Roller) nextHeight = checkItemHeight(toX, toY, roomUser.roomID); else nextHeight = (double)sqFLOORHEIGHT[toX, toY]; roomUser.statusManager.addStatus("mv", toX + "," + toY + "," + nextHeight.ToString().Replace(',', '.')); Refresh(roomUser); Thread.Sleep(310); roomUser.X = toX; roomUser.Y = toY; roomUser.H = nextHeight; roomUser.statusManager.removeStatus("mv"); Refresh(roomUser); if (secondRefresh) { if (sqSTATE[toX, toY] == squareState.Seat) // The next steps are on a seat, seat the user, prepare the sit status for next cycle of thread { roomUser.statusManager.removeStatus("dance"); // Remove dance status roomUser.Z1 = sqITEMROT[toX, toY]; roomUser.Z2 = roomUser.Z1; roomUser.statusManager.addStatus("sit", sqITEMHEIGHT[toX, toY].ToString().Replace(',', '.')); roomUser.statusManager.removeStatus("mv"); Refresh(roomUser); } else if (sqSTATE[toX, toY] == squareState.Roller) // Roller here { using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { DataRow dRow = dbClient.getRow("SELECT * FROM furniture WHERE tid > 464 AND tid < 475 AND roomid = '" + roomID + "' AND x = '" + roomUser.X + "' AND y = '" + roomUser.Y + "' LIMIT 1"); if (Convert.ToInt32(dRow["z"]) == 6) roomUser.goalX = roomUser.X - 1; else if (Convert.ToInt32(dRow["z"]) == 2) roomUser.goalX = roomUser.X + 1; else roomUser.goalX = roomUser.X; if (Convert.ToInt32(dRow["z"]) == 0) roomUser.goalY = roomUser.Y - 1; else if (Convert.ToInt32(dRow["z"]) == 4) roomUser.goalY = roomUser.Y + 1; else roomUser.goalY = roomUser.Y; roomUser.Z1 = byte.Parse(dRow["z"].ToString() + 1); roomUser.Z2 = roomUser.Z1; Refresh(roomUser); } } } } catch { } } #endregion #endregion #region Chat internal void sendSaying(virtualRoomUser sourceUser, string Message) { int gestureID = checkEmotion(sourceUser, Message); if (sourceUser.isTyping) { sendData("Ei" + Encoding.encodeVL64(sourceUser.roomUID) + "H"); sourceUser.isTyping = false; } foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (Math.Abs(roomUser.X - sourceUser.X) < 6 && Math.Abs(roomUser.Y - sourceUser.Y) < 6) { if (roomUser.roomUID != sourceUser.roomUID && roomUser.goalX == -1) { { roomUser.Z1 = Pathfinding.Rotation.headRotation(roomUser.Z2, roomUser.X, roomUser.Y, sourceUser.X, sourceUser.Y); //5 args _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } } string mutedIDs = roomUser.User._mutedIDs + ""; if (mutedIDs.Contains("<" + sourceUser.userID + ">") == false) roomUser.User.hearSayTalk(sourceUser, Message, gestureID); } } foreach (virtualBot roomBot in _Bots.Values) { roomBot.Interact(sourceUser, Message); } foreach (virtualPet roomPet in _Pets.Values) { roomPet.Interact(sourceUser, Message); } } internal void sendSaying(virtualBot sourceBot, string Message) { string Data = "@X" + Encoding.encodeVL64(sourceBot.roomUID) + Message + Convert.ToChar(2) + Encoding.encodeVL64(0); ; foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (Math.Abs(roomUser.X - sourceBot.X) < 6 && Math.Abs(roomUser.Y - sourceBot.Y) < 6) { { roomUser.Z1 = Pathfinding.Rotation.headRotation(roomUser.Z2, roomUser.X, roomUser.Y, sourceBot.X, sourceBot.Y); //5 args _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } } } } internal void sendSaying(virtualFantasyBot sourceBot, string Message) { string Data = "@X" + Encoding.encodeVL64(sourceBot.roomUID) + Message + Convert.ToChar(2) + Encoding.encodeVL64(0); ; foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (Math.Abs(roomUser.X - sourceBot.X) < 6 && Math.Abs(roomUser.Y - sourceBot.Y) < 6) { { roomUser.Z1 = Pathfinding.Rotation.headRotation(roomUser.Z2, roomUser.X, roomUser.Y, sourceBot.X, sourceBot.Y); //5 args _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } } } } internal void sendShout(virtualRoomUser sourceUser, string Message) { int gestureID = checkEmotion(sourceUser, Message); if (sourceUser.isTyping) { sendData("Ei" + Encoding.encodeVL64(sourceUser.roomUID) + "H"); sourceUser.isTyping = false; } Hashtable users = new Hashtable(); users = (Hashtable)this._Users.Clone(); { foreach (virtualRoomUser roomUser in _Users.Values) { if (roomUser.roomUID != sourceUser.roomUID && roomUser.goalX == -1) { { roomUser.Z1 = Pathfinding.Rotation.headRotation(roomUser.Z2, roomUser.X, roomUser.Y, sourceUser.X, sourceUser.Y); //5 args _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } } string mutedIDs = roomUser.User._mutedIDs + ""; if (mutedIDs.Contains("<" + sourceUser.userID + ">") == false) roomUser.User.hearShoutTalk(sourceUser, Message, gestureID); } foreach (virtualBot roomBot in _Bots.Values) { roomBot.Interact(sourceUser, Message); } foreach (virtualPet roomPet in _Pets.Values) { roomPet.Interact(sourceUser, Message); } } } internal void sendShout(virtualBot sourceBot, string Message) { string Data = "@Z" + Encoding.encodeVL64(sourceBot.roomUID) + stringManager.fixWords(Message) + Convert.ToChar(2) + Encoding.encodeVL64(0); ; lock (_Users) { foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (roomUser.roomUID != sourceBot.roomUID && roomUser.goalX == -1) { { _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } } roomUser.User.sendData(Data); } } } internal void sendShout(virtualFantasyBot sourceBot, string Message) { string Data = "@Z" + Encoding.encodeVL64(sourceBot.roomUID) + stringManager.fixWords(Message) + Convert.ToChar(2) + Encoding.encodeVL64(0); ; lock (_Users) { foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (roomUser.roomUID != sourceBot.roomUID && roomUser.goalX == -1) { { _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } } roomUser.User.sendData(Data); } } } internal void sendShout(virtualPet sourceBot, string Message) { string Data = "@Z" + Encoding.encodeVL64(sourceBot.roomUID) + stringManager.fixWords(Message) + Convert.ToChar(2) + Encoding.encodeVL64(0); ; lock (_Users) { foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (roomUser.roomUID != sourceBot.roomUID && roomUser.goalX == -1) { _statusUpdates.Append(roomUser.statusString + Convert.ToChar(2)); } roomUser.User.sendData(Data); } } } internal void sendWhisper(virtualRoomUser sourceUser, string Receiver, string Message) { int gestureID = checkEmotion(sourceUser, Message); if (sourceUser.isTyping) { sendData("Ei" + Encoding.encodeVL64(sourceUser.roomUID) + "H"); sourceUser.isTyping = false; } string Data = "@Y" + Encoding.encodeVL64(sourceUser.roomUID) + Message + Convert.ToChar(2) + Encoding.encodeVL64(gestureID); Hashtable users = new Hashtable(); users = (Hashtable)this._Users.Clone(); { foreach (virtualRoomUser roomUser in _Users.Values) { if (roomUser.User._Username == Receiver) { sourceUser.User.sendData(Data); string mutedIDs = roomUser.User._mutedIDs + ""; if (mutedIDs.Contains("<" + sourceUser.userID + ">") == false) roomUser.User.sendData(Data); return; } } } } internal void addPet(int ID, int X, int Y, bool Broadcast) { int UID = getFreeRoomIdentifier(); virtualPet roomPet = new virtualPet(ID, UID, this, X, Y); sqUNIT[roomPet.X, roomPet.Y] = true; _Pets.Add(UID, roomPet); if (Broadcast) { sendData(@"@\I" + roomPet.detailsString); //sendData("@b" + dynamicStatuses); sendData("@b" + roomPet.statusString); } } internal void addFBot(string name, string mission, string figure, int X, int Y, int Z, bool guide, bool Broadcast) { int UID = getFreeRoomIdentifier(); virtualFantasyBot roomBot = new virtualFantasyBot(UID, this, name, mission, figure, X, Y, Z, guide); roomBot.H = sqFLOORHEIGHT[roomBot.X, roomBot.Y]; sqUNIT[roomBot.X, roomBot.Y] = true; _FBots.Add(roomBot.roomUID, roomBot); if (Broadcast) { sendData(@"@\I" + roomBot.detailsString); sendData("@b" + roomBot.statusString); } if (guide) { roomBot.Move(); roomBot.Room.sendShout(roomBot, "Hola. Bienvenido a Habbo, es un placer conocerte. ¿Necesitas ayuda?"); roomBot.Room.sendShout(roomBot, "Soy un Bot Guí­a y estoy aquÃí para responder a cualquier pregunta en las próximas 24 horas."); } } internal string getPetString(int petID) { StringBuilder s = new StringBuilder(); foreach (virtualPet Pet in _Pets.Values) { if (Pet.ID == petID) { s.Append(Holo.Encoding.encodeVL64(petID)); s.Append(Pet.Name); s.Append(Convert.ToChar(2)); //s.Append("I"); //Pet level //s.Append(Holo.Encoding.encodeVL64(20)); //s.Append("I"); //Pet experience //s.Append(Holo.Encoding.encodeVL64(200)); //Max experience //s.Append("I"); //Pet energy //s.Append(Holo.Encoding.encodeVL64(200)); //Max energy //s.Append("I"); //Pet satiety //s.Append(Holo.Encoding.encodeVL64(200)); //Max satiety s.Append(Pet.Type); s.Append(Convert.ToChar(32)); s.Append(Pet.Race); s.Append(Convert.ToChar(32)); s.Append(Pet.Colour); s.Append(Convert.ToChar(2)); //s.Append("H"); //Pet respects s.Append("I"); //Pet owner (ID) s.Append("I"); //Pet age s.Append("_Users"); //Pet owner (Username) s.Append(Convert.ToChar(2)); s.Append(Convert.ToChar(2)); return s.ToString(); } } return null; } #endregion #region Moderacy tasks internal void kickUsers(byte casterRank, string Message) { List remove = new List(); lock (_Users) { foreach (virtualRoomUser roomUser in _Users.Values) { if (roomUser.User._Rank < casterRank) remove.Add(roomUser); } foreach (virtualRoomUser roomUser in remove) { removeUser(roomUser.roomUID, true, Message); } } } internal void muteUsers(byte casterRank, string Message) { Message = "B!" + stringManager.getString("scommand_muted") + "\r" + Message + Convert.ToChar(2); foreach (virtualRoomUser roomUser in ((Hashtable)_Users.Clone()).Values) { if (roomUser.User._isMuted == false && roomUser.User._Rank < casterRank) { roomUser.User._isMuted = true; roomUser.User.sendData(Message); } } } internal void unmuteUsers(byte casterRank) { string Message = "B!" + stringManager.getString("scommand_unmuted") + Convert.ToChar(2); Hashtable users = new Hashtable(); users = (Hashtable)_Users.Clone(); try { foreach (virtualRoomUser roomUser in users.Values) { if (roomUser.User._isMuted && roomUser.User._Rank < casterRank) { roomUser.User._isMuted = false; roomUser.User.sendData(Message); } } } catch { } } #endregion #region Bot loading and deloading internal void loadBots() { DataColumn dCol; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dCol = dbClient.getColumn("SELECT id FROM roombots WHERE roomid = '" + this.roomID + "'"); } int[] IDs = dataHandling.dColToArray(dCol, null); for (int i = 0; i < IDs.Length; i++) { virtualBot roomBot = new virtualBot(IDs[i], getFreeRoomIdentifier(), this); roomBot.H = sqFLOORHEIGHT[roomBot.X, roomBot.Y]; sqUNIT[roomBot.X, roomBot.Y] = true; _Bots.Add(roomBot.roomUID, roomBot); sendData(@"@\I" + roomBot.detailsString); sendData("@b" + roomBot.statusString); } } internal void loadPets() { DataColumn dCol; DataColumn dCol1; DataColumn dCol2; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dCol = dbClient.getColumn("SELECT id FROM pets WHERE roomid = '" + this.roomID + "'"); dCol1 = dbClient.getColumn("SELECT x FROM pets WHERE roomid = '" + this.roomID + "'"); dCol2 = dbClient.getColumn("SELECT y FROM pets WHERE roomid = '" + this.roomID + "'"); } int[] IDs = dataHandling.dColToArray(dCol, null); int[] Xs = dataHandling.dColToArray(dCol1, null); int[] Ys = dataHandling.dColToArray(dCol2, null); for (int i = 0; i < IDs.Length; i++) { virtualPet roomBot = new virtualPet(IDs[i], getFreeRoomIdentifier(), this, Xs[i], Ys[i]); roomBot.H = sqFLOORHEIGHT[roomBot.X, roomBot.Y]; sqUNIT[roomBot.X, roomBot.Y] = true; _Pets.Add(roomBot.roomUID, roomBot); sendData(@"@\I" + roomBot.detailsString); sendData("@b" + dynamicStatuses); } } #endregion #endregion #region Map management internal bool squareBlocked(int X, int Y, int Length, int Width) { for (int jX = X; jX < X + Width; jX++) { for (int jY = Y; jY < X + Length; jY++) { if (sqUNIT[jX, jY]) return true; } } return false; } internal void setSquareState(int X, int Y, int Length, int Width, squareState State) { for (int jX = X; jX < X + Width; jX++) { for (int jY = Y; jY < Y + Length; jY++) { sqSTATE[jX, jY] = State; } } } internal squareTrigger getTrigger(int X, int Y) { try { return sqTRIGGER[X, Y]; } catch { return null; } } internal int[] getMapBorders() { int[] i = new int[2]; i[0] = sqUNIT.GetUpperBound(0); i[1] = sqUNIT.GetUpperBound(1); return i; } internal class squareTrigger { internal readonly string Object; internal readonly int goalX; internal readonly int goalY; internal readonly int stepX; internal readonly int stepY; internal readonly int roomID; internal bool State; internal squareTrigger(string Object, int goalX, int goalY, int stepX, int stepY, bool State, int roomID) { this.Object = Object; this.goalX = goalX; this.goalY = goalY; this.stepX = stepX; this.stepY = stepY; this.roomID = roomID; this.State = State; } } #endregion #region Item managers internal class FloorItemManager { private virtualRoom _Room; internal Hashtable _Items = new Hashtable(); internal int soundMachineID; public FloorItemManager(virtualRoom Room) { this._Room = Room; } internal void Clear() { try { _Items.Clear(); } catch { } _Room = null; _Items = null; } internal void addItem(int itemID, int templateID, int X, int Y, int Z, double H, string Var, int remoteID) { try { catalogueManager.itemTemplate Template = catalogueManager.getTemplate(templateID); if ((stringManager.getStringPart(Template.Sprite, 0, 13) == "sound_machine") || (stringManager.getStringPart(Template.Sprite, 0, 13) == "ads_idol_trax") || (stringManager.getStringPart(Template.Sprite, 0, 13) == "nouvelle_trax")) soundMachineID = itemID; int Length = 0; int Width = 0; if (Z == 2 || Z == 6) { Length = Template.Length; Width = Template.Width; } else { Length = Template.Width; Width = Template.Length; } for (int jX = X; jX < X + Width; jX++) for (int jY = Y; jY < Y + Length; jY++) { furnitureStack Stack = _Room.sqSTACK[jX, jY]; if (Stack == null) { if (Template.typeID != 2 && Template.typeID != 3) { Stack = new furnitureStack(); Stack.Add(itemID); } } else Stack.Add(itemID); _Room.sqSTATE[jX, jY] = (squareState)Template.typeID; if (Template.typeID == 2 || Template.typeID == 3) { _Room.sqITEMHEIGHT[jX, jY] = H + Template.topH; _Room.sqITEMROT[jX, jY] = Convert.ToByte(Z); if (Template.typeID == 3 && (jX != X || jY != Y)) if (Width == 1) _Room.sqSTATE[jX, jY] = squareState.Blocked; else if ((Z == 2 && jX != X) || (Z == 0 && jY != Y)) _Room.sqSTATE[jX, jY] = squareState.Blocked; } else { if (Template.typeID == 4) _Room.sqITEMHEIGHT[jX, jY] = H; } _Room.sqSTACK[jX, jY] = Stack; } if (Template.isDoor) { if (_Room.squareBlocked(X, Y, Length, Width)) return; if (Var.ToLower() == "0") _Room.setSquareState(X, Y, Length, Width, squareState.Blocked); else if (Var.ToLower() == "1") _Room.setSquareState(X, Y, Length, Width, squareState.Open); else _Room.setSquareState(X, Y, Length, Width, squareState.Blocked); } floorItem Item = new floorItem(itemID, templateID, X, Y, Z, H, Var, remoteID); _Items.Add(itemID, Item); } catch { } } internal void removeItem(int itemID, int ownerID) { if (_Items.ContainsKey(itemID)) { floorItem Item = (floorItem)_Items[itemID]; catalogueManager.itemTemplate Template = catalogueManager.getTemplate(Item.templateID); int Length = 0; int Width = 0; if (Item.Z == 2 || Item.Z == 6) { Length = Template.Length; Width = Template.Width; } else { Length = Template.Width; Width = Template.Length; } for (int jX = Item.X; jX < Item.X + Width; jX++) { for (int jY = Item.Y; jY < Item.Y + Length; jY++) { furnitureStack Stack = _Room.sqSTACK[jX, jY]; if (Stack != null && Stack.Count > 1) { if (itemID == Stack.bottomItemID()) { int topID = Stack.topItemID(); floorItem topItem = (floorItem)_Items[topID]; if (catalogueManager.getTemplate(topItem.templateID).typeID == 2) _Room.sqSTATE[jX, jY] = squareState.Seat; else _Room.sqSTATE[jX, jY] = 0; } else if (itemID == Stack.topItemID()) { int belowID = Stack.getBelowItemID(itemID); floorItem belowItem = (floorItem)_Items[belowID]; byte typeID = catalogueManager.getTemplate(belowItem.templateID).typeID; _Room.sqSTATE[jX, jY] = (squareState)typeID; if (typeID == 2 || typeID == 3) { _Room.sqITEMROT[jX, jY] = belowItem.Z; _Room.sqITEMHEIGHT[jX, jY] = belowItem.H + catalogueManager.getTemplate(belowItem.templateID).topH; } else if (typeID == 4) { _Room.sqITEMHEIGHT[jX, jY] = belowItem.H; // Open = 0, Blocked = 1, Seat = 2, Bed = 3, Rug = 4 }; } } Stack.Remove(itemID); _Room.sqSTACK[jX, jY] = Stack; } else { _Room.sqSTATE[jX, jY] = 0; _Room.sqITEMHEIGHT[jX, jY] = 0; _Room.sqITEMROT[jX, jY] = 0; _Room.sqSTACK[jX, jY] = null; } if (Template.typeID == 2 || Template.typeID == 3) _Room.refreshCoord(jX, jY); } } if (this.soundMachineID == 0 && ((stringManager.getStringPart(Template.Sprite, 0, 13) == "sound_machine") || (stringManager.getStringPart(Template.Sprite, 0, 13) == "ads_idol_trax") || (stringManager.getStringPart(Template.Sprite, 0, 13) == "nouvelle_trax"))) soundMachineID = 0; _Room.sendData("A^" + itemID + Convert.ToChar(2)); _Items.Remove(itemID); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.AddParamWithValue("ownerid", ownerID); dbClient.AddParamWithValue("itemid", itemID); if (ownerID > 0) // Return to current owner/new owner dbClient.runQuery("UPDATE furniture SET x = '0',y = '0', z = '0', h = '0', ownerid = @ownerid,roomid = '0' WHERE id = @itemid LIMIT 1;"); else dbClient.runQuery("DELETE FROM furniture WHERE id = @itemid LIMIT 1;"); } } } internal void placeItem(int itemID, int templateID, int X, int Y, byte typeID, byte Z, bool _stackRugs) { if (_Items.ContainsKey(itemID)) return; try { catalogueManager.itemTemplate Template = catalogueManager.getTemplate(templateID); bool isSoundMachine = ((stringManager.getStringPart(Template.Sprite, 0, 13) == "sound_machine") || (stringManager.getStringPart(Template.Sprite, 0, 13) == "ads_idol_trax") || (stringManager.getStringPart(Template.Sprite, 0, 13) == "nouvelle_trax")); if (isSoundMachine && soundMachineID > 0) return; int Length = 0; int Width = 0; if (Z == 2 || Z == 6) { Length = Template.Length; Width = Template.Width; } else { Length = Template.Width; Width = Template.Length; } double testH = _Room.sqFLOORHEIGHT[X, Y]; double H = testH; if (_Room.sqSTACK[X, Y] != null) { floorItem topItem = (floorItem)_Items[_Room.sqSTACK[X, Y].topItemID()]; H = topItem.H + catalogueManager.getTemplate(topItem.templateID).topH; } for (int jX = X; jX < X + Width; jX++) { for (int jY = Y; jY < Y + Length; jY++) { if (_Room.sqUNIT[jX, jY]) // Dynamical unit here return; squareState jState = _Room.sqSTATE[jX, jY]; if (jState != squareState.Open) { if (jState == squareState.Blocked) { if (_Room.sqSTACK[jX, jY] == null) // Square blocked and no stack here return; else { floorItem topItem = (floorItem)_Items[_Room.sqSTACK[jX, jY].topItemID()]; catalogueManager.itemTemplate topItemTemplate = catalogueManager.getTemplate(topItem.templateID); if (topItemTemplate.topH == 0 || topItemTemplate.typeID == 2 || topItemTemplate.typeID == 3) // No stacking on seat/bed return; else { if (topItem.H + topItemTemplate.topH > H) // Higher than previous topheight H = topItem.H + topItemTemplate.topH; } } } else if (jState == squareState.Rug && _Room.sqSTACK[jX, jY] != null) { double jH = ((floorItem)_Items[_Room.sqSTACK[jX, jY].topItemID()]).H + 0.1; if (jH > H) H = jH; } else // Seat etc return; } } } if (H > Config.Items_Stacking_maxHeight) H = Config.Items_Stacking_maxHeight; for (int jX = X; jX < X + Width; jX++) { for (int jY = Y; jY < Y + Length; jY++) { furnitureStack Stack = null; if (_Room.sqSTACK[jX, jY] == null) { if ((Template.typeID == 1 && Template.topH > 0) || Template.typeID == 4) { Stack = new furnitureStack(); Stack.Add(itemID); } } else { Stack = _Room.sqSTACK[jX, jY]; Stack.Add(itemID); } _Room.sqSTATE[jX, jY] = (squareState)Template.typeID; _Room.sqSTACK[jX, jY] = Stack; if (Template.typeID == 2 || Template.typeID == 3) { //_Room.sqITEMHEIGHT[jX, jY] = Template.topH; _Room.sqITEMHEIGHT[jX, jY] = H + Template.topH; _Room.sqITEMROT[jX, jY] = Z; _Room.sqITEMROT[jX, jY] = Z; if (Template.typeID == 3 && (jX != X || jY != Y)) if (Width == 1) _Room.sqSTATE[jX, jY] = squareState.Blocked; else if ((Z == 2 && jX != X) || (Z == 0 && jY != Y)) _Room.sqSTATE[jX, jY] = squareState.Blocked; } else if (Template.typeID == 4) _Room.sqITEMHEIGHT[jX, jY] = H; //_Room.sqITEMHEIGHT[jX, jY] = Template.topH; } } string Var; int remoteID = 0; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.AddParamWithValue("itemid", itemID); Var = dbClient.getString("SELECT var FROM furniture WHERE id = @itemid;"); dbClient.AddParamWithValue("roomid", _Room.roomID); dbClient.AddParamWithValue("x", X); dbClient.AddParamWithValue("y", Y); dbClient.AddParamWithValue("z", Z); dbClient.AddParamWithValue("h", H.ToString().Replace(',', '.')); dbClient.runQuery("UPDATE furniture SET roomid = @roomid,x = @x,y = @y,z = @z,h = @h WHERE id = @itemid LIMIT 1;"); remoteID = dbClient.getInt("SELECT teleportid FROM furniture WHERE id = @itemid;"); } floorItem Item = new floorItem(itemID, templateID, X, Y, Z, H, Var, remoteID); _Items.Add(itemID, Item); _Room.sendData("A]" + Item.ToString() + Convert.ToChar(2) + Convert.ToChar(1) + "C[!;0"); if (isSoundMachine) this.soundMachineID = itemID; } catch { } } internal void rotateItem(int itemID, byte Z) { floorItem Item = (floorItem)_Items[itemID]; catalogueManager.itemTemplate Template = catalogueManager.getTemplate(Item.templateID); int Length = 1; int Width = 1; if (Template.Length > 1 && Template.Width > 1) { if (Z == 2 || Z == 6) { Length = Template.Length; Width = Template.Width; } else { Length = Template.Width; Width = Template.Length; } } for (int jX = Item.X; jX < Item.X + Width; jX++) for (int jY = Item.Y; jY < Item.Y + Length; jY++) { furnitureStack Stack = _Room.sqSTACK[jX, jY]; if (Stack != null && Stack.topItemID() != itemID) { } } } internal void relocateItem(int itemID, int X, int Y, byte Z) { try { floorItem Item = (floorItem)_Items[itemID]; catalogueManager.itemTemplate Template = catalogueManager.getTemplate(Item.templateID); int Length = 0; int Width = 0; if (Z == 2 || Z == 6) { Length = Template.Length; Width = Template.Width; } else { Length = Template.Width; Width = Template.Length; } double baseFloorH = _Room.sqFLOORHEIGHT[X, Y]; double H = baseFloorH; if (_Room.sqSTACK[X, Y] != null) { floorItem topItem = (floorItem)_Items[_Room.sqSTACK[X, Y].topItemID()]; if (topItem != Item) { catalogueManager.itemTemplate topTemplate = catalogueManager.getTemplate(topItem.templateID); if (topTemplate.typeID == 1) H = topItem.H + topTemplate.topH; } else if (_Room.sqSTACK[X, Y].Count > 1) H = topItem.H; } for (int jX = X; jX < X + Width; jX++) { for (int jY = Y; jY < Y + Length; jY++) { if (Template.typeID != 2 && _Room.sqUNIT[jX, jY]) return; squareState jState = _Room.sqSTATE[jX, jY]; furnitureStack Stack = _Room.sqSTACK[jX, jY]; if (jState != squareState.Open) { if (Stack == null) { if (jX != Item.X || jY != Item.Y) return; } else { floorItem topItem = (floorItem)_Items[Stack.topItemID()]; if (topItem != Item) { catalogueManager.itemTemplate topItemTemplate = catalogueManager.getTemplate(topItem.templateID); if (topItemTemplate.typeID == 1 && topItemTemplate.topH > 0) { if (topItem.H + topItemTemplate.topH > H) H = topItem.H + topItemTemplate.topH; } else { if (topItemTemplate.typeID == 2) return; } //return; } } } } } int oldLength = 1; int oldWidth = 1; if (Template.Length > 1 || Template.Width > 1) { if (Item.Z == 2 || Item.Z == 6) { oldLength = Template.Length; oldWidth = Template.Width; } else { oldLength = Template.Width; oldWidth = Template.Length; } } if (H > Config.Items_Stacking_maxHeight) H = Config.Items_Stacking_maxHeight; for (int jX = Item.X; jX < Item.X + oldWidth; jX++) { for (int jY = Item.Y; jY < Item.Y + oldLength; jY++) { furnitureStack Stack = _Room.sqSTACK[jX, jY]; if (Stack != null && Stack.Count > 1) { if (itemID == Stack.bottomItemID()) { if (catalogueManager.getTemplate(((floorItem)_Items[Stack.topItemID()]).templateID).typeID == 2) _Room.sqSTATE[jX, jY] = squareState.Seat; else _Room.sqSTATE[jX, jY] = squareState.Open; } else if (itemID == Stack.topItemID()) { floorItem belowItem = (floorItem)_Items[Stack.getBelowItemID(itemID)]; byte typeID = catalogueManager.getTemplate(belowItem.templateID).typeID; _Room.sqSTATE[jX, jY] = (squareState)typeID; if (typeID == 2 || typeID == 3) { _Room.sqITEMROT[jX, jY] = belowItem.Z; _Room.sqITEMHEIGHT[jX, jY] = belowItem.H + catalogueManager.getTemplate(belowItem.templateID).topH; if (Template.typeID == 3 && (jX != X || jY != Y)) if (Width == 1) _Room.sqSTATE[jX, jY] = squareState.Blocked; else if ((Z == 2 && jX != X) || (Z == 0 && jY != Y)) _Room.sqSTATE[jX, jY] = squareState.Blocked; } else if (typeID == 4) _Room.sqITEMHEIGHT[jX, jY] = belowItem.H; } Stack.Remove(itemID); _Room.sqSTACK[jX, jY] = Stack; } else { _Room.sqSTATE[jX, jY] = 0; _Room.sqITEMHEIGHT[jX, jY] = 0; _Room.sqITEMROT[jX, jY] = 0; _Room.sqSTACK[jX, jY] = null; } if (Template.typeID == 2 || Template.typeID == 3) _Room.refreshCoord(jX, jY); } } Item.X = X; Item.Y = Y; Item.Z = Z; Item.H = H; _Room.sendData("A_" + Item.ToString()); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.AddParamWithValue("x", X); dbClient.AddParamWithValue("y", Y); dbClient.AddParamWithValue("z", Z); dbClient.AddParamWithValue("h", H.ToString().Replace(',', '.')); dbClient.AddParamWithValue("itemid", itemID); dbClient.runQuery("UPDATE furniture SET x = @x,y = @y,z = @z,h = @h WHERE id = @itemid LIMIT 1;"); } for (int jX = X; jX < X + Width; jX++) { for (int jY = Y; jY < Y + Length; jY++) { furnitureStack Stack = null; if (_Room.sqSTACK[jX, jY] == null) { if (Template.topH > 0 && Template.typeID != 2 && Template.typeID != 3 && Template.typeID != 4) { Stack = new furnitureStack(); Stack.Add(itemID); } } else { Stack = _Room.sqSTACK[jX, jY]; Stack.Add(itemID); } _Room.sqSTATE[jX, jY] = (squareState)Template.typeID; _Room.sqSTACK[jX, jY] = Stack; if (Template.typeID == 2 || Template.typeID == 3) { _Room.sqITEMHEIGHT[jX, jY] = H + Template.topH; _Room.sqITEMROT[jX, jY] = Z; _Room.refreshCoord(jX, jY); } else if (Template.typeID == 4) _Room.sqITEMHEIGHT[jX, jY] = H; } } } catch { } } internal void toggleItemStatus(int itemID, string toStatus, bool hasRights) { string curStatus = ""; int curAction = Encoding.decodeVL64(toStatus); toStatus = Convert.ToString(Encoding.decodeVL64(toStatus)); if (int.Parse(toStatus) == 0) { toStatus = ""; } if (_Items.ContainsKey(itemID) == false) return; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { curStatus = dbClient.getString("SELECT var FROM furniture WHERE id = " + itemID + " LIMIT 1"); } floorItem Item = (floorItem)_Items[itemID]; catalogueManager.itemTemplate Template = catalogueManager.getTemplate(Item.templateID); int toStatusInt = 0; if (curStatus == "") curStatus = Convert.ToString(0); if (Template.drinkIDs != "") { toStatus = Convert.ToString(1); goto resumeTostatus; } toStatusInt = int.Parse(curStatus); if (int.Parse(curStatus) != Template.maxStatus && int.Parse(curStatus) < Template.maxStatus) { if (curAction == 1) toStatusInt = toStatusInt - 1; if (curAction == 2) toStatusInt = toStatusInt + 1; if (toStatusInt == -1) toStatusInt = Template.maxStatus; if (curAction == 0) { toStatusInt = toStatusInt + 1; if (Template.maxStatus > 9) { if (int.Parse(curStatus) == -1) { toStatusInt = 0; } else { toStatusInt = -1; } } } } else { toStatusInt = 0; } toStatus = Convert.ToString(toStatusInt); resumeTostatus: string itemSprite = Item.Sprite; /* Can not hack presents by Hebbo */ if (itemSprite.Contains("present_gen")) return; /* Can not hack trophies by Hebbo */ if (itemSprite.Contains("prizetrophy") || itemSprite.Contains("greektrophy")) return; if (itemSprite == "edice" || itemSprite == "edicehc" || stringManager.getStringPart(itemSprite, 0, 11) == "prizetrophy" || stringManager.getStringPart(itemSprite, 0, 7) == "present") // Items that can't be signed [this regards dicerigging etc] return; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.AddParamWithValue("var", toStatus); if (Template.isDoor == true) // Door { if (hasRights) // Rights check { #region Open/close doors int Length = 1; int Width = 1; if (Template.Length > 1 || Template.Width > 1) { if (Item.Z == 2 || Item.Z == 6) { Length = Template.Length; Width = Template.Width; } else { Length = Template.Width; Width = Template.Length; } } if (int.Parse(toStatus.ToLower()) == 0) { if (_Room.squareBlocked(Item.X, Item.Y, Length, Width)) return; _Room.setSquareState(Item.X, Item.Y, Length, Width, squareState.Blocked); } else _Room.setSquareState(Item.X, Item.Y, Length, Width, squareState.Open); Item.Var = toStatus; _Room.sendData("AX" + itemID + Convert.ToChar(2) + toStatus + Convert.ToChar(2)); dbClient.runQuery("UPDATE furniture SET var = '" + toStatus + "' WHERE id = " + itemID + " LIMIT 1"); #endregion } return; } string safeStatus = toStatus.Replace(Convert.ToChar(2), Convert.ToChar(32)); if (safeStatus != toStatus) return; Item.Var = toStatus; dbClient.runQuery("UPDATE furniture SET var = '" + toStatus + "' WHERE id = " + itemID + " LIMIT 1"); _Room.sendData("AX" + itemID + Convert.ToChar(2) + toStatus + Convert.ToChar(2)); } } /// /// Returns a string with all the virtual wallitems in this item manager. /// internal string Items { get { StringBuilder itemList = new StringBuilder(Encoding.encodeVL64(_Items.Count)); foreach (floorItem Item in _Items.Values) itemList.Append(Item.ToString()); return itemList.ToString(); } } /// /// Returns a bool that indicates if the item manager contains a certain virtual flooritem. /// /// The ID of the item to check. internal bool containsItem(int itemID) { return _Items.ContainsKey(itemID); } /// /// Returns the floorItem object of a certain virtual flooritem in the item manager. /// /// The ID of the item to get the floorItem object of. internal floorItem getItem(int itemID) { return (floorItem)_Items[itemID]; } } /// /// Provides management for virtual wallitems in a virtual room. /// internal class WallItemManager { private virtualRoom _Room; internal Hashtable _Items = new Hashtable(); /// /// Initializes the manager. /// /// The parent room. public WallItemManager(virtualRoom Room) { this._Room = Room; } /// /// Removes all the items from the item manager and destructs all objects inside. /// internal void Clear() { try { _Items.Clear(); } catch { } _Room = null; _Items = null; } /// /// Adds a virtual wallitem to the item manager and optionally makes it appear in the room. /// /// The ID of the item to add. /// The item to add. /// Indicates if the item is put in the room now, so updating database and sending appear packet to room. internal void addItem(int itemID, int templateID, string wallPosition, string Var, bool Place) { //Out.WriteLine("addItem: " + itemID + " " + templateID + " " + wallPosition + " " + Var + " " + Place); if (_Items.Contains(itemID) == false) { wallItem Item = new wallItem(itemID, templateID, wallPosition, Var); _Items.Add(itemID, Item); if (Place) { _Room.sendData("AS" + Item.ToString() + Convert.ToChar(2)); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.runQuery("UPDATE furniture SET roomid = '" + _Room.roomID + "',wallpos = '" + wallPosition + "' WHERE id = '" + itemID + "' LIMIT 1"); if (templateID == 1002) { if (dbClient.findsResult("SELECT roomid FROM furniture_moodlight WHERE id='" + itemID + "'") == false) { // The moodlight is new ;) dbClient.runQuery("INSERT INTO furniture_moodlight VALUES ('" + itemID + "','" + _Room.roomID + "','1','1,#000000,225','1,#000000,200','1,#000000,175')"); } else { // The moodlight is moved to another room dbClient.runQuery("UPDATE furniture_moodlight SET roomid = '" + _Room.roomID + "' WHERE id= '" + itemID + "'"); } } } } } } /// /// Removes a virtual wallitem from the item manager, updates the database row/drops the item from database and makes it disappear in the room. /// /// The ID of the item to remove. /// The ID of the user that owns this item. If 0, then the item will be dropped from the database. internal void removeItem(int itemID, int ownerID) { if (_Items.ContainsKey(itemID)) { _Room.sendData("AT" + itemID + Convert.ToChar(2)); _Items.Remove(itemID); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { if (ownerID > 0) dbClient.runQuery("UPDATE furniture SET ownerid = '" + ownerID + "',roomid = '0',pickedup = '" + Convert.ToString(DateTime.Now) + "' WHERE id = '" + itemID + "' LIMIT 1"); else dbClient.runQuery("DELETE FROM furniture WHERE id = '" + itemID + "' LIMIT 1"); } } } /// /// Updates the status of a virtual wallitem and updates it in the virtual room and in the database. Certain items can't switch status by this way, and they will be ignored to prevent exploiting. /// /// The ID of the item to update. /// The new status of the item. internal void toggleItemStatus(int itemID, int toStatus) { if (_Items.ContainsKey(itemID) == false) return; wallItem Item = (wallItem)_Items[itemID]; string itemSprite = Item.Sprite; if (itemSprite == "roomdimmer" || itemSprite == "post.it" || itemSprite == "post.it.vd" || itemSprite == "poster" || itemSprite == "habbowheel" || itemSprite == "ads_lin_wh_c") return; Item.Var = toStatus.ToString(); _Room.sendData("AU" + itemID + Convert.ToChar(2) + Encoding.encodeVL64(Item.templateID) + Item.wallPosition + Convert.ToChar(2) + Item.Var + Convert.ToChar(2)); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.runQuery("UPDATE furniture SET var = '" + toStatus + "' WHERE id = '" + itemID + "' LIMIT 1"); } } /// /// Returns a string with all the virtual wallitems in this item manager. /// internal string Items { get { StringBuilder itemList = new StringBuilder(); itemList.Append(Encoding.encodeVL64(_Items.Count)); try { foreach (wallItem Item in _Items.Values) itemList.Append(Item.ToString() + Convert.ToChar(2)); } catch { } return itemList.ToString(); } } /// /// Returns a bool that indicates if the item manager contains a certain virtual wallitem. /// /// The ID of the item to check. internal bool containsItem(int itemID) { return _Items.ContainsKey(itemID); } /// /// Returns the wallItem object of a certain virtual wallitem in the item manager. /// /// The ID of the item to get the wallItem object of. internal wallItem getItem(int itemID) { return (wallItem)_Items[itemID]; } /// /// Gets the setting of the moodlight in the current room /// internal string moodLight_GetSettings(int roomID) { try { string[] itemSettings; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { itemSettings = (string[])dbClient.getRow("SELECT preset_cur,preset_1,preset_2,preset_3 FROM furniture_moodlight WHERE roomid ='" + roomID + "'").ItemArray; } string settingPack = (Encoding.encodeVL64(3) + Encoding.encodeVL64(Convert.ToInt32(itemSettings[0]))); for (int i = 1; i <= 3; i++) { string[] curPresetData = itemSettings[i].Split(','); settingPack = (settingPack + Encoding.encodeVL64(i) + Encoding.encodeVL64(Convert.ToInt32(curPresetData[0])) + curPresetData[1] + Convert.ToChar(2) + Encoding.encodeVL64(Convert.ToInt32(curPresetData[2]))); } return settingPack; } catch { return ""; } } /// /// Sets the Settings of the Moodlight in the current room /// /// /// /// /// /// /// /// internal void moodLight_SetSettings(bool isEnabled, int presetID, int bgState, string presetColour, int alphaDarkF, int roomID, int templateID) { int itemID; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { itemID = dbClient.getInt("SELECT id FROM furniture_moodlight WHERE roomid ='" + roomID + "'"); } string newPresetValue; if (isEnabled == false) { string curPresetValue; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { curPresetValue = dbClient.getString("SELECT var FROM furniture WHERE id ='" + itemID + "'"); } if (curPresetValue.Substring(0, 1) == "2") { newPresetValue = ("1" + curPresetValue.Substring(1)); } else { newPresetValue = ("2" + curPresetValue.Substring(1)); } using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.runQuery("UPDATE furniture SET var = '" + newPresetValue + "' WHERE id ='" + itemID + "' LIMIT 1"); } } else { newPresetValue = ("2," + presetID + "," + bgState + "," + presetColour + "," + alphaDarkF); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dbClient.runQuery("UPDATE furniture SET var ='" + newPresetValue + "' WHERE id ='" + itemID + "' LIMIT 1"); dbClient.runQuery("UPDATE furniture_moodlight SET preset_cur ='" + presetID + "',preset_" + presetID + " ='" + bgState + "," + presetColour + "," + alphaDarkF + "' WHERE id = '" + itemID + "' LIMIT 1"); } } DataRow dRow; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dRow = dbClient.getRow("SELECT wallpos,var FROM furniture WHERE id = '" + itemID + "'"); } string wallPosition = Convert.ToString(dRow["wallpos"]); refreshWallitem(itemID, "roomdimmer", wallPosition, Convert.ToString(dRow["var"]), templateID); } /// /// refreshWallItem, taken from the Old VB.NET source. [Only used by Moodlight] /// /// /// /// /// /// internal void refreshWallitem(int itemID, string cctName, string wallPosition, string itemVariable, int templateID) { _Room.sendData("AU" + itemID + Convert.ToChar(2) + Encoding.encodeVL64(templateID) + wallPosition + Convert.ToChar(2) + itemVariable + Convert.ToChar(2)); } } #endregion /// /// returns if there is an active specialcast with the emitter in it /// /// The value of the emitter in question public bool hasSpecialCasts(string emiterValue) { if (emitter != null) { if (emitter == emiterValue) return true; } return false; } #region Special publicroom additions private void handleSpecialCasts(object o) { try { DataRow dRow; using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { dRow = dbClient.getRow("SELECT specialcast_emitter,specialcast_interval,specialcast_rnd_min, specialcast_rnd_max FROM room_modeldata WHERE model = '" + (string)o + "'"); } emitter = Convert.ToString(dRow["specialcast_emitter"]); int Interval = Convert.ToInt32(dRow["specialcast_interval"]); int rndMin = Convert.ToInt32(dRow["specialcast_rnd_min"]); int rndMax = Convert.ToInt32(dRow["specialcast_rnd_max"]); dRow = null; string prevCast = ""; while (StatusThingy) { string Cast = ""; int RND = new Random().Next(rndMin, rndMax + 1); if (emitter == "cam1") // User camera system { switch (RND) { case 1: int roomUID = getRandomRoomIdentifier(); if (roomUID != -1) Cast = "targetcamera " + roomUID; break; case 2: Cast = "setcamera 1"; break; case 3: Cast = "setcamera 2"; break; default: roomUID = getRandomRoomIdentifier(); if (roomUID != -1) Cast = "targetcamera " + roomUID; break; } } else if (emitter == "sf") // Flashing dancetiles system Cast = RND.ToString(); else if (emitter == "lamp") // Discolights system Cast = "setlamp " + RND; if (Cast == "") break; if (Cast != prevCast) // Cast is not the same as previous cast { sendSpecialCast(emitter, Cast); prevCast = Cast; } Thread.Sleep(Interval); } } catch { } } #endregion internal void Crash() { try { #region User kicking try { foreach (virtualRoomUser roomUser in _Users.Values) { roomUser.User.sendData("@R"); roomUser.User.statusManager.Clear(); roomUser.User.statusManager = null; roomUser.User._roomID = 0; roomUser.User._inPublicroom = false; roomUser.User._ROOMACCESS_PRIMARY_OK = false; roomUser.User._ROOMACCESS_SECONDARY_OK = false; roomUser.User._isOwner = false; roomUser.User._hasRights = false; roomUser.User.Room = null; roomUser.User.roomUser = null; if (roomUser.User._tradePartnerRoomUID != -1) roomUser.User.abortTrade(true); } } catch { } foreach (virtualBot roomBot in _Bots.Values) roomBot.Kill(); foreach (virtualPet roomPet in _Pets.Values) roomPet.Kill(); _Users.Clear(); _Bots.Clear(); _Pets.Clear(); #endregion _statusUpdates = null; if (isPublicroom == false) { floorItemManager.Clear(); wallItemManager.Clear(); } else { CycleThread = false; } roomManager.removeRoom(this.roomID); StatusThingy = false; } catch { } } #region Private classes private class furnitureStack { private int[] _itemIDs; internal furnitureStack() { _itemIDs = new int[20]; } internal void Add(int itemID) { for (int i = 0; i < 20; i++) { if (_itemIDs[i] == 0) { _itemIDs[i] = itemID; return; } } } internal void Remove(int itemID) { for (int i = 0; i < 20; i++) if (_itemIDs[i] == itemID) { _itemIDs[i] = 0; break; } int g = 0; int[] j = new int[20]; for (int i = 0; i < 20; i++) if (_itemIDs[i] > 0) { j[g] = _itemIDs[i]; g++; } _itemIDs = j; } internal int topItemID() { for (int i = 0; i < 20; i++) if (_itemIDs[i] == 0) return _itemIDs[i - 1]; return 0; } internal int bottomItemID() { return _itemIDs[0]; } internal int getAboveItemID(int aboveID) { for (int i = 0; i < 20; i++) if (_itemIDs[i] == aboveID) return _itemIDs[i + 1]; return 0; } internal int getBelowItemID(int belowID) { for (int i = 0; i < 20; i++) if (_itemIDs[i] == belowID) return _itemIDs[i - 1]; return 0; } internal bool Contains(int itemID) { foreach (int i in _itemIDs) if (i == itemID) return true; return false; } internal int Count { get { int j = 0; for (int i = 0; i < 20; i++) { if (_itemIDs[i] > 0) j++; else return j; } return j; } } } private class magicTile { internal string toMode; internal string toStatus; internal int toID; internal int toX; internal int toY; internal byte toZ; internal int toH; internal magicTile(string s4, string s5, int i6, int i7, int i8, byte b9, int i10) { toMode = s4; toStatus = s5; toID = i6; toX = i7; toY = i8; toZ = b9; toH = i10; } } #endregion } }