namespace Holo.Virtual.Rooms.Games { using Holo; using Holo.Virtual.Rooms.Pathfinding; using Ion.Storage; using System; using System.Collections.ObjectModel; using System.Data; using System.Text; using System.Threading; internal class Game { private bbTileColor[,] bbTColor; private bbTileState[,] bbTState; private bool[,] Blocked; private int bX; private int bY; internal int[] enabledPowerups; private byte[,] Height; internal string Heightmap; internal int ID; internal bool isBattleBall; private int leftCountdownSeconds; internal int leftTime; internal gameLobby Lobby; internal int mapID; internal string Name; internal gamePlayer Owner; internal gameState State; internal Collection Subviewers; internal Collection[] Teams; internal int totalTime; private Thread updateHandler; internal Game(gameLobby Lobby, int ID, string Name, int mapID, int teamAmount, int[] enabledPowerups, gamePlayer Owner) { this.Subviewers = new Collection(); this.leftCountdownSeconds = Config.Game_Countdown_Seconds; this.Lobby = Lobby; this.ID = ID; this.Name = Name; this.mapID = mapID; this.Owner = Owner; this.enabledPowerups = enabledPowerups; this.totalTime = Config.Game_BattleBall_gameLength_Seconds; this.leftTime = Config.Game_BattleBall_gameLength_Seconds; this.isBattleBall = true; this.Teams = new Collection[teamAmount]; for (int i = 0; i < teamAmount; i++) { this.Teams[i] = new Collection(); } } internal Game(gameLobby Lobby, int ID, string Name, int mapID, int teamAmount, int totalTime, gamePlayer Owner) { this.Subviewers = new Collection(); this.leftCountdownSeconds = Config.Game_Countdown_Seconds; this.Lobby = Lobby; this.ID = ID; this.Name = Name; this.mapID = mapID; this.Owner = Owner; this.totalTime = totalTime; this.leftTime = totalTime; this.isBattleBall = false; this.Teams = new Collection[teamAmount]; for (int i = 0; i < teamAmount; i++) { this.Teams[i] = new Collection(); } } internal void Abort() { try { this.updateHandler.Abort(); } catch { } string Data = "CmH"; for (int i = 0; i < this.Teams.Length; i++) { foreach (gamePlayer Member in this.Teams[i]) { if (Member.User != null) { if (this.State == gameState.Waiting) { Member.User.sendData(Data); } Member.User.gamePlayer = null; } } } foreach (gamePlayer subViewer in this.Subviewers) { if (subViewer.User != null) { if (this.State == gameState.Waiting) { subViewer.User.sendData(Data); } subViewer.User.gamePlayer = null; } } } private void countDownTicker() { while (this.leftCountdownSeconds > 0) { this.leftCountdownSeconds--; Thread.Sleep(0x3e8); } using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { for (int i = 0; i < this.Teams.Length; i++) { foreach (gamePlayer Player in this.Teams[i]) { Player.User._Tickets -= 2; Player.User.sendData("A|" + Player.User._Tickets); dbClient.runQuery(string.Concat(new object[] { "UPDATE users SET tickets = '", Player.User._Tickets, "' WHERE id = '", Player.User.userID, "' LIMIT 1" })); } } } this.updateHandler = new Thread(new ThreadStart(this.updateLoop)); this.updateHandler.Start(); this.sendData("Cw" + Encoding.encodeVL64(this.totalTime)); } internal string getMap() { StringBuilder Setup = new StringBuilder(); if (this.isBattleBall) { Setup.Append("I" + Encoding.encodeVL64(this.leftCountdownSeconds) + Encoding.encodeVL64(Config.Game_Countdown_Seconds) + "H" + Encoding.encodeVL64(this.bX) + Encoding.encodeVL64(this.bY)); for (int y = 0; y < this.bY; y++) { for (int x = 0; x < this.bX; x++) { Setup.Append(Encoding.encodeVL64((int) this.bbTColor[x, y]) + Encoding.encodeVL64((int) this.bbTState[x, y])); } } Setup.Append("IH"); } else { Setup.Append("holo.cast.not_finished"); } return Setup.ToString(); } internal string getPlayers() { StringBuilder Setup = null; StringBuilder Helper = new StringBuilder(); Random RND = new Random(DateTime.Now.Millisecond * this.totalTime); if (this.isBattleBall) { int p = 0; for (int i = 0; i < this.Teams.Length; i++) { foreach (gamePlayer Player in this.Teams[i]) { Out.WriteLine(Player.roomUID + "!"); Helper.Append(string.Concat(new object[] { "H", Encoding.encodeVL64(p), Encoding.encodeVL64(Player.X), Encoding.encodeVL64(Player.Y), Encoding.encodeVL64(Player.H), Encoding.encodeVL64(Player.Z), "HM", Player.User._Username, Convert.ToChar(2), Player.User._Mission, Convert.ToChar(2), Player.User._Figure, Convert.ToChar(2), Player.User._Sex, Convert.ToChar(2), Encoding.encodeVL64(Player.teamID), Encoding.encodeVL64(Player.roomUID) })); p++; } } Setup = new StringBuilder("I" + Encoding.encodeVL64(this.leftCountdownSeconds) + Encoding.encodeVL64(Config.Game_Countdown_Seconds) + Encoding.encodeVL64(p)); Setup.Append(Helper.ToString()); Helper = null; Setup.Append(Encoding.encodeVL64(this.bX) + Encoding.encodeVL64(this.bY)); for (int y = 0; y < this.bY; y++) { for (int x = 0; x < this.bX; x++) { Setup.Append(Encoding.encodeVL64((int) this.bbTColor[x, y]) + Encoding.encodeVL64((int) this.bbTState[x, y])); } } Setup.Append("IH"); } else { Setup.Append("holo.cast.not_finished"); } return Setup.ToString(); } private Coord[] getSurfaceTiles(Coord Start) { return null; } internal void movePlayer(gamePlayer Player, int fromTeamID, int toTeamID) { try { if (fromTeamID != -1) { this.Teams[fromTeamID].Remove(Player); } if (toTeamID != -1) { if (!this.Teams[toTeamID].Contains(Player)) { this.Teams[toTeamID].Add(Player); } Player.teamID = toTeamID; } else { this.Teams[Player.teamID].Remove(Player); Player.User.gamePlayer = null; } this.sendData("Ci" + this.Sub); } catch { } } internal void sendData(string Data) { for (int i = 0; i < this.Teams.Length; i++) { foreach (gamePlayer Member in this.Teams[i]) { Member.sendData(Data); } } if (this.State == gameState.Waiting) { foreach (gamePlayer subViewer in this.Subviewers) { subViewer.sendData(Data); } } } internal void startGame() { DatabaseClient dbClient; this.State = gameState.Started; foreach (gamePlayer subViewer in this.Subviewers) { subViewer.sendData(this.Sub); } using (dbClient = Eucalypt.dbManager.GetClient()) { this.Heightmap = dbClient.getString(string.Concat(new object[] { "SELECT heightmap FROM games_maps WHERE type = '", this.Lobby.Type, "' AND id = '", this.mapID, "'" })); } string[] _H = this.Heightmap.Split(new char[] { Convert.ToChar(13) }); this.bX = _H[0].Length; this.bY = _H.Length - 1; string[] _T = null; if (this.isBattleBall) { this.bbTState = new bbTileState[this.bX, this.bY]; this.bbTColor = new bbTileColor[this.bX, this.bY]; using (dbClient = Eucalypt.dbManager.GetClient()) { _T = dbClient.getString("SELECT bb_tilemap FROM games_maps WHERE type = 'bb' AND id = '" + this.mapID + "'").Split(new char[] { Convert.ToChar(13) }); } } this.Height = new byte[this.bX, this.bY]; this.Blocked = new bool[this.bX, this.bY]; for (int y = 0; y < this.bY; y++) { for (int x = 0; x < this.bX; x++) { string q = _H[y].Substring(x, 1); if (q == "x") { this.Blocked[x, y] = true; if (this.isBattleBall) { this.bbTColor[x, y] = bbTileColor.Disabled; this.bbTState[x, y] = bbTileState.Sealed; } } else { this.Height[x, y] = Convert.ToByte(q); if (this.isBattleBall) { if (_T[y].Substring(x, 1) == "1") { this.bbTColor[x, y] = bbTileColor.Default; } else { this.bbTColor[x, y] = bbTileColor.Disabled; this.bbTState[x, y] = bbTileState.Sealed; } } } } } int j = 0; for (int i = 0; i < this.Teams.Length; i++) { if (this.Teams[i].Count != 0) { DataRow dRow; using (dbClient = Eucalypt.dbManager.GetClient()) { dRow = dbClient.getRow(string.Concat(new object[] { "SELECT x,y,z FROM games_maps_playerspawns WHERE type = '", this.Lobby.Type, "' AND mapid = '", this.mapID, "' AND teamid = '", i, "'" })); } int spawnX = Convert.ToInt32(dRow["x"]); int spawnY = Convert.ToInt32(dRow["y"]); byte spawnZ = Convert.ToByte(dRow["z"]); bool Flip = false; foreach (gamePlayer Player in this.Teams[i]) { Player.roomUID = j; Label_047B: try { while (this.Blocked[spawnX, spawnY]) { switch (spawnZ) { case 0: case 2: if (Flip) { spawnX--; } else { spawnX++; } goto Label_047A; case 4: case 6: if (Flip) { spawnY--; } else { spawnY++; } break; } Label_047A:; } Flip = !Flip; } catch { Flip = !Flip; goto Label_047B; } this.Blocked[spawnX, spawnY] = true; Player.X = spawnX; Player.Y = spawnY; Player.Z = spawnZ; Player.H = this.Height[spawnX, spawnY]; Player.goalX = -1; Player.enteringGame = true; j++; Out.WriteLine(string.Concat(new object[] { "Assigned spawnpoint [", spawnX, ",", spawnY, "] to player [", j, ", team id: ", Player.teamID, "]" })); } } } this.sendData("Cq" + Encoding.encodeVL64(-1)); new Eucalypt.commonDelegate(this.countDownTicker).BeginInvoke(null, null); } internal bool teamHasSpace(int teamID) { try { int m = 0; switch (this.Teams.Length) { case 2: m = 6; break; case 3: m = 4; break; case 4: m = 3; break; } return (this.Teams[teamID].Count < m); } catch { return false; } } private void updateLoop() { if (this.isBattleBall) { int teamAmount = this.Teams.Length; int[] teamScores = new int[teamAmount]; bool subtrSecond = false; int activeTeamAmount = 0; int i = 0; while (i < teamAmount) { if (this.Teams[i].Count > 0) { activeTeamAmount++; } else { teamScores[i] = -1; } i++; } Random RND = new Random(DateTime.Now.Millisecond * teamAmount); while (this.leftTime > 0) { int[] Amounts = new int[3]; StringBuilder Players = new StringBuilder(); StringBuilder updatedTiles = new StringBuilder(); StringBuilder Movements = new StringBuilder(); i = 0; while (i < teamAmount) { foreach (gamePlayer Player in this.Teams[i]) { Players.Append("H" + Encoding.encodeVL64(Player.roomUID) + Encoding.encodeVL64(Player.X) + Encoding.encodeVL64(Player.Y) + Encoding.encodeVL64(Player.H) + Encoding.encodeVL64(Player.Z) + "HM"); if (Player.bbColorTile) { Player.bbColorTile = false; updatedTiles.Append(Encoding.encodeVL64(Player.X) + Encoding.encodeVL64(Player.Y) + Encoding.encodeVL64((int) this.bbTColor[Player.X, Player.Y]) + Encoding.encodeVL64((int) this.bbTState[Player.X, Player.Y])); Amounts[1]++; } if (Player.goalX != -1) { Coord Next = gamePathfinder.getNextStep(Player.X, Player.Y, Player.goalX, Player.goalY); if ((Next.X != -1) && !this.Blocked[Next.X, Next.Y]) { Amounts[2]++; Movements.Append("J" + Encoding.encodeVL64(Player.roomUID) + Encoding.encodeVL64(Next.X) + Encoding.encodeVL64(Next.Y)); if ((Next.X == Player.goalX) && (Next.Y == Player.goalY)) { Player.goalX = -1; } this.Blocked[Player.X, Player.Y] = false; this.Blocked[Next.X, Next.Y] = true; Player.Z = Rotation.Calculate(Player.X, Player.Y, Next.X, Next.Y); Player.X = Next.X; Player.Y = Next.Y; Player.H = this.Height[Next.X, Next.Y]; if (this.bbTState[Next.X, Next.Y] != bbTileState.Sealed) { if (this.bbTColor[Next.X, Next.Y] == Player.teamID) { this.bbTState[Next.X, Next.Y]++; } else { this.bbTState[Next.X, Next.Y] = bbTileState.Touched; this.bbTColor[Next.X, Next.Y] = (bbTileColor) Player.teamID; } int extraPoints = 0; switch (((int) this.bbTState[Next.X, Next.Y])) { case 1: extraPoints = activeTeamAmount; break; case 2: extraPoints = activeTeamAmount * 3; break; case 3: extraPoints = activeTeamAmount * 5; break; case 4: extraPoints = activeTeamAmount * 7; break; } teamScores[Player.teamID] += extraPoints; Player.Score += extraPoints; Player.bbColorTile = true; } } else { Player.goalX = -1; } } Amounts[0]++; } i++; } string scoreString = "H" + Encoding.encodeVL64(teamAmount); i = 0; while (i < teamAmount) { scoreString = scoreString + Encoding.encodeVL64(teamScores[i]); i++; } this.sendData("Ct" + Encoding.encodeVL64(Amounts[0]) + Players.ToString() + Encoding.encodeVL64(Amounts[1]) + updatedTiles.ToString() + scoreString + "I" + Encoding.encodeVL64(Amounts[2]) + Movements.ToString()); if (subtrSecond) { this.leftTime--; } subtrSecond = !subtrSecond; Thread.Sleep(470); } this.State = gameState.Ended; StringBuilder Scores = new StringBuilder("Cx" + Encoding.encodeVL64(Config.Game_scoreWindow_restartGame_Seconds) + Encoding.encodeVL64(teamAmount)); for (i = 0; i < teamAmount; i++) { int memberAmount = this.Teams[i].Count; if (memberAmount > 0) { Scores.Append(Encoding.encodeVL64(memberAmount)); using (DatabaseClient dbClient = Eucalypt.dbManager.GetClient()) { foreach (gamePlayer Player in this.Teams[i]) { Scores.Append(Encoding.encodeVL64(Player.roomUID)); if (Player.User != null) { dbClient.runQuery(string.Concat(new object[] { "UPDATE users SET bb_playedgames = bb_playedgames + 1,bb_totalpoints = bb_totalpoints + ", Player.Score, " WHERE id = '", Player.User.userID, "' LIMIT 1" })); Scores.Append(Player.User._Username + Convert.ToChar(2)); } else { Scores.Append("M"); } Scores.Append(Encoding.encodeVL64(Player.Score)); } } Scores.Append(Encoding.encodeVL64(teamScores[i])); } else { Scores.Append("M"); } } this.sendData(Scores.ToString()); } } internal bool Launchable { get { int activeTeamCount = 0; for (int i = 0; i < this.Teams.Length; i++) { if (this.Teams[i].Count != 0) { activeTeamCount++; } } return (activeTeamCount > 1); } } internal string Sub { get { int i; StringBuilder Entry = new StringBuilder(Encoding.encodeVL64((int) this.State)); if (this.Launchable) { Entry.Append("I"); } else { Entry.Append("H"); } Entry.Append(string.Concat(new object[] { this.Name, Convert.ToChar(2), Encoding.encodeVL64(this.Owner.roomUID), this.Owner.User._Username, Convert.ToChar(2) })); if (!this.isBattleBall) { Entry.Append(Encoding.encodeVL64(this.totalTime)); } Entry.Append(Encoding.encodeVL64(this.mapID) + Encoding.encodeVL64(0) + Encoding.encodeVL64(this.Teams.Length)); for (i = 0; i < this.Teams.Length; i++) { Entry.Append(Encoding.encodeVL64(this.Teams[i].Count)); foreach (gamePlayer Member in this.Teams[i]) { Entry.Append(Encoding.encodeVL64(Member.roomUID) + Member.User._Username + Convert.ToChar(2)); } } if (this.isBattleBall) { for (i = 0; i < this.enabledPowerups.Length; i++) { Entry.Append(this.enabledPowerups[i] + ","); } Entry.Append("9" + Convert.ToChar(2)); } else { Entry.Append(Encoding.encodeVL64(this.leftTime) + Encoding.encodeVL64(this.mapID)); } return Entry.ToString(); } } private enum bbTileColor { Blue = 1, Default = -1, Disabled = -2, Green = 3, Red = 0, Yellow = 2 } private enum bbTileState { Default, Touched, Clicked, Pressed, Sealed } internal enum gameState { Waiting, Started, Ended } } }