/* Thor Server Project Copyright 2008 Joe Hegarty This file is part of The Thor Server Project. The Thor Server Project is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The Thor Server Project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with The Thor Server Project. If not, see . */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Timers; using ThorServer.Game.Furni; using ThorServer.Core; using ThorServer.Utilities; using ThorServer.Game.Rooms; using ThorServer.Game.Rooms.Pathfinding; namespace ThorServer.Game.Rooms.Interactor { public partial class RoomInteractor { private void GenerateMaps() { //Get information about the default heightmap string[] lines = mDefaultHeightmap.Split(Convert.ToChar(13)); int y = lines.Length; int x = lines[0].Length; //Client heightmap string[,] theMap = new string[x, y]; string[,] theOldMap = new string[x, y]; //Pathfinding info byte[,] theMatrix = new byte[SpecialMath.NearestSuperiorPowerOfTwo(x), SpecialMath.NearestSuperiorPowerOfTwo(y)]; //Heightmap float[,] hMap = new float[x, y]; //Redirect map for beds Point[,] redirectMap = new Point[x, y]; //Rollers bool enableRollers = false; //Translate the default map into data thor can understand for (int line = 0; line < y; line++) { for (int chr = 0; chr < x; chr++) { float tileZ = 0; string tileValue = lines[line].Substring(chr, 1); theMap[chr, line] = tileValue; if (float.TryParse(tileValue, out tileZ)) { theMatrix[chr, line] = 1; hMap[chr, line] = tileZ; } else { theMatrix[chr, line] = 0; } redirectMap[chr, line] = new Point(chr, line); } } theOldMap = theMap; //Loop over the furniture and update heightmap and pathfinder foreach (FurniInfo info in mFloorFurni) { //If this is the highest item on the tile, set the heightmap if (info.TotalHeight > hMap[info.PosX, info.PosY]) hMap[info.PosX, info.PosY] = info.TotalHeight; //If the item isn't pathable, block the tile if (!info.Flags.CanPath) theMatrix[info.PosX, info.PosY] = 0; //If the item isn't stackable or interactable, we should tell the client if (!info.Flags.CanStackOn && !info.PublicFurni && !info.Flags.CanSit && !info.Flags.CanLay && !info.Flags.CanStand) if (hMap[info.PosX, info.PosY] == 0) { theMap[info.PosX, info.PosY] = "A"; } //If the item is a roller, set the weight higher so users avoid walking on them if (info.Flags.IsRoller && theMatrix[info.PosX, info.PosY] != 0) theMatrix[info.PosX, info.PosY] = 5; //Get a list of tiles this furniture currently resides on Dictionary pointList = GetAffectedTiles(info); //Loop over the affected tiles and essentially do what we did above foreach (AffectedTile point in pointList.Values) { //If this is the highest item on the tile, set the heightmap if (info.TotalHeight > hMap[point.X, point.X]) hMap[point.X, point.Y] = info.TotalHeight; //If the item isn't pathable, block the tile if (!info.Flags.CanPath) theMatrix[point.X, point.Y] = 0; //If the item isn't stackable or interactable, we should tell the client if (!info.Flags.CanStackOn && !info.PublicFurni && !info.Flags.CanSit && !info.Flags.CanLay && !info.Flags.CanStand) if (hMap[point.X, point.Y] == 0) { theMap[point.X, point.Y] = "A"; } //If this is a bed, we need to redirect the tile to the top if (info.Flags.TopRow) { if (info.PosRotation == 0 || info.PosRotation == 4) { redirectMap[point.X, point.Y].Y = info.PosY; } if (info.PosRotation == 2 || info.PosRotation == 6) { redirectMap[point.X, point.Y].X = info.PosX; } } } } //Second loop, to handle special exceptions and client heightmap generation foreach (FurniInfo info in mFloorFurni) { //Is this furniture at the top of the tile? if (info.TotalHeight == hMap[info.PosX, info.PosY]) { //Can we stack on it? If so, the client tile height should be equal to it if (info.Flags.CanStackOn) { theMap[info.PosX, info.PosY] = ((int)Math.Round(info.TotalHeight)).ToString(); } } //Get a list of tiles this furniture currently resides on Dictionary pointList = GetAffectedTiles(info); //Loop over the affected tiles and essentially do what we did above foreach (AffectedTile point in pointList.Values) { //Is this furniture at the top of the tile? if (info.TotalHeight == hMap[point.X, point.Y]) { //Can we stack on it? If so, the client tile height should be equal to it if (info.Flags.CanStackOn) { theMap[point.X, point.Y] = ((int)Math.Round(info.TotalHeight)).ToString(); } } } //Is it a door divder? If it is, update the pathfinder with the correct value if (info.VarType == FurniInfo.VarTypes.DoorDivider) { theMatrix[info.PosX, info.PosY] = 0; //Open ? if (info.FurniVar == "O") theMatrix[info.PosX, info.PosY] = 1; } //Is it a chair? If it is, drop the tile to the lowest possible if (info.Flags.CanSit && !info.PublicFurni) { hMap[info.PosX, info.PosY] = int.Parse(theOldMap[info.PosX, info.PosY]); //Get a list of tiles this furniture currently resides on pointList = GetAffectedTiles(info); //Loop over the affected tiles and essentially do what we did above foreach (AffectedTile point in pointList.Values) { hMap[point.X, point.Y] = int.Parse(theOldMap[info.PosX, info.PosY]); } } } //Do one final loop to handle rollers foreach (FurniInfo info in mFloorFurni) { //Roller ? if (info.Flags.IsRoller) { enableRollers = true; theMap[info.PosX, info.PosY] = theOldMap[info.PosX, info.PosY]; } } //Update the real maps! mClientMap = theMap; mMatrix = theMatrix; mHeightMap = hMap; mRedirectMap = redirectMap; mHasRollers = enableRollers; } private string CreatePlaintextClientHeightmap() { StringBuilder sb = new StringBuilder(); for (int j = 0; j <= mClientMap.GetUpperBound(1); j++) { for (int i = 0; i <= mClientMap.GetUpperBound(0); i++) { sb.Append(mClientMap[i, j]); } sb.Append(Convert.ToChar(13)); } return sb.ToString(); } private bool InteractiveTile(int X, int Y) { List furni = GetFurniObjects(X, Y); if (furni != null) { foreach (FurniInfo info in furni) { if (info.Flags.CanSit || info.Flags.CanLay || info.Flags.CanStand) { return true; } } } return false; } private Dictionary GetAffectedTiles(FurniInfo info) { return GetAffectedTiles(info.L, info.W, info.PosX, info.PosY, info.PosRotation); } private Dictionary GetAffectedTiles(int FurniL, int FurniW, int PosX, int PosY, int PosRotation) { int x = 0; Dictionary pointList = new Dictionary(); if (FurniL > 1) { if (PosRotation == 0 || PosRotation == 4) //Y Axis + W { for (int i = 1; i < FurniL; i++) { pointList.Add(x++, new AffectedTile(PosX, PosY + i, i)); for (int j = 1; j < FurniW; j++) { pointList.Add(x++, new AffectedTile(PosX + j, PosY + i, (i < j) ? j : i)); } } } else if (PosRotation == 2 || PosRotation == 6) //X Axis + W { for (int i = 1; i < FurniL; i++) { pointList.Add(x++, new AffectedTile(PosX + i, PosY, i)); for (int j = 1; j < FurniW; j++) { pointList.Add(x++, new AffectedTile(PosX + i, PosY + j, (i < j) ? j : i)); } } } } if (FurniW > 1) { if (PosRotation == 0 || PosRotation == 4) //X Axis + L { for (int i = 1; i < FurniW; i++) { pointList.Add(x++, new AffectedTile(PosX + i, PosY, i)); for (int j = 1; j < FurniL; j++) { pointList.Add(x++, new AffectedTile(PosX + i, PosY + j, (i < j) ? j : i)); } } } else if (PosRotation == 2 || PosRotation == 6) //Y Axis + L { for (int i = 1; i < FurniW; i++) { pointList.Add(x++, new AffectedTile(PosX, PosY + i, i)); for (int j = 1; j < FurniL; j++) { pointList.Add(x++, new AffectedTile(PosX + j, PosY + i, (i < j) ? j : i)); } } } } return pointList; } public string ClientMap { get { return CreatePlaintextClientHeightmap(); } } public void FreeTile(int x, int y) { mPlayerMap[x, y] = false; } private bool ValidTile(int X, int Y) { if (X < mHeightMap.GetLowerBound(0) || Y < mHeightMap.GetLowerBound(1)) return false; if (X > mHeightMap.GetUpperBound(0) || Y > mHeightMap.GetUpperBound(1)) return false; return true; } private bool TileCheck(int X, int Y, byte[,] matrix) { if (!ValidTile(X, Y)) return false; bool badTile = false; if (matrix[X, Y] == 0) badTile = true; if (PlayerCheck(X, Y)) badTile = true; return !badTile; } private bool PlayerCheck(int X, int Y) { if (!ValidTile(X, Y)) return true; if (mPlayerMap[X, Y] == true) return true; return false; } public bool TilesTouching(int X1, int Y1, int X2, int Y2) { if (!(Math.Abs(X1 - X2) > 1 || Math.Abs(Y1 - Y2) > 1)) return true; if (X1 == X2 && Y1 == Y2) return true; return false; } } }