<NME> TileMap.cs <BEF> using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; using System.Text; using System.IO; /// <summary> /// Tile map class for storing and accessing the tilemap and tile properties.. /// </summary> public class TileMap : Loader { //Raw Data public DataLoader.UWBlock lev_ark_block = new DataLoader.UWBlock();//Data containing tilemap. public DataLoader.UWBlock tex_ark_block = new DataLoader.UWBlock();//Data containing texture map public DataLoader.UWBlock ovl_ark_block = new DataLoader.UWBlock();//Data containing animation overlays //Tile Types for UW1 & 2 and SS1. Note the diag tiles are flipped around in SS1. public const short TILE_SOLID = 0; public const short TILE_OPEN = 1; public const short TILE_DIAG_SE = 2; public const short TILE_DIAG_SW = 3; public const short TILE_DIAG_NE = 4; public const short TILE_DIAG_NW = 5; public const short TILE_SLOPE_N = 6; public const short TILE_SLOPE_S = 7; public const short TILE_SLOPE_E = 8; public const short TILE_SLOPE_W = 9; public const short TILE_VALLEY_NW = 10; public const short TILE_VALLEY_NE = 11; public const short TILE_VALLEY_SE = 12; public const short TILE_VALLEY_SW = 13; public const short TILE_RIDGE_SE = 14; public const short TILE_RIDGE_SW = 15; public const short TILE_RIDGE_NW = 16; public const short TILE_RIDGE_NE = 17; /// <summary> /// The tile map size along the x axis /// </summary> public const short TileMapSizeX = 63; //0 to 63 /// <summary> /// The tile map size along the y axis. /// </summary> public const short TileMapSizeY = 63; //0 to 63 /// <summary> /// Locaton X and Y of the object storage tile location where non map objects are kept. /// </summary> public const short ObjectStorageTile = 99; public const short SURFACE_FLOOR = 1; public const short SURFACE_CEIL = 2; public const short SURFACE_WALL = 3; public const short SURFACE_SLOPE = 4; public const short SLOPE_BOTH_PARALLEL = 0; public const short SLOPE_BOTH_OPPOSITE = 1; public const short SLOPE_FLOOR_ONLY = 2; public const short SLOPE_CEILING_ONLY = 3; //Visible faces indices. Used in sorting tile surface visiblity. public const short vTOP = 0; public const short vEAST = 1; public const short vBOTTOM = 2; public const short vWEST = 3; public const short vNORTH = 4; public const short vSOUTH = 5; //BrushFaces const short fSELF = 128; const short fCEIL = 64; const short fNORTH = 32; const short fSOUTH = 16; const short fEAST = 8; const short fWEST = 4; const short fTOP = 2; const short fBOTTOM = 1; public const int UW1_TEXTUREMAPSIZE = 64; public const int UW2_TEXTUREMAPSIZE = 70; public const int UWDEMO_TEXTUREMAPSIZE = 63; public const int UW1_NO_OF_LEVELS = 9; public const int UW2_NO_OF_LEVELS = 80; /// <summary> /// The ceiling texture for this level /// </summary> public short UWCeilingTexture; /// <summary> /// Animation overlay. Controls how long an animated effect appears for. /// </summary> public struct Overlay { public int header; public int link; public int duration; public int tileX; public int tileY; }; /// <summary> /// Lists of overlays for controlling animated items. /// </summary> public Overlay[] Overlays = new Overlay[64]; public short thisLevelNo; //The number of this level public short UW_CEILING_HEIGHT; public short CEILING_HEIGHT; public short SHOCK_CEILING_HEIGHT; /// <summary> /// The texture indices for the current map. /// </summary> public short[] texture_map = new short[272]; /// <summary> /// Tile info storage class /// </summary> public TileInfo[,] Tiles = new TileInfo[TileMap.TileMapSizeX + 1, TileMap.TileMapSizeY + 1]; /// <summary> /// The current tile X that the player is in /// </summary> public static short visitTileX; /// <summary> /// The current tile Y that the player is in. /// </summary> public static short visitTileY; /// The tile X that the player was in the previous frame /// </summary> public static short visitedTileX; /// <summary> /// The current tile Y that the player was in the previous frame /// </summary> public static short visitedTileY; /// <summary> /// Reference to the objects list for this level. /// </summary> public ObjectLoader LevelObjects { get { return GameWorldController.instance.objectList[thisLevelNo]; } } public TileMap(short NewLevelNo) { thisLevelNo = NewLevelNo; } /// <summary> /// Checks to see if the tile at a specified location is within the valid game world. (eg is rendered and is not a solid). /// Assumes the map is positioned at 0,0,0 /// </summary> /// <returns><c>true</c>, if tile was valided, <c>false</c> otherwise.</returns> /// <param name="location">Location.</param> public bool ValidTile(Vector3 location) { int tileX = (int)(location.x / 1.2f); int tileY = (int)(location.y / 1.2f); if ((tileX > TileMap.TileMapSizeX) || (tileX < 0) || (tileY > TileMap.TileMapSizeY) || (tileY < 0)) {//Location is outside the map return false; } int tileType = GetTileType(tileX, tileY); bool isRendered = GetTileRender(tileX, tileY); return ((tileType != TILE_SOLID) && (isRendered)); } /// <summary> /// Validates the tile to see if it is within the range of tiles. /// </summary> /// <returns><c>true</c>, if tile was valided, <c>false</c> otherwise.</returns> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> public static bool ValidTile(int tileX, int tileY) { return (((tileX >= 0) && (tileX <= TileMapSizeX)) && ((tileY >= 0) && (tileY <= TileMapSizeY))); } /// <summary> /// Tells if the tile is one of the square open types /// </summary> /// <returns><c>true</c>, if tile open was ised, <c>false</c> otherwise.</returns> /// <param name="TileType">Tile type.</param> public static bool isTileOpen(int TileType) { switch (TileType) { case TILE_OPEN: case TILE_SLOPE_N: case TILE_SLOPE_S: case TILE_SLOPE_E: case TILE_SLOPE_W: { return true; } default: { return false; } } } /// <summary> /// Gets the height of the floor for the specified tile. /// </summary> /// <returns>The floor height.</returns> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> public int GetFloorHeight(int tileX, int tileY) { if (ValidTile(tileX, tileY)) { return Tiles[tileX, tileY].floorHeight; } else { // Debug.Log("invalid tile for height at " + tileX + "," + tileY); return 0; } } /// <summary> /// Gets the height of the ceiling. Will always be the same value in UW1/2 varies in SHOCK. /// </summary> /// <returns>The ceiling height.</returns> /// <param name="LevelNo">Level no.</param> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> public int GetCeilingHeight(int tileX, int tileY) { return Tiles[tileX, tileY].ceilingHeight; } /// <summary> /// Sets the height of the floor. /// </summary> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> /// <param name="newHeight">New height.</param> public void SetFloorHeight(int tileX, int tileY, short newHeight) { Tiles[tileX, tileY].floorHeight = newHeight; } /// <summary> /// Sets the height of the ceiling. /// </summary> /// <param name="LevelNo">Level no.</param> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> /// <param name="newHeight">New height.</param> public void SetCeilingHeight(int tileX, int tileY, short newHeight) { //Debug.Log ("ceil :" + newHeight + " was " + CeilingHeight[tileX,tileY]); Tiles[tileX, tileY].ceilingHeight = newHeight; } /// <summary> /// Gets the type of the tile. /// </summary> /// <returns>The tile type.</returns> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> public int GetTileType(int tileX, int tileY) { //if ((tileX>TileMap.TileMapSizeX) || (tileY>TileMap.TileMapSizeY) || (tileX<0) || (tileY<0)) if (!TileMap.ValidTile(tileX, tileY)) {//Assume out of bounds is solid return TILE_SOLID; } else { return Tiles[tileX, tileY].tileType; } } /// <summary> /// Gets the room region at the specified tile /// </summary> /// <returns>The room.</returns> /// <param name="TileX">Tile x.</param> /// <param name="tileY">Tile y.</param> public int GetRoom(int tileX, int tileY) { if (TileMap.ValidTile(tileX, tileY)) { return Tiles[tileX, tileY].roomRegion; } else { return 0; } } /// <summary> /// Gets the tile render state. /// </summary> /// <returns>The tile render.</returns> /// <param name="LevelNo">Level no.</param> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> private bool GetTileRender(int tileX, int tileY) { return Tiles[tileX, tileY].Render == true; } /// <summary> /// Gets the vector3 at the center of the tile specified. /// </summary> /// <returns>The tile vector.</returns> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> public Vector3 getTileVector(int tileX, int tileY) { return new Vector3( (((float)tileX) * 1.2f) + 0.6f, (float)GetFloorHeight(tileX, tileY) * 0.15f, (((float)tileY) * 1.2f) + 0.6f ); } /// <summary> /// Gets the vector3 at the center of the tile specified. /// </summary> /// <returns>The tile vector.</returns> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> public Vector3 getTileVector(float tileX, float tileY) { return getTileVector((int)tileX, (int)tileY); } /// <summary> /// Gets the vector3 at the center of the tile specified. /// </summary> /// <returns>The tile vector.</returns> /// <param name="tileX">Tile x.</param> /// <param name="tileY">Tile y.</param> public Vector3 getTileVector(int tileX, int tileY, float zpos) { return new Vector3( (((float)tileX) * 1.2f) + 0.6f, zpos, (((float)tileY) * 1.2f) + 0.6f ); } public bool BuildTileMapUW(int levelNo, DataLoader.UWBlock lev_ark, DataLoader.UWBlock tex_ark, DataLoader.UWBlock ovl_ark) { long address_pointer = 0; short CeilingTexture = 0; UW_CEILING_HEIGHT = ((128 >> 2) * 8 >> 3); //Shifts the scale of the level. Idea borrowed from abysmal CEILING_HEIGHT = UW_CEILING_HEIGHT; BuildTextureMap(tex_ark, ref CeilingTexture, levelNo); this.UWCeilingTexture = CeilingTexture; for (short y = 0; y <= TileMap.TileMapSizeY; y++) { for (short x = 0; x <= TileMap.TileMapSizeX; x++) { int FirstTileInt = (int)DataLoader.getValAtAddress(lev_ark, (address_pointer + 0), 16); int SecondTileInt = (int)DataLoader.getValAtAddress(lev_ark, (address_pointer + 2), 16); Tiles[x, y] = new TileInfo(this, x, y); address_pointer = address_pointer + 4; } } SetTileMapWallFacesUW(); //if (OverlayAddress!=0) switch (_RES) { case GAME_UW1: { if (ovl_ark.DataLen != 0) {//read in the next 64 entries of length 6 bytes long OverlayAddress = 0; for (int overlayIndex = 0; overlayIndex < 64; overlayIndex++) { Overlays[overlayIndex].header = (int)DataLoader.getValAtAddress(ovl_ark, OverlayAddress, 16); Overlays[overlayIndex].link = (int)(DataLoader.getValAtAddress(ovl_ark, OverlayAddress, 16) >> 6) & 0x3ff; Overlays[overlayIndex].duration = (int)DataLoader.getValAtAddress(ovl_ark, OverlayAddress + 2, 16); Overlays[overlayIndex].tileX = (int)DataLoader.getValAtAddress(ovl_ark, OverlayAddress + 4, 8); Overlays[overlayIndex].tileY = (int)DataLoader.getValAtAddress(ovl_ark, OverlayAddress + 5, 8); if (Overlays[overlayIndex].link!=0) { // Debug.Log("Overlay at " + OverlayAddress // + " obj " + Overlays[overlayIndex].link // + " for " + Overlays[overlayIndex].duration // + " tile " + Overlays[overlayIndex].tileX + "," + Overlays[overlayIndex].tileY // + " header :" + Overlays[overlayIndex].header); } OverlayAddress += 6; } } break; } case GAME_UW2: { long OverlayAddress = 31752; for (int overlayIndex = 0; overlayIndex < 64; overlayIndex++) { if (OverlayAddress + 5 <= lev_ark.Data.GetUpperBound(0)) { Overlays[overlayIndex].header = (int)DataLoader.getValAtAddress(lev_ark, OverlayAddress, 16); Overlays[overlayIndex].link = (int)(DataLoader.getValAtAddress(lev_ark, OverlayAddress, 16)>> 6) & 0x3ff; Overlays[overlayIndex].duration = (int)DataLoader.getValAtAddress(lev_ark, OverlayAddress + 2, 16); Overlays[overlayIndex].tileX = (int)DataLoader.getValAtAddress(lev_ark, OverlayAddress + 4, 8); Overlays[overlayIndex].tileY = (int)DataLoader.getValAtAddress(lev_ark, OverlayAddress + 5, 8); if (Overlays[overlayIndex].link != 0) { // Debug.Log("Overlay at " + OverlayAddress // + " obj " + Overlays[overlayIndex].link // + " for " + Overlays[overlayIndex].duration // + " tile " + Overlays[overlayIndex].tileX + "," + Overlays[overlayIndex].tileY // + " header :" + Overlays[overlayIndex].header); } } OverlayAddress += 6; } break; } } return true; } /// <summary> /// Creates the tile map wall textures for each north, south, east and west faces /// </summary> /// <param name="x">The x coordinate.</param> /// <param name="y">The y coordinate.</param> public void SetTileMapWallFacesUW() { short x; short y; for (y = 0; y <= TileMap.TileMapSizeY; y++) { for (x = 0; x <= TileMap.TileMapSizeX; x++) { SetTileWallFacesUW(x, y); } } } /// <summary> /// Sets the tile wall faces for the selected tile /// </summary> /// <param name="x">The x coordinate.</param> /// <param name="y">The y coordinate.</param> public void SetTileWallFacesUW(short x, short y) { if (Tiles[x, y].tileType >= 0)//was just solid only. Note: If textures are all wrong it's probably caused here! { //assign it's north texture if (y < TileMap.TileMapSizeY) { Tiles[x, y].North = Tiles[x, y + 1].wallTexture; } else { Tiles[x, y].North = -1; } //assign it's southern if (y > 0) { Tiles[x, y].South = Tiles[x, y - 1].wallTexture; } else { Tiles[x, y].South = -1; } //it's east if (x < TileMap.TileMapSizeX) { Tiles[x, y].East = Tiles[x + 1, y].wallTexture; } else { Tiles[x, y].East = -1; } //assign it's West if (x > 0) { Tiles[x, y].West = Tiles[x - 1, y].wallTexture; } else { Tiles[x, y].West = -1; } } } public bool BuildTileMapShock(char[] archive_ark, int LevelNo) { long address_pointer = 4; //LevelInfo=new TileInfo[64,64]; //char[] archive_ark; //file data DataLoader.Chunk lev_ark; /* unsigned char *tmp_ark; unsigned char *sub_ark;*/ DataLoader.Chunk tex_ark; DataLoader.Chunk inf_ark; //Read in the archive. //if (!DataLoader.ReadStreamFile(filePath, out archive_ark)) //{ // return false; //} if (!DataLoader.LoadChunk(archive_ark, LevelNo * 100 + 4004, out inf_ark)) {//Read in the evel properties. return false; } //Process level properties (height c-space) int HeightUnits = (int)DataLoader.getValAtAddress(inf_ark.data, 16, 32); //Log2 value. The higher the value the lower the level height. if (HeightUnits > 3) //Any higher we lose data, { HeightUnits = 3; } //int cSpace = (int)DataLoader.getValAtAddress(inf_ark.data,24,32); //Per docs should return 1 on cyberspace. Does'nt appear to work. SHOCK_CEILING_HEIGHT = (short)(((256 >> HeightUnits) * 8 >> 3)); //Shifts the scale of the level. CEILING_HEIGHT = SHOCK_CEILING_HEIGHT; //long sizeV = getValAtAddress(inf_ark,0,32); //long sizeH = getValAtAddress(inf_ark,4,32); //long always6_1 = getValAtAddress(inf_ark,8,32); //long always6_2 = getValAtAddress(inf_ark,12,32); if (!DataLoader.LoadChunk(archive_ark, LevelNo * 100 + 4005, out lev_ark)) {//Read in the level tilemap data return false; } //Read the main level data in /* blockAddress =getShockBlockAddress(LevelNo*100+4005,archive_ark, ref chunkPackedLength,ref chunkUnpackedLength,ref chunkType); if (blockAddress == -1) {return false;} lev_ark=new char[chunkUnpackedLength]; //or 64*64*16 LoadShockChunk(blockAddress, chunkType, archive_ark, ref lev_ark,chunkPackedLength,chunkUnpackedLength); AddressOfBlockStart=0; address_pointer=0; */ if (!DataLoader.LoadChunk(archive_ark, LevelNo * 100 + 4007, out tex_ark)) {//Read in the level texture data return false; } //get the texture data from the archive.is never compressed? //AddressOfBlockStart = getShockBlockAddress(4007+ LevelNo*100, archive_ark, ref chunkPackedLength, ref chunkUnpackedLength,ref chunkType); //tex_ark = new char[chunkUnpackedLength]; address_pointer = 0; for (long k = 0; k < tex_ark.chunkUnpackedLength / 2; k++) { texture_map[k] = (short)DataLoader.getValAtAddress(tex_ark.data, address_pointer, 16); address_pointer = address_pointer + 2; //tmp_ark[AddressOfBlockStart+k]; } address_pointer = 0; //Reactor Map 0 (chunk 40xx) //Levels 1-9 Map L (chunk 4Lxx) //SHODAN c/space Map 10 (chunk 50xx) //Delta grove Map 11 (chunk 51xx) //Alpha grove Map 12 (chunk 52xx) //Beta grove Map 13 (chunk 53xx) //C/space L1-2 Map 14 (chunk 54xx) //C/space other Map 15 (chunk 55xx) for (int y = 0; y <= TileMap.TileMapSizeY; y++) { for (int x = 0; x <= TileMap.TileMapSizeX; x++) { //Read in the tile data Tiles[x, y] = new TileInfo(); Tiles[x, y].tileX = (short)x; Tiles[x, y].tileY = (short)y; Tiles[x, y].tileType = (short)lev_ark.data[address_pointer]; switch (Tiles[x, y].tileType) {//Need to swap some tile types around so that they conform to uw naming standards. case 4: { Tiles[x, y].tileType = 5; break; } case 5: { Tiles[x, y].tileType = 4; break; } case 7: { Tiles[x, y].tileType = 8; break; } case 8: { Tiles[x, y].tileType = 7; break; } } Tiles[x, y].indexObjectList = 0; Tiles[x, y].Render = true; Tiles[x, y].DimX = 1; Tiles[x, y].DimY = 1; Tiles[x, y].Grouped = false; for (int v = 0; v < 6; v++) { Tiles[x, y].VisibleFaces[v] = true; } /* word 6 contains 0-5 Wall texture (index into texture list) 6-10 Ceiling texture 11-15 Floor texture */ //Tiles[x,y].wallTexture = texture_map[(int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) & 0x3F]; Tiles[x, y].wallTexture = (short)(DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) & 0x3F); //Tiles[x,y].shockCeilingTexture = texture_map[((int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) >> 6) & 0x1F]; Tiles[x, y].shockCeilingTexture = (short)((DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) >> 6) & 0x1F); //Tiles[x,y].floorTexture = texture_map[((int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) >> 11) & 0x1F]; Tiles[x, y].floorTexture = (short)((DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) >> 11) & 0x1F); //Tiles[x,y].wallTexture = 270;//debug //Tiles[x,y].shockCeilingTexture = 273; Tiles[x, y].North = Tiles[x, y].wallTexture; Tiles[x, y].South = Tiles[x, y].wallTexture; Tiles[x, y].East = Tiles[x, y].wallTexture; Tiles[x, y].West = Tiles[x, y].wallTexture; //Water xTiles[x, y].isWater = false; //No swimming in shock. //Tiles[x, y].landRegion = 0; //Tiles[x, y].lavaRegion = 0; //Tiles[x, y].waterRegion = 0; Tiles[x, y].floorHeight = (short)((lev_ark.data[address_pointer + 1]) & 0x1F); Tiles[x, y].floorHeight = (short)(((Tiles[x, y].floorHeight << 3) >> HeightUnits) * 8 >> 3); //Shift it for varying height scales Tiles[x, y].ceilingHeight = (short)((lev_ark.data[address_pointer + 2]) & 0x1F); Tiles[x, y].ceilingHeight = (short)(((Tiles[x, y].ceilingHeight << 3) >> HeightUnits) * 8 >> 3); //Shift it for varying height scales Tiles[x, y].shockFloorOrientation = (short)(((lev_ark.data[address_pointer + 1]) >> 5) & 0x3); Tiles[x, y].shockCeilOrientation = (short)(((lev_ark.data[address_pointer + 2]) >> 5) & 0x3); //Need to know heights in various directions for alignments. //Will set these properly after loading levels. Tiles[x, y].shockNorthCeilHeight = Tiles[x, y].ceilingHeight; Tiles[x, y].shockSouthCeilHeight = Tiles[x, y].ceilingHeight; Tiles[x, y].shockEastCeilHeight = Tiles[x, y].ceilingHeight; Tiles[x, y].shockWestCeilHeight = Tiles[x, y].ceilingHeight; Tiles[x, y].TileSlopeSteepness = (short)(lev_ark.data[address_pointer + 3] & 0x0f); Tiles[x, y].TileSlopeSteepness = (short)(((Tiles[x, y].TileSlopeSteepness << 3) >> HeightUnits) * 8 >> 3); //Shift it for varying height scales if ((Tiles[x, y].TileSlopeSteepness == 0) && (Tiles[x, y].tileType >= 6))//If a sloped tile has no slope then it's a open tile. { Tiles[x, y].tileType = 1; } if ((Tiles[x, y].tileType == 1) && (Tiles[x, y].TileSlopeSteepness > 0)) //similarly an open tile can't have a slope at all { Tiles[x, y].TileSlopeSteepness = 0; } Tiles[x, y].indexObjectList = (int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 4, 16); //if(Tiles[x,y].indexObjectList!=0) // { // fprintf(LOGFILE,"At %d %d we have: %d\n", x,y,Tiles[x,y].indexObjectList); // } /* xxxxx0xx Floor & ceiling, same direction xxxxx4xx Floor & ceiling, ceiling opposite dir to tile type xxxxx8xx Floor only xxxxxCxx Ceiling only */ Tiles[x, y].shockSlopeFlag = (short)((DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) >> 10) & 0x03); Tiles[x, y].UseAdjacentTextures = (short)((DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) >> 8) & 0x01); Tiles[x, y].shockTextureOffset = (short)(DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) & 0xF); //unknownflags //70E000E0 // fprintf(LOGFILE,"\nUnknownflags @ %d %d= %d",x,y, getValAtAddress(lev_ark,address_pointer+8,32) & 0x70E000E0); Tiles[x, y].shockShadeLower = (short)(((int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) >> 16) & 0x0F); Tiles[x, y].shockShadeUpper = (short)(((int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) >> 24) & 0x0F); //Tiles[x,y].shadeUpperGlobal = 0; // Tiles[x,y].shadeLowerGlobal = 0; Tiles[x, y].shockNorthOffset = Tiles[x, y].shockTextureOffset; Tiles[x, y].shockSouthOffset = Tiles[x, y].shockTextureOffset; Tiles[x, y].shockEastOffset = Tiles[x, y].shockTextureOffset; /// Although the tile map renderer supports tiles of size X*Y I'm only smart enought to optimise the tilemap into strips of X*1 or Y*1 !! public void CleanUp(string game) { int x; int y; for (x = 0; x <= TileMap.TileMapSizeX; x++) //Tiles[x,y].indexObjectList=0; //if (y == 0) //{ // Tiles[x,y].tileType = TILE_SLOPE_N; // Tiles[x,y].shockSlopeFlag=SLOPE_FLOOR_ONLY; // Tiles[x,y].floorHeight=x; // Tiles[x,y].shockSteep=11; //} address_pointer = address_pointer + 16; } } for (int y = 1; y < TileMap.TileMapSizeY; y++) //skip the outer textures. { for (int x = 1; x < TileMap.TileMapSizeX; x++) { //if ( // (Tiles[x,y].tileType != TILE_OPEN) // || ((Tiles[x,y].tileType != TILE_OPEN) && (Tiles[x,y].UseAdjacentTextures == 1)) // ) // { //if (Tiles[x,y].UseAdjacentTextures != 1) // { if (Tiles[x + 1, y].UseAdjacentTextures != 1) { Tiles[x, y].East = Tiles[x + 1, y].wallTexture; Tiles[x, y].shockEastOffset = Tiles[x + 1, y].shockTextureOffset; //Tiles[x,y].shockEastCeilHeight =LevelInfo[x+1,y].ceilingHeight - LevelInfo[x+1,y].shockSteep ; } if (Tiles[x - 1, y].UseAdjacentTextures != 1) { Tiles[x, y].West = Tiles[x - 1, y].wallTexture; Tiles[x, y].shockWestOffset = Tiles[x - 1, y].shockTextureOffset; //Tiles[x,y].shockWestCeilHeight =LevelInfo[x-1,y].ceilingHeight - LevelInfo[x-1,y].shockSteep ; } if (Tiles[x, y + 1].UseAdjacentTextures != 1) { Tiles[x, y].North = Tiles[x, y + 1].wallTexture; Tiles[x, y].shockNorthOffset = Tiles[x, y + 1].shockTextureOffset; //Tiles[x,y].shockNorthCeilHeight =LevelInfo[x,y+1].ceilingHeight - LevelInfo[x,y+1].shockSteep ; } if (Tiles[x, y - 1].UseAdjacentTextures != 1) { Tiles[x, y].South = Tiles[x, y - 1].wallTexture; Tiles[x, y].shockSouthOffset = Tiles[x, y - 1].shockTextureOffset; //Tiles[x,y].shockSouthCeilHeight =LevelInfo[x,y-1].ceilingHeight - LevelInfo[x,y-1].shockSteep ; } //Need to calculate the adjustment here with the steepness and the direction of the slope. Tiles[x, y].shockEastCeilHeight = (short)CalcNeighbourCeilHeight(Tiles[x, y], Tiles[x + 1, y], fEAST); Tiles[x, y].shockWestCeilHeight = (short)CalcNeighbourCeilHeight(Tiles[x, y], Tiles[x - 1, y], fWEST); Tiles[x, y].shockNorthCeilHeight = (short)CalcNeighbourCeilHeight(Tiles[x, y], Tiles[x, y + 1], fNORTH); Tiles[x, y].shockSouthCeilHeight = (short)CalcNeighbourCeilHeight(Tiles[x, y], Tiles[x, y - 1], fSOUTH); /* Tiles[x,y].shockEastCeilHeight =LevelInfo[x+1,y].ceilingHeight - LevelInfo[x+1,y].shockSteep ; Tiles[x,y].shockWestCeilHeight =LevelInfo[x-1,y].ceilingHeight - LevelInfo[x-1,y].shockSteep ; Tiles[x,y].shockNorthCeilHeight =LevelInfo[x,y+1].ceilingHeight - LevelInfo[x,y+1].shockSteep ; Tiles[x,y].shockSouthCeilHeight =LevelInfo[x,y-1].ceilingHeight - LevelInfo[x,y-1].shockSteep ;*/ //} //Tiles[x, y].UpperEast = Tiles[x, y].East; //Tiles[x, y].UpperWest = Tiles[x, y].West; //Tiles[x, y].UpperNorth = Tiles[x, y].North; //Tiles[x, y].UpperSouth = Tiles[x, y].South; //Tiles[x, y].LowerEast = Tiles[x, y].East; //Tiles[x, y].LowerWest = Tiles[x, y].West; //Tiles[x, y].LowerNorth = Tiles[x, y].North; //Tiles[x, y].LowerSouth = Tiles[x, y].South; } } return true; } /// <summary> /// Cleans up the tilemap. Splits up the tiles into strips of tiles along the x or y axis and sets tile face visibility as required /// </summary> /// <param name="game">Game.</param> /// Although the tile map renderer supports tiles of size X*Y I'm only smart enought to optimise the tilemap into strips of X*1 or Y*1 !! public void CleanUp(string game) { if (!GameWorldController.instance.DoCleanUp) { return; } int x; int y; for (x = 0; x <= TileMap.TileMapSizeX; x++) { for (y = 0; y <= TileMap.TileMapSizeY; y++) { //Set some easy tile visible settings switch (Tiles[x, y].tileType) { case TILE_SOLID: //Bottom and top are invisible Tiles[x, y].VisibleFaces[vBOTTOM] = false; Tiles[x, y].VisibleFaces[vTOP] = false; break; default: //Bottom and top is invisible Tiles[x, y].VisibleFaces[vBOTTOM] = false; Tiles[x, y].VisibleFaces[vTOP] = false; break; } } for (x = 0; x <= TileMap.TileMapSizeX; x++) { for (y = 0; y <= TileMap.TileMapSizeY; y++) { //lets test this tile for visibility //A tile is invisible if it only touches other solid tiles and has no objects or does not have a terrain change. if ((Tiles[x, y].tileType == 0) && (Tiles[x, y].indexObjectList == 0) && (Tiles[x, y].TerrainChange == false)) { switch (y) { case 0: //bottom row switch (x) { case 0: //bl corner if ((Tiles[x + 1, y].tileType == 0) && (Tiles[x, y + 1].tileType == 0) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y + 1].TerrainChange == false)) { Tiles[x, y].Render = false; ; break; } else { Tiles[x, y].Render = true; break; } case TileMap.TileMapSizeX://br corner if ((Tiles[x - 1, y].tileType == 0) && (Tiles[x, y + 1].tileType == 0) && (Tiles[x - 1, y].TerrainChange == false) && (Tiles[x, y + 1].TerrainChange == false)) { Tiles[x, y].Render = false; break; } else { Tiles[x, y].Render = true; break; } default: // invert t if ((Tiles[x + 1, y].tileType == 0) && (Tiles[x, y + 1].tileType == 0) && (Tiles[x + 1, y].tileType == 0) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x + 1, y].TerrainChange == false)) { Tiles[x, y].Render = false; break; } else { Tiles[x, y].Render = true; break; } } break; case TileMap.TileMapSizeY: //Top row switch (x) { case 0: //tl corner if ((Tiles[x + 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false)) { Tiles[x, y].Render = false; break; } else { Tiles[x, y].Render = true; break; } case TileMap.TileMapSizeX://tr corner if ((Tiles[x - 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0) && (Tiles[x - 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false)) { Tiles[x, y].Render = false; break; } else { Tiles[x, y].Render = true; break; } default: // t if ((Tiles[x + 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0) && (Tiles[x - 1, y].tileType == 0) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false) && (Tiles[x - 1, y].TerrainChange == false)) { Tiles[x, y].Render = false; break; } else { Tiles[x, y].Render = true; break; } } break; default: // switch (x) { case 0: //left edge if ((Tiles[x, y + 1].tileType == 0) && (Tiles[x + 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0) && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false)) { Tiles[x, y].Render = false; break; } else { Tiles[x, y].Render = true; break; } case TileMap.TileMapSizeX: //right edge if ((Tiles[x, y + 1].tileType == 0) && (Tiles[x - 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0) && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x - 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false)) { Tiles[x, y].Render = false; break; } else { Tiles[x, y].Render = true; break; } default: //+ if ((Tiles[x, y + 1].tileType == 0) && (Tiles[x + 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0) && (Tiles[x - 1, y].tileType == 0) && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false) && (Tiles[x - 1, y].TerrainChange == false)) { Tiles[x, y].Render = false; break; } else { Tiles[x, y].Render = true; break; } } break; } } } } } //return; if (game == GAME_SHOCK) {//TODO:FIx some z-fighting due to tile visibility. return; } //return; int j = 1; //Now lets combine the solids along particular axis for (x = 0; x < TileMap.TileMapSizeX; x++) { for (y = 0; y < TileMap.TileMapSizeY; y++) { if ((Tiles[x, y].Grouped == false)) { j = 1; while ((Tiles[x, y].Render == true) && (Tiles[x, y + j].Render == true) && (Tiles[x, y + j].Grouped == false)) //&& (Tiles[x,y].tileType ==0) && (Tiles[x,y+j].tileType ==0) { //combine these two if they match and they are not already part of a group if (DoTilesMatch(Tiles[x, y], Tiles[x, y + j])) { Tiles[x, y + j].Render = false; Tiles[x, y + j].Grouped = true; Tiles[x, y].Grouped = true; //Tiles[x,y].DimY++; j++; } else { break; } } Tiles[x, y].DimY = (short)(Tiles[x, y].DimY + j - 1); j = 1; } } } j = 1; ////Now lets combine solids along the other axis for (y = 0; y < TileMap.TileMapSizeY; y++) { for (x = 0; x < TileMap.TileMapSizeX; x++) { if ((Tiles[x, y].Grouped == false)) { j = 1; while ((Tiles[x, y].Render == true) && (Tiles[x + j, y].Render == true) && (Tiles[x + j, y].Grouped == false)) //&& (Tiles[x,y].tileType ==0) && (Tiles[x,y+j].tileType ==0) { //combine these two if they match and they are not already part of a group if (DoTilesMatch(Tiles[x, y], Tiles[x + j, y])) { Tiles[x + j, y].Render = false; Tiles[x + j, y].Grouped = true; Tiles[x, y].Grouped = true; //Tiles[x,y].DimY++; j++; } else { break; } } Tiles[x, y].DimX = (short)(Tiles[x, y].DimX + j - 1); j = 1; } } } //Clear invisible faces on solid tiles. //TODO:Support all 64x64 tiles for (y = 0; y <= TileMap.TileMapSizeY; y++) { for (x = 0; x <= TileMap.TileMapSizeX; x++) { if ((Tiles[x, y].tileType == TILE_SOLID)) { int dimx = Tiles[x, y].DimX; int dimy = Tiles[x, y].DimY; if (x == 0) { Tiles[x, y].VisibleFaces[vWEST] = false; } if (x == TileMap.TileMapSizeX) { Tiles[x, y].VisibleFaces[vEAST] = false; } if (y == 0) { Tiles[x, y].VisibleFaces[vSOUTH] = false; } if (y == TileMap.TileMapSizeY) { Tiles[x, y].VisibleFaces[vNORTH] = false; } if ((x + dimx <= TileMap.TileMapSizeX) && (y + dimy <= TileMap.TileMapSizeY)) { if ((Tiles[x + dimx, y].tileType == TILE_SOLID) && (Tiles[x + dimx, y].TerrainChange == false) && (Tiles[x, y].TerrainChange == false))//Tile to the east is a solid { Tiles[x, y].VisibleFaces[vEAST] = false; Tiles[x + dimx, y].VisibleFaces[vWEST] = false; } if ((Tiles[x, y + dimy].tileType == TILE_SOLID) && (Tiles[x, y].TerrainChange == false) && (Tiles[x, y + dimy].TerrainChange == false))//TIle to the north is a solid { Tiles[x, y].VisibleFaces[vNORTH] = false; Tiles[x, y + dimy].VisibleFaces[vSOUTH] = false; } } } } } //Clear invisible faces on diagonals for (y = 1; y < TileMap.TileMapSizeY; y++) { for (x = 1; x < TileMap.TileMapSizeX; x++) { switch (Tiles[x, y].tileType) { case TILE_DIAG_NW: { if ((Tiles[x, y - 1].tileType == TILE_SOLID) && (Tiles[x, y - 1].TerrainChange == false)) { Tiles[x, y].VisibleFaces[vSOUTH] = false; Tiles[x, y - 1].VisibleFaces[vNORTH] = false; } if ((Tiles[x + 1, y].tileType == TILE_SOLID) && (Tiles[x + 1, y].TerrainChange == false)) { Tiles[x, y].VisibleFaces[vEAST] = false; Tiles[x + 1, y].VisibleFaces[vWEST] = false; } } break; case TILE_DIAG_NE: { if ((Tiles[x, y - 1].tileType == TILE_SOLID) && (Tiles[x, y - 1].TerrainChange == false)) { Tiles[x, y].VisibleFaces[vSOUTH] = false; Tiles[x, y - 1].VisibleFaces[vNORTH] = false; } if ((Tiles[x - 1, y].tileType == TILE_SOLID) && (Tiles[x - 1, y].TerrainChange == false)) { Tiles[x, y].VisibleFaces[vWEST] = false; Tiles[x - 1, y].VisibleFaces[vEAST] = false; } } break; case TILE_DIAG_SE: { if ((Tiles[x, y + 1].tileType == TILE_SOLID) && (Tiles[x, y + 1].TerrainChange == false)) { Tiles[x, y].VisibleFaces[vNORTH] = false; Tiles[x, y + 1].VisibleFaces[vSOUTH] = false; } if ((Tiles[x - 1, y].tileType == TILE_SOLID) && (Tiles[x - 1, y].TerrainChange == false)) { Tiles[x, y].VisibleFaces[vWEST] = false; Tiles[x - 1, y].VisibleFaces[vEAST] = false; } } break; case TILE_DIAG_SW: { if ((Tiles[x, y + 1].tileType == TILE_SOLID) && (Tiles[x, y + 1].TerrainChange == false)) { Tiles[x, y].VisibleFaces[vNORTH] = false; Tiles[x, y + 1].VisibleFaces[vSOUTH] = false; } if ((Tiles[x + 1, y].tileType == TILE_SOLID) && (Tiles[x + 1, y].TerrainChange == false)) { Tiles[x, y].VisibleFaces[vEAST] = false; Tiles[x + 1, y].VisibleFaces[vWEST] = false; } } break; } } } for (y = 1; y < TileMap.TileMapSizeY; y++) { for (x = 1; x < TileMap.TileMapSizeX; x++) { if ((Tiles[x, y].tileType == TILE_OPEN) && (Tiles[x, y].TerrainChange == false)) { if ( ((Tiles[x + 1, y].tileType == TILE_OPEN) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x + 1, y].floorHeight >= Tiles[x, y].floorHeight)) || (Tiles[x + 1, y].tileType == TILE_SOLID) && (Tiles[x + 1, y].TerrainChange == false) ) { Tiles[x, y].VisibleFaces[vEAST] = false; } if ( ((Tiles[x - 1, y].tileType == TILE_OPEN) && (Tiles[x - 1, y].TerrainChange == false) && (Tiles[x - 1, y].floorHeight >= Tiles[x, y].floorHeight)) || (Tiles[x - 1, y].tileType == TILE_SOLID) && (Tiles[x - 1, y].TerrainChange == false) ) { Tiles[x, y].VisibleFaces[vWEST] = false; } if ( ((Tiles[x, y + 1].tileType == TILE_OPEN) && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x, y + 1].floorHeight >= Tiles[x, y].floorHeight)) || (Tiles[x, y + 1].tileType == TILE_SOLID) && (Tiles[x, y + 1].TerrainChange == false) ) { Tiles[x, y].VisibleFaces[vNORTH] = false; } if ( ((Tiles[x, y - 1].tileType == TILE_OPEN) && (Tiles[x, y - 1].TerrainChange == false) && (Tiles[x, y - 1].floorHeight >= Tiles[x, y].floorHeight)) || (Tiles[x, y - 1].tileType == TILE_SOLID) && (Tiles[x, y - 1].TerrainChange == false) ) { Tiles[x, y].VisibleFaces[vSOUTH] = false; } } } } //Make sure solids & opens are still consistently visible. for (y = 1; y < TileMap.TileMapSizeY; y++) { for (x = 1; x < TileMap.TileMapSizeX; x++) { if ((Tiles[x, y].tileType == TILE_SOLID) || (Tiles[x, y].tileType == TILE_OPEN)) { int dimx = Tiles[x, y].DimX; int dimy = Tiles[x, y].DimY; if (dimx > 1) {//Make sure the ends are set properly Tiles[x, y].VisibleFaces[vEAST] = Tiles[x + dimx - 1, y].VisibleFaces[vEAST]; } if (dimy > 1) { Tiles[x, y].VisibleFaces[vNORTH] = Tiles[x, y + dimy - 1].VisibleFaces[vNORTH]; } //Check along each axis for (int i = 0; i < Tiles[x, y].DimX; i++) { if (Tiles[x + i, y].VisibleFaces[vNORTH] == true) { Tiles[x, y].VisibleFaces[vNORTH] = true; } if (Tiles[x + i, y].VisibleFaces[vSOUTH] == true) { Tiles[x, y].VisibleFaces[vSOUTH] = true; } } for (int i = 0; i < Tiles[x, y].DimY; i++) { if (Tiles[x, y + i].VisibleFaces[vEAST] == true) { Tiles[x, y].VisibleFaces[vEAST] = true; } if (Tiles[x, y + i].VisibleFaces[vWEST] == true) { Tiles[x, y].VisibleFaces[vWEST] = true; } } } } } for (y = 0; y <= TileMap.TileMapSizeY; y++) { Tiles[0, y].VisibleFaces[vEAST] = true; Tiles[TileMap.TileMapSizeX, y].VisibleFaces[vWEST] = true; } for (x = 0; x <= TileMap.TileMapSizeX; x++) { Tiles[x, 0].VisibleFaces[vNORTH] = true; Tiles[x, TileMap.TileMapSizeY].VisibleFaces[vSOUTH] = true; } } /// <summary> /// Check if two tiles are alike /// </summary> /// <param name="t1"></param> /// <param name="t2"></param> /// <returns></returns> bool DoTilesMatch(TileInfo t1, TileInfo t2) {//TODO:Tiles have a lot more properties now. if (_RES == GAME_SHOCK) { return false; } //if ((t1.tileType >1) || (t1.hasElevator==1) || (t1.TerrainChange ==1) || (t2.hasElevator==1) || (t2.TerrainChange ==1) || (t1.isWater ==1) || (t2.isWater ==1)){ //autofail no none solid/open/special. if ((t1.tileType > 1) || (t1.TerrainChange == true) || (t2.TerrainChange == true)) { //autofail no none solid/open/special. return false; } else { if ((t1.tileType == 0) && (t2.tileType == 0)) //solid { return ((t1.wallTexture == t2.wallTexture) && (t1.West == t2.West) && (t1.South == t2.South) && (t1.East == t2.East) && (t1.North == t2.North) && (t1.UseAdjacentTextures == t2.UseAdjacentTextures)); } else { return (t1.shockCeilingTexture == t2.shockCeilingTexture) && (t1.floorTexture == t2.floorTexture) && (t1.floorHeight == t2.floorHeight) && (t1.ceilingHeight == t2.ceilingHeight) && (t1.DimX == t2.DimX) && (t1.DimY == t2.DimY) && (t1.wallTexture == t2.wallTexture) && (t1.tileType == t2.tileType) && (t1.IsDoorForNPC == false) && (t2.IsDoorForNPC == false);// } } } public static bool isTerrainWater(int terraintype) { switch (terraintype) { case TerrainDatLoader.Water: case TerrainDatLoader.Waterfall: case TerrainDatLoader.WaterFlowEast: case TerrainDatLoader.WaterFlowWest: case TerrainDatLoader.WaterFlowNorth: case TerrainDatLoader.WaterFlowSouth: return true; } return false; } /// <summary> /// Checks if the terrain is lava /// </summary> /// <param name="terraintype"></param> /// <returns>True if it lava</returns> public static bool isTerrainLava(int terraintype) { switch (terraintype) { case TerrainDatLoader.Lava: case TerrainDatLoader.Lavafall: return true; } return false; } /// <summary> /// Checks if Terrain is ice /// </summary> /// <param name="terraintype"></param> /// <returns></returns> public static bool isTerrainIce(int terraintype) { switch (terraintype) { case TerrainDatLoader.Ice_wall: case TerrainDatLoader.IceNonSlip: case TerrainDatLoader.Ice_walls: return true; } return false; } ////Temp //public static bool isTextureWater(int textureNo) //{ // if (textureNo > GameWorldController.instance.terrainData.Terrain.GetUpperBound(0)) // { // return false; // } // switch (_RES) // { // case GAME_UW2: // return // ( // GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Water // || // GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Waterfall // || // GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.WaterFlowEast // || // GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.WaterFlowWest // || // GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.WaterFlowNorth // || // GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.WaterFlowSouth // ); // default: // return GameWorldController.instance.terrainData.Terrain[256 + textureNo - 210] == TerrainDatLoader.Water;//Adjust for uw1 texturemap positions // } //} //public static bool isTextureIce(int textureNo) //{ // if (textureNo > GameWorldController.instance.terrainData.Terrain.GetUpperBound(0)) // { // return false; // } // switch (_RES) // { // case GAME_UW2: // return ( // (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Ice_wall) // || // (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.IceNonSlip) // || // (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Ice_walls) // ); // //GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.IceNonSlip) // //|| // default: // return GameWorldController.instance.terrainData.Terrain[256 + textureNo - 210] == TerrainDatLoader.Water;//Adjust for uw1 texturemap positions // } //} //public static bool isTextureLava(int textureNo) //{ // if (textureNo > GameWorldController.instance.terrainData.Terrain.GetUpperBound(0)) // { // return false; // } // switch (_RES) // { // case GAME_UW2: // return ( // (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Lava) // || // (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Lavafall) // ); // default: // return GameWorldController.instance.terrainData.Terrain[256 + textureNo - 210] == TerrainDatLoader.Lava;//Adjust for uw1 texturemap positions // } //} /// <summary> /// Is the texture nothing. /// </summary> /// <returns><c>true</c>, if texture nothing was ised, <c>false</c> otherwise.</returns> /// <param name="textureNo">Texture no.</param> public static bool isTextureNothing(int textureNo) { switch (textureNo) { case 236: return true; } return false; } /* public void MergeWaterRegions() { int currRegion; currRegion =1; for (int x = 0; x<=TileMap.TileMapSizeX; x++) { for (int y = 0; y<=TileMap.TileMapSizeY; y++) { if (Tiles[x,y].hasBridge != true) { if ((Tiles[x,y].isWater == true) && (Tiles[x,y].waterRegion == 0))//Unset water region. { Tiles[x,y].waterRegion = (short)currRegion; MergeCurrentWaterRegion(currRegion, x, y); currRegion++; } } } } } void MergeCurrentWaterRegion(int currRegion, int x, int y) { //north if ((Tiles[x,y+1].isWater==true) && (Tiles[x,y+1].waterRegion == 0)) { Tiles[x,y + 1].waterRegion = (short)currRegion; MergeCurrentWaterRegion(currRegion, x, y+1); } //south if ((Tiles[x,y - 1].isWater == true) && (Tiles[x,y - 1].waterRegion == 0)) { Tiles[x,y - 1].waterRegion = (short)currRegion; MergeCurrentWaterRegion(currRegion, x , y-1); } //east if ((Tiles[x + 1,y].isWater == true) && (Tiles[x + 1,y].waterRegion == 0)) { Tiles[x + 1,y].waterRegion = (short)currRegion; MergeCurrentWaterRegion(currRegion, x+1, y); } //west if ((Tiles[x - 1,y].isWater == true) && (Tiles[x - 1,y].waterRegion == 0)) { Tiles[x - 1,y].waterRegion = (short)currRegion; MergeCurrentWaterRegion(currRegion, x-1, y); } } */ /* /// <summary> /// Merges the lava regions into a single region /// </summary> public void MergeLavaRegions() { int currRegion; currRegion = 1; for (int x = 0; x<=TileMap.TileMapSizeX; x++) { for (int y = 0; y<=TileMap.TileMapSizeY; y++) { if (Tiles[x,y].hasBridge != true) { if ((Tiles[x,y].isLava == true) && (Tiles[x,y].lavaRegion == 0))//Unset lava region. { Tiles[x,y].lavaRegion = (short)currRegion; MergeCurrentLavaRegion(currRegion, x, y); currRegion++; } } } } } void MergeCurrentLavaRegion( int currRegion, int x, int y) { //north if ((Tiles[x,y + 1].isLava == true) && (Tiles[x,y + 1].lavaRegion == 0)) { Tiles[x,y + 1].lavaRegion = (short)currRegion; MergeCurrentLavaRegion(currRegion, x, y + 1); } //south if ((Tiles[x,y - 1].isLava == true) && (Tiles[x,y - 1].lavaRegion == 0)) { Tiles[x,y - 1].lavaRegion =(short) currRegion; MergeCurrentLavaRegion( currRegion, x, y - 1); } //east if ((Tiles[x + 1,y].isLava == true) && (Tiles[x + 1,y].lavaRegion == 0)) { Tiles[x + 1,y].lavaRegion =(short) currRegion; MergeCurrentLavaRegion( currRegion, x + 1, y); } //west if ((Tiles[x - 1,y].isLava == true) && (Tiles[x - 1,y].lavaRegion == 0)) { Tiles[x - 1,y].lavaRegion = (short)currRegion; MergeCurrentLavaRegion(currRegion, x - 1, y); } } */ int CalcNeighbourCeilHeight(TileInfo t1, TileInfo t2, int Direction) {//TODO:Test me. I'm terrible. // fNORTH 32 // fSOUTH 16 // fEAST 8 // fWEST 4 if ((t2.tileType <= 1) || (t2.shockSlopeFlag == SLOPE_FLOOR_ONLY)) {//Don't need to do anything since it has a flat ceiling. return t2.ceilingHeight; } else { //return t2.ceilingHeight; switch (Direction) { case fNORTH: { switch (t2.tileType) { case TILE_SLOPE_N: case TILE_SLOPE_S: if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) || (t2.shockSlopeFlag == SLOPE_CEILING_ONLY)) { return t2.ceilingHeight + t2.TileSlopeSteepness; } else { return t2.ceilingHeight; } //break; default: return t2.ceilingHeight; //break; } } case fSOUTH: { switch (t2.tileType) { case TILE_SLOPE_S: case TILE_SLOPE_N: if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) || (t2.shockSlopeFlag == SLOPE_CEILING_ONLY)) { return t2.ceilingHeight + t2.TileSlopeSteepness; } else { return t2.ceilingHeight; } //break; default: return t2.ceilingHeight; //break; } //if (t2.tileType == TILE_SLOPE_S) // { // if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) ||(t2.shockSlopeFlag == SLOPE_CEILING_ONLY)) // { // return t2.ceilingHeight+t2.shockSteep ; // } // else // { // return t2.ceilingHeight; // } // } //break; } case fEAST: { switch (t2.tileType) { case TILE_SLOPE_E: case TILE_SLOPE_W: if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) || (t2.shockSlopeFlag == SLOPE_CEILING_ONLY)) { return t2.ceilingHeight + t2.TileSlopeSteepness; } else { return t2.ceilingHeight; } //break; default: return t2.ceilingHeight; //break; } } case fWEST: { switch (t2.tileType) { case TILE_SLOPE_W: case TILE_SLOPE_E: if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) || (t2.shockSlopeFlag == SLOPE_CEILING_ONLY)) { return t2.ceilingHeight + t2.TileSlopeSteepness; } else { return t2.ceilingHeight; } //break; default: return t2.ceilingHeight; //break; } } } } return t2.ceilingHeight; } /* char[] GetUW2TileMapBytes(int LevelNo, char[] lev_ark_file_data, out long datalen) { char[] lev_ark; long address_pointer=0; int NoOfBlocks=(int)DataLoader.getValAtAddress(lev_ark_file_data,0,32); datalen=0; address_pointer=6; int isCompressed =( ( (int)DataLoader.getValAtAddress(lev_ark_file_data,address_pointer + (NoOfBlocks*4) + (LevelNo*4) ,32) ) >>1) & 0x01; address_pointer=(LevelNo * 4) + 6; if ((int)DataLoader.getValAtAddress(lev_ark_file_data,address_pointer,32)==0) { Debug.Log("This should not happen in getuw2tilemapbytes"); lev_ark= new char[1]; return lev_ark ; } if (isCompressed == 1) { //long datalen=0; lev_ark = DataLoader.unpackUW2(lev_ark_file_data,DataLoader.getValAtAddress(lev_ark_file_data,address_pointer,32), ref datalen); } else { datalen = 0x7c08; int BlockStart = (int)DataLoader.getValAtAddress(lev_ark_file_data, address_pointer, 32); lev_ark = new char[0x7c08];//Make sure this contains the object data as well. int j=0; for (int i = BlockStart; i < BlockStart + 0x7c08; i++) { lev_ark[j] = lev_ark_file_data[i]; j++; } } return lev_ark; }*/ /// <summary> /// Converts this tilemap/Objectlist into an array that can be written to file. /// </summary> /// <returns>The map to bytes.</returns> public char[] TileMapToBytes(char[] lev_ark_file_data, out long datalen) { //holy crap this is crap! //SCRAP IT ALL char[] TileMapData = new char[31752];//Size of tilemap + object list //Copy filedata from tile map to data array for (int i=0;i< 16384;i++) { TileMapData[i] = lev_ark_block.Data[i]; } //Copy mobile object data block for (int i = 0; i < 256 * 27; i++) { // TileMapData[i] = LevelObjects. } //and so on. //Copy Static object data block //Copy mobile free list //copy static free list // 7afc 0104 unknown (260 bytes) //7c00 0002 // 7c02 0002 no.entries in mobile free list minus 1 //7c04 0002 no.entries in static free list minus 1 // 7c06 0002 0x7775('uw') DataLoader.UWBlock uwdata = new DataLoader.UWBlock(); DataLoader.LoadUWBlock(lev_ark_file_data, thisLevelNo, 31752, out uwdata); for (int i = 0x7afc; i < 31752; i++)//07afc { TileMapData[i] = uwdata.Data[i]; } datalen = uwdata.DataLen; long addptr = 0; //for (int y = 0; y <= TileMap.TileMapSizeY; y++) //{ // for (int x = 0; x <= TileMap.TileMapSizeX; x++) // { // TileInfo t = Tiles[x, y]; // //Shift the bits to construct my data // int tileType = t.tileType; // int floorHeight = (t.floorHeight / 2) << 4; // int ByteToWrite = tileType | floorHeight;//| floorTexture | noMagic;//This will be set in the original data // TileMapData[addptr] = (char)(ByteToWrite); // int flags = t.flags & 0x3; // int floorTexture = t.floorTexture << 2; // int noMagic = t.noMagic << 6; // int DoorBit = t.doorBit << 7; // ByteToWrite = floorTexture | noMagic | DoorBit | flags; // TileMapData[addptr + 1] = (char)(ByteToWrite); // ByteToWrite = ((t.indexObjectList & 0x3FF) << 6) | (t.wallTexture & 0x3F); // TileMapData[addptr + 2] = (char)(ByteToWrite & 0xFF); // TileMapData[addptr + 3] = (char)((ByteToWrite >> 8) & 0xFF); // addptr += 4; // } //} for (int o = 0; o <= GameWorldController.instance.objectList[thisLevelNo].objInfo.GetUpperBound(0); o++) { ObjectLoaderInfo currobj = GameWorldController.instance.objectList[thisLevelNo].objInfo[o]; if (currobj != null) { /* if (currobj.instance!=null) { if (currobj.instance.transform.parent == GameWorldController.instance.InventoryMarker.transform) { Debug.Log("Trying to save object that is in inventory list" + currobj.instance.name); } } else { if (currobj.InUseFlag==1) { Debug.Log("Trying to save in use object that has no current instance:" + o); } } */ if (IsObjectFree(o)) { TileMapData[addptr] = (char)0; TileMapData[addptr + 1] = (char)0; TileMapData[addptr + 2] = (char)0; TileMapData[addptr + 3] = (char)0; TileMapData[addptr + 4] = (char)0; TileMapData[addptr + 5] = (char)0; TileMapData[addptr + 6] = (char)0; TileMapData[addptr + 7] = (char)0; if (o < 256) { TileMapData[addptr + 8] = (char)0; TileMapData[addptr + 9] = (char)0; TileMapData[addptr + 10] = (char)0; TileMapData[addptr + 11] = (char)0; TileMapData[addptr + 12] = (char)0; TileMapData[addptr + 13] = (char)0; TileMapData[addptr + 14] = (char)0; TileMapData[addptr + 15] = (char)0; TileMapData[addptr + 16] = (char)0; TileMapData[addptr + 17] = (char)0; TileMapData[addptr + 18] = (char)0; TileMapData[addptr + 19] = (char)0; TileMapData[addptr + 20] = (char)0; TileMapData[addptr + 21] = (char)0; TileMapData[addptr + 22] = (char)0; TileMapData[addptr + 23] = (char)0; TileMapData[addptr + 24] = (char)0; TileMapData[addptr + 25] = (char)0; TileMapData[addptr + 26] = (char)0; addptr = addptr + 8 + 19; } else { addptr = addptr + 8; } } else { int ByteToWrite = (currobj.is_quant << 15) | (currobj.invis << 14) | (currobj.doordir << 13) | (currobj.enchantment << 12) | ((currobj.flags & 0x07) << 9) | (currobj.item_id & 0x1FF); TileMapData[addptr] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 1] = (char)((ByteToWrite >> 8) & 0xFF); ByteToWrite = ((currobj.xpos & 0x7) << 13) | ((currobj.ypos & 0x7) << 10) | ((currobj.heading & 0x7) << 7) | ((currobj.zpos & 0x7F)); TileMapData[addptr + 2] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 3] = (char)((ByteToWrite >> 8) & 0xFF); ByteToWrite = (((int)currobj.next & 0x3FF) << 6) | (currobj.quality & 0x3F); TileMapData[addptr + 4] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 5] = (char)((ByteToWrite >> 8) & 0xFF); ByteToWrite = ((currobj.link & 0x3FF) << 6) | (currobj.owner & 0x3F); TileMapData[addptr + 6] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 7] = (char)((ByteToWrite >> 8) & 0xFF); if (o < 256) {//Additional npc mobile data. TileMapData[addptr + 0x8] = (char)(currobj.npc_hp); // TileMapData[addptr + 0x9] = (char)((currobj.ProjectileHeadingMajor & 0xE0) | ((char)(currobj.ProjectileHeadingMinor & 0x1F))); //+A is copied unknown value //+B bits 0-3 npc_goal, 4-11 npc_gtarg, 12-15 is unknown but needs to be copied to prevent npcs duplicating. ByteToWrite = ( ((currobj.npc_goal & 0xF)) | ((currobj.npc_gtarg & 0xFF) << 4) | ((TileMapData[addptr + 0xb + 1] & 0xf0) << 8) ); TileMapData[addptr + 0xb] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 0xb + 1] = (char)((ByteToWrite >> 8) & 0xFF); int val = (int)DataLoader.getValAtAddress(TileMapData, addptr + 0xd, 16); val = val & 0x1ff0; ByteToWrite = ((currobj.npc_attitude & 0x3) << 14) | ((currobj.npc_talkedto & 0x1) << 13) | (currobj.npc_level & 0xF) | val ; TileMapData[addptr + 0xd] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 0xd + 1] = (char)((ByteToWrite >> 8) & 0xFF); //TileMapData[addptr+0x14] = (char)((TileMapData[addptr+0x14] & 0xC0) | (char)(currobj.Projectile_Pitch & 0x3F)); //// TileMapData[addptr + 0x14] = (char)(((currobj.Projectile_Sign << 7) & 0x1) | ((currobj.Projectile_Pitch & 0x7) << 4) | (currobj.Projectile_Speed & 0xf)); ByteToWrite = ((currobj.npc_xhome & 0x3F) << 10) | ((currobj.npc_yhome & 0x3F) << 4) | (TileMapData[addptr + 0x16] & 0xf); TileMapData[addptr + 0x16] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 0x16 + 1] = (char)((ByteToWrite >> 8) & 0xFF); ByteToWrite = (TileMapData[addptr + 0x18] & 0xE0) | (currobj.npc_heading & 0x1F); TileMapData[addptr + 0x18] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 0x18 + 1] = (char)((ByteToWrite >> 8) & 0xFF); TileMapData[addptr + 0x19] = (char)( ((currobj.npc_hunger & 0x3F)) ); TileMapData[addptr + 0x1a] = (char)( ((currobj.npc_whoami & 0xFF)) ); addptr = addptr + 8 + 19; } else { addptr = addptr + 8; } } } } addptr = 0x7300;//mobile object list int f = 0; for (int i = 0; i <= GameWorldController.instance.objectList[thisLevelNo].NoOfFreeMobile; i++) { int ByteToWrite = GameWorldController.instance.objectList[thisLevelNo].FreeMobileList[f]; TileMapData[addptr] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 1] = (char)((ByteToWrite >> 8) & 0xFF); f++; addptr += 2; } addptr = 0x74fc;//static object list f = 0; for (int i = 0; i <= GameWorldController.instance.objectList[thisLevelNo].NoOfFreeStatic; i++) { int ByteToWrite = GameWorldController.instance.objectList[thisLevelNo].FreeStaticList[f]; TileMapData[addptr] = (char)(ByteToWrite & 0xFF); TileMapData[addptr + 1] = (char)((ByteToWrite >> 8) & 0xFF); f++; addptr += 2; } //Now write the counts of free objects //TileMapData[0x7c02] = (char)(GameWorldController.instance.objectList[thisLevelNo].NoOfFreeMobile & 0xFF); //TileMapData[0x7c03] = (char)((GameWorldController.instance.objectList[thisLevelNo].NoOfFreeMobile >> 8) & 0xFF); // TileMapData[0x7c04] = (char)(GameWorldController.instance.objectList[thisLevelNo].NoOfFreeStatic & 0xFF); // TileMapData[0x7c05] = (char)((GameWorldController.instance.objectList[thisLevelNo].NoOfFreeStatic >> 8) & 0xFF); return TileMapData; } bool IsObjectFree(int index) { if (index < 256)//mobile list { for (int i = 2; i <= GameWorldController.instance.objectList[thisLevelNo].NoOfFreeMobile; i++) { if (index == GameWorldController.instance.objectList[thisLevelNo].FreeMobileList[i]) {//obj is on free list return true; } } } else {//static for (int i = 0; i <= GameWorldController.instance.objectList[thisLevelNo].NoOfFreeStatic; i++) { if (index == GameWorldController.instance.objectList[thisLevelNo].FreeStaticList[i]) {//obj is on free list return true; } } } return false; } /// <summary> /// Converts the animation overlay data back to bytes /// </summary> /// <returns>The info to bytes.</returns> public char[] OverlayInfoToBytes() { char[] OverLayData = new char[64 * 6]; int OverlayAddress = 0; for (int overlayIndex = 0; overlayIndex < 64; overlayIndex++) { int link = Overlays[overlayIndex].link << 6; OverLayData[OverlayAddress + 0] = (char)(link & 0xFF); OverLayData[OverlayAddress + 1] = (char)((link >> 8) & 0xFF); OverLayData[OverlayAddress + 2] = (char)(Overlays[overlayIndex].duration & 0xFF); OverLayData[OverlayAddress + 3] = (char)((Overlays[overlayIndex].duration >> 8) & 0xFF); OverLayData[OverlayAddress + 4] = (char)(Overlays[overlayIndex].tileX & 0xFF); OverLayData[OverlayAddress + 5] = (char)(Overlays[overlayIndex].tileY & 0xFF); OverlayAddress += 6; } return OverLayData; } /// <summary> /// Converts the uw1 texture map to bytes. /// </summary> /// <returns>The map to bytes.</returns> public char[] TextureMapToBytes() { char[] textureMapData = new char[122]; short textureMapSize = 64; int TextureMapAddress = 0; for (int i = 0; i < textureMapSize; i++) { if (i < 48) //Wall textures { textureMapData[TextureMapAddress + 0] = (char)(texture_map[i] & 0xFF); textureMapData[TextureMapAddress + 1] = (char)((texture_map[i] >> 8) & 0xFF); TextureMapAddress += 2; } else if (i <= 57) //Floor textures are 49 to 56, ceiling is 57 { textureMapData[TextureMapAddress + 0] = (char)((texture_map[i] - 210) & 0xFF); textureMapData[TextureMapAddress + 1] = (char)(((texture_map[i] - 210) >> 8) & 0xFF); TextureMapAddress += 2; } else { //door textures textureMapData[TextureMapAddress] = (char)(texture_map[i]); TextureMapAddress++; } } return textureMapData; } /// <summary> /// Defines continous rooms regions. /// </summary> public void CreateRooms() { short RegionNo = 1; //Reset room settings for (int y = TileMapSizeY; y >= 0; y--) { for (int x = 0; x <= TileMapSizeX; x++) { Tiles[x, y].roomRegion = 0; } } for (int y = TileMapSizeY; y >= 0; y--) { for (int x = 0; x <= TileMapSizeX; x++) { if ( (Tiles[x, y].tileType != TILE_SOLID) && (Tiles[x, y].roomRegion == 0) ) {//Tiles is open and room region is not set Tiles[x, y].roomRegion = RegionNo; fillRoomRegion(x, y, TileTerrainType(x, y), RegionNo); RegionNo++; } } } /* if (false) { string output=""; StreamWriter writer = new StreamWriter( Application.dataPath + "//..//_output.txt", true); for (int y=TileMapSizeY; y>=0;y--) { output +="\n"; for (int x=0; x<=TileMapSizeX;x++) { output += Tiles[x,y].roomRegion.ToString("d3") + ","; } } writer.WriteLine(output); writer.Close(); }*/ } void fillRoomRegion(int startX, int startY, int terrainType, short RegionNo) { short thisTileHeight = Tiles[startX, startY].floorHeight; //Check in each direction for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { if ( ((x == -1) && (y == 0)) || ((x == 1) && (y == 0)) || ((x == 0) && (y == -1)) || ((x == 0) && (y == +1)) ) { if (TileMap.ValidTile(startX + x, startY + y)) { if ( (Tiles[startX + x, startY + y].tileType != TILE_SOLID) && (Tiles[startX + x, startY + y].roomRegion == 0) && (terrainType == TileTerrainType(startX + x, startY + y)) && (isTileOpenFromDirection(startX + x, startY + y, x, y)) && ( ( (thisTileHeight >= Tiles[startX + x, startY + y].floorHeight - 2) && (thisTileHeight <= Tiles[startX + x, startY + y].floorHeight + 2) ) || ( ( (Tiles[startX + x, startY + y].hasBridge) || (Tiles[startX, startY].hasBridge) ) && (terrainType == 0) ) ) ) {//Tiles is open and room region is not set and is a matching terrain type and does not drop down too far (unless it has a bridge and I'm testing for land) Tiles[startX + x, startY + y].roomRegion = RegionNo; fillRoomRegion(startX + x, startY + y, terrainType, RegionNo); } } } } } } /// <summary> /// Terrain types for calculating room regions. /// </summary> /// <returns>The terrain type.</returns> /// <param name="x">The x coordinate.</param> /// <param name="y">The y coordinate.</param> int TileTerrainType(int x, int y) { if ((Tiles[x, y].isLand) || (Tiles[x, y].hasBridge)) { return 0; } else if (Tiles[x, y].isWater) { return 1; } else if (Tiles[x, y].isLava) { return 2; } else if (Tiles[x, y].isNothing) { return 3; } else { return 0; } } /// <summary> /// Determines if the tile is open (Ie no wall is in the way) from the specified direction. /// </summary> /// <returns><c>true</c>, if tile open from direction was ised, <c>false</c> otherwise.</returns> /// <param name="X">X.</param> /// <param name="Y">Y.</param> /// <param name="directionX">Direction x.</param> /// <param name="directionY">Direction y.</param> bool isTileOpenFromDirection(int X, int Y, int directionX, int directionY) { switch (Tiles[X, Y].tileType) { case TILE_OPEN: case TILE_SLOPE_N: case TILE_SLOPE_S: case TILE_SLOPE_E: case TILE_SLOPE_W: return true; case TILE_DIAG_NE: if ((directionX == 1) || (directionY == -1)) { return true; } break; case TILE_DIAG_NW: if ((directionX == 1) || (directionY == 1)) { return true; } break; case TILE_DIAG_SE: if ((directionX == -1) || (directionY == -1)) { return true; } break; case TILE_DIAG_SW: if ((directionX == -1) || (directionY == 1)) { return true; } break; default: return false; } return false; } /// <summary> /// Create a string identifying the general shape of the level. /// </summary> /// <returns></returns> public string getSignature() { string signature = ""; for (int x = 0; x < TileMapSizeX; x++) { for (int y = 0; y < TileMapSizeY; y++) { signature += Tiles[x, y].tileType.ToString() + Tiles[x, y].floorHeight.ToString(); } } return signature; } //public int getTileAgentID(int tileX, int tileY) //{ // if (Tiles[tileX, tileY].isWater) // { // return GameWorldController.instance.NavMeshWater.agentTypeID; // } // if (Tiles[tileX, tileY].isLava) // { // return GameWorldController.instance.NavMeshLava.agentTypeID;
{'commit': 'diff --git a/UnityScripts/scripts/Magic/Magic.cs b/UnityScripts/scripts/Magic/Magic.cs\nindex f108f995..14bd3c7b 100644\n--- a/UnityScripts/scripts/Magic/Magic.cs\n+++ b/UnityScripts/scripts/Magic/Magic.cs\n@@ -3424,16 +3424,22 @@ public class Magic : UWEBase\n                 {\r\n                     if (!spellprop.silent)\r\n                     {\r\n-                        caster.transform.parent.GetComponent<AudioSource>().clip = MusicController.instance.SoundEffects[MusicController.SOUND_EFFECT_ZAP];\r\n-                        caster.transform.parent.GetComponent<AudioSource>().Play();\r\n+                        if (caster.GetComponent<AudioSource>() != null)\r\n+                        {\r\n+                            caster.transform.parent.GetComponent<AudioSource>().clip = MusicController.instance.SoundEffects[MusicController.SOUND_EFFECT_ZAP];\r\n+                            caster.transform.parent.GetComponent<AudioSource>().Play();\r\n+                        }\r\n                     }\r\n                 }\r\n                 else\r\n                 {\r\n                     if (!spellprop.silent)\r\n                     {\r\n-                        caster.GetComponent<AudioSource>().clip = MusicController.instance.SoundEffects[MusicController.SOUND_EFFECT_ZAP];\r\n-                        caster.GetComponent<AudioSource>().Play();\r\n+                        if (caster.GetComponent<AudioSource>()!=null)\r\n+                        {\r\n+                            caster.GetComponent<AudioSource>().clip = MusicController.instance.SoundEffects[MusicController.SOUND_EFFECT_ZAP];\r\n+                            caster.GetComponent<AudioSource>().Play();\r\n+                        }\r\n                     }\r\n                 }\r\n             }\r\ndiff --git a/UnityScripts/scripts/NPC/NPC.cs b/UnityScripts/scripts/NPC/NPC.cs\nindex 676990a9..d6269adb 100644\n--- a/UnityScripts/scripts/NPC/NPC.cs\n+++ b/UnityScripts/scripts/NPC/NPC.cs\n@@ -457,27 +457,30 @@ public class NPC : MobileObject\n             }\r\n         }\r\n         Container cnt = this.GetComponent<Container>();\r\n-        if (cnt.CountItems() == 0)\r\n+        if (cnt!=null)\r\n         {\r\n-            //Populate the container with a loot list\r\n-            for (int i = 0; i <= GameWorldController.instance.objDat.critterStats[item_id - 64].Loot.GetUpperBound(0); i++)\r\n+            if (cnt.CountItems() == 0)\r\n             {\r\n-                if (GameWorldController.instance.objDat.critterStats[item_id - 64].Loot[i] != -1)\r\n+                //Populate the container with a loot list\r\n+                for (int i = 0; i <= GameWorldController.instance.objDat.critterStats[item_id - 64].Loot.GetUpperBound(0); i++)\r\n                 {\r\n-                    int itemid = GameWorldController.instance.objDat.critterStats[item_id - 64].Loot[i];\r\n-                    ObjectLoaderInfo newobjt = ObjectLoader.newObject(itemid, Random.Range(1, 41), 0, 0, 256);\r\n-                    if (itemid == 16)//Sling stone.\r\n+                    if (GameWorldController.instance.objDat.critterStats[item_id - 64].Loot[i] != -1)\r\n                     {\r\n-                        newobjt.is_quant = 1;\r\n-                        newobjt.link = Random.Range(1, 10);\r\n-                        newobjt.quality = 40;\r\n-                    }\r\n-                    else\r\n-                    {\r\n-                        newobjt.is_quant = 0;\r\n+                        int itemid = GameWorldController.instance.objDat.critterStats[item_id - 64].Loot[i];\r\n+                        ObjectLoaderInfo newobjt = ObjectLoader.newObject(itemid, Random.Range(1, 41), 0, 0, 256);\r\n+                        if (itemid == 16)//Sling stone.\r\n+                        {\r\n+                            newobjt.is_quant = 1;\r\n+                            newobjt.link = Random.Range(1, 10);\r\n+                            newobjt.quality = 40;\r\n+                        }\r\n+                        else\r\n+                        {\r\n+                            newobjt.is_quant = 0;\r\n+                        }\r\n+                        newobjt.instance = ObjectInteraction.CreateNewObject(CurrentTileMap(), newobjt, CurrentObjectList().objInfo, GameWorldController.instance._ObjectMarker, GameWorldController.instance.InventoryMarker.transform.position);\r\n+                        cnt.AddItemToContainer(newobjt.instance.name);\r\n                     }\r\n-                    newobjt.instance = ObjectInteraction.CreateNewObject(CurrentTileMap(), newobjt, CurrentObjectList().objInfo, GameWorldController.instance._ObjectMarker, GameWorldController.instance.InventoryMarker.transform.position);\r\n-                    cnt.AddItemToContainer(newobjt.instance.name);\r\n                 }\r\n             }\r\n         }\r\ndiff --git a/UnityScripts/scripts/Objects/ObjectInteraction.cs b/UnityScripts/scripts/Objects/ObjectInteraction.cs\nindex d381fd0d..b0380ea0 100644\n--- a/UnityScripts/scripts/Objects/ObjectInteraction.cs\n+++ b/UnityScripts/scripts/Objects/ObjectInteraction.cs\n@@ -2444,6 +2444,8 @@ public class ObjectInteraction : UWEBase\n                             myObj.AddComponent<a_hack_trap_button_mover>(); break;\r\n                         case 0xA://Bonus object trap\r\n                             myObj.AddComponent<a_hack_trap_class_item>(); break;\r\n+                        case 0xC://\r\n+                            myObj.AddComponent<a_hack_trap_platformwave>(); break;\r\n                         case 0xE://colour cycle a room in talorus\r\n                             myObj.AddComponent<a_hack_trap_colour_cycle>(); break;\r\n                         case 0x1a://Forcefield in scint 5\t\t\t\t\t\t\t\t\t\t\r\ndiff --git a/UnityScripts/scripts/Traps/a_hack_trap_platformwave.cs b/UnityScripts/scripts/Traps/a_hack_trap_platformwave.cs\nnew file mode 100644\nindex 00000000..72da4ca2\n--- /dev/null\n+++ b/UnityScripts/scripts/Traps/a_hack_trap_platformwave.cs\n@@ -0,0 +1,206 @@\n+\ufeffusing System.Collections;\r\n+using System.Collections.Generic;\r\n+using UnityEngine;\r\n+\r\n+public class a_hack_trap_platformwave : a_hack_trap {\r\n+    //Raises or lowers tiles along a line\r\n+    //X000X111X\r\n+    //X = stationary platforms.\r\n+    //0 or 1 = tiles that goes up or down\r\n+    //The two sets of moving tiles are mirrored\r\n+    //Owner appears to control what state this trap is in  (always seems to be an odd number)\r\n+    //Owner is 5 at the highest peak (the first set)\r\n+    //Owner is 9 when flat\r\n+    //Owner is 13 when lowest\r\n+    //Example in void\r\n+    //10,51 to 10,45,  10,48 stays still in the middle.\r\n+\r\n+\r\n+    /// <summary>\r\n+    /// The colliders that are in contact with the trigger.\r\n+    /// </summary>\r\n+   // public Collider[,] colliders;\r\n+\r\n+    /// <summary>\r\n+    /// The position of the center of the tile.\r\n+    /// </summary>\r\n+    public Vector3 TileVector;\r\n+\r\n+    /// <summary>\r\n+    /// The contact area that detects the presence of objects.\r\n+    /// </summary>\r\n+    public Vector3 ContactArea = new Vector3(0.59f, 0.15f, 0.59f);\r\n+\r\n+    const int baseHeight = 18;\r\n+\r\n+    public override void ExecuteTrap(object_base src, int triggerX, int triggerY, int State)\r\n+    {\r\n+        //I would have expected to increment by 2 but there appears to be two seperate trigger chains acting on this trap in game\r\n+        owner++;\r\n+        if (owner > 15)\r\n+        {\r\n+            owner = 1;\r\n+        }\r\n+\r\n+        switch (owner)\r\n+        {\r\n+            case 1:\r\n+                ChangeTileHeight(10, 49, baseHeight-2);\r\n+                ChangeTileHeight(10, 50, baseHeight);\r\n+                ChangeTileHeight(10, 51, baseHeight-2);\r\n+\r\n+                ChangeTileHeight(10, 45, baseHeight + 2);\r\n+                ChangeTileHeight(10, 46, baseHeight);\r\n+                ChangeTileHeight(10, 47, baseHeight + 2);\r\n+\r\n+                break;\r\n+            case 3:\r\n+                ChangeTileHeight(10, 49, baseHeight + 4 -2);\r\n+                ChangeTileHeight(10, 50, baseHeight + 4 );\r\n+                ChangeTileHeight(10, 51, baseHeight + 4 -2);\r\n+\r\n+                ChangeTileHeight(10, 45, baseHeight  -4 + 2);\r\n+                ChangeTileHeight(10, 46, baseHeight -4 );\r\n+                ChangeTileHeight(10, 47, baseHeight -4 + 2);\r\n+\r\n+                break;\r\n+            case 5:\r\n+                ChangeTileHeight(10, 49, baseHeight+6-2);\r\n+                ChangeTileHeight(10, 50, baseHeight + 6);\r\n+                ChangeTileHeight(10, 51, baseHeight+6-2);\r\n+\r\n+                ChangeTileHeight(10, 45, baseHeight -6 + 2);\r\n+                ChangeTileHeight(10, 46, baseHeight - 6 );\r\n+                ChangeTileHeight(10, 47, baseHeight -6 + 2);\r\n+\r\n+                break;\r\n+            case 7:\r\n+                ChangeTileHeight(10, 49, baseHeight+4-2);\r\n+                ChangeTileHeight(10, 50, baseHeight + 4);\r\n+                ChangeTileHeight(10, 51, baseHeight+4-2);\r\n+\r\n+                ChangeTileHeight(10, 45, baseHeight -4+2);\r\n+                ChangeTileHeight(10, 46, baseHeight -4);\r\n+                ChangeTileHeight(10, 47, baseHeight -4+2);\r\n+\r\n+                break;\r\n+            case 9:\r\n+                ChangeTileHeight(10, 49, baseHeight);\r\n+                ChangeTileHeight(10, 50, baseHeight);\r\n+                ChangeTileHeight(10, 51, baseHeight);\r\n+\r\n+                ChangeTileHeight(10, 45, baseHeight );\r\n+                ChangeTileHeight(10, 46, baseHeight );\r\n+                ChangeTileHeight(10, 47, baseHeight);\r\n+\r\n+                break;\r\n+            case 11:\r\n+                ChangeTileHeight(10, 49, baseHeight-4+2);\r\n+                ChangeTileHeight(10, 50, baseHeight -4);\r\n+                ChangeTileHeight(10, 51, baseHeight-4+2);\r\n+\r\n+                ChangeTileHeight(10, 45, baseHeight +4-2);\r\n+                ChangeTileHeight(10, 46, baseHeight +4 );\r\n+                ChangeTileHeight(10, 47, baseHeight +4-2);\r\n+\r\n+                break;\r\n+            case 13:\r\n+                ChangeTileHeight(10, 49, baseHeight-6+2);\r\n+                ChangeTileHeight(10, 50, baseHeight -6);\r\n+                ChangeTileHeight(10, 51, baseHeight-6+2);\r\n+\r\n+                ChangeTileHeight(10, 45, baseHeight +6-2);\r\n+                ChangeTileHeight(10, 46, baseHeight+6);\r\n+                ChangeTileHeight(10, 47, baseHeight + 6-2);\r\n+\r\n+                break;\r\n+            case 15:\r\n+                ChangeTileHeight(10, 49, baseHeight-4+2);\r\n+                ChangeTileHeight(10, 50, baseHeight - 4);\r\n+                ChangeTileHeight(10, 51, baseHeight-4+2);\r\n+\r\n+                ChangeTileHeight(10, 45, baseHeight +4-2);\r\n+                ChangeTileHeight(10, 46, baseHeight + 4 );\r\n+                ChangeTileHeight(10, 47, baseHeight +4-2);\r\n+\r\n+                break;\r\n+        }\r\n+    }\r\n+\r\n+\r\n+    void ChangeTileHeight(int tileX, int tileY, int newHeight)\r\n+    {\r\n+        TileInfo t = CurrentTileMap().Tiles[tileX, tileY];\r\n+        //int curHeight = CurrentTileMap().Tiles[tileX, tileX].floorHeight;\r\n+        //Debug.Log("Changing height from " + curHeight + " to " + newHeight  + " at " + owner);\r\n+        //int diff = newHeight - curHeight;\r\n+        t.floorHeight = (short)newHeight;\r\n+        GameObject platformTile = GameWorldController.FindTile(tileX, tileY, TileMap.SURFACE_FLOOR);\r\n+        TileVector = CurrentTileMap().getTileVector(tileX, tileY);\r\n+        Collider[] colliders = Physics.OverlapBox(TileVector, ContactArea);\r\n+        \r\n+        MoveObjectsInContact((float)(newHeight) * 0.15f, colliders);\r\n+        \r\n+        //CurrentTileMap().Tiles[tileX, tileX].TileNeedsUpdate();\r\n+        DestroyImmediate(platformTile);\r\n+        TileMapRenderer.RenderTile(GameWorldController.instance.LevelModel, t.tileX, t.tileY, t, false, false, false, true);\r\n+        //MoveTile(platformTile.transform, new Vector3(0f, (float)(diff) * 0.3f, 0f), 0.1f, tileX, tileY);\r\n+    }\r\n+\r\n+\r\n+    public override bool WillFireRepeatedly()\r\n+    {\r\n+        return true;\r\n+    }\r\n+\r\n+    //protected void MoveTile(Transform platform, Vector3 dist, float traveltime, int TileXToWatch, int TileYToWatch)\r\n+    //{\r\n+    //    //Co-routine to move the tile to it\'s target position.\r\n+    //    //float rate = 1.0f / traveltime;\r\n+    //    //float index = 0.0f;\r\n+    //    //Vector3 StartPos = platform.position;\r\n+    //    //Vector3 EndPos = StartPos + dist;\r\n+    //    //this.transform.position = StartPos;\r\n+\r\n+\r\n+    //    DestroyImmediate(platform.gameObject);\r\n+\r\n+\r\n+    //    //while (index < 1.0f)\r\n+    //    //{\r\n+    //    //    Vector3 OldPosition = platform.position;\r\n+    //    //    platform.position = Vector3.Lerp(StartPos, EndPos, index);\r\n+    //    //    float height = TileVector.y;\r\n+    //    //    //move\r\n+    //    //    this.transform.position = platform.position;\r\n+    //    //    index += rate * Time.deltaTime;\r\n+    //    //    yield return new WaitForSeconds(0.01f);\r\n+    //    //}\r\n+    //    MoveObjectsInContact(EndPos.y, colliders);\r\n+    //    //platform.position = EndPos;\r\n+    //    //this.transform.position = EndPos;\r\n+    //}\r\n+\r\n+\r\n+    /// <summary>\r\n+    /// Moves the objects in contact.\r\n+    /// </summary>\r\n+    /// <param name="Height">Height.</param>\r\n+    /// Could be better.\r\n+    public void MoveObjectsInContact(float Height, Collider[] colliders)\r\n+    {\r\n+        for (int i = 0; i <= colliders.GetUpperBound(0); i++)\r\n+        {\r\n+            if (colliders[i].gameObject.GetComponent<ObjectInteraction>() != null)\r\n+            {\r\n+                if (colliders[i].gameObject.GetComponent<ObjectInteraction>().isMoveable())\r\n+                {\r\n+                    Vector3 objPosition = colliders[i].gameObject.transform.position;\r\n+                    UnFreezeMovement(colliders[i].gameObject);\r\n+                    colliders[i].gameObject.transform.position = new Vector3(objPosition.x, Height, objPosition.z);\r\n+                }\r\n+            }\r\n+        }\r\n+    }\r\n+\r\n+}\r\ndiff --git a/UnityScripts/scripts/Traps/a_null_trap.cs b/UnityScripts/scripts/Traps/a_null_trap.cs\nindex a37dffd9..d1b75195 100644\n--- a/UnityScripts/scripts/Traps/a_null_trap.cs\n+++ b/UnityScripts/scripts/Traps/a_null_trap.cs\n@@ -12,9 +12,4 @@ public class a_null_trap : trap_base\n \r\n     }\r\n \r\n-    public override void PostActivate(object_base src)\r\n-    {\r\n-        Debug.Log("Overridden PostActivate to test " + this.name);\r\n-        base.PostActivate(src);\r\n-    }\r\n }\n\\ No newline at end of file\ndiff --git a/UnityScripts/scripts/Traps/a_proximity_trap.cs b/UnityScripts/scripts/Traps/a_proximity_trap.cs\nindex e72417eb..4d6348ca 100644\n--- a/UnityScripts/scripts/Traps/a_proximity_trap.cs\n+++ b/UnityScripts/scripts/Traps/a_proximity_trap.cs\n@@ -7,40 +7,70 @@ using UnityEngine;\n /// </summary>\r\n /// This appears to behave as a move trigger rather than a trap.\r\n /// Appears to fires when the player passes through the trigger plane along a range of owner by quality tiles.\r\n-public class a_proximity_trap : a_move_trigger\r\n+public class a_proximity_trap : trap_base\r\n {\r\n-\tprotected override void Start ()\r\n+    protected Vector3 boxDimensions = new Vector3(1.2f, 1.2f, 1.2f);\r\n+    protected Vector3 boxCenter = Vector3.zero;\r\n+    private BoxCollider box;\r\n+\r\n+    protected override void Start ()\r\n \t{\r\n \t    boxDimensions= new Vector3(quality * 1.2f,0.2f,owner*1.2f);\r\n \t    boxCenter = new Vector3(quality * 0.6f,0f,owner*0.6f);\r\n-\t    base.Start ();\r\n+        box = this.gameObject.GetComponent<BoxCollider>();\r\n+        if (box == null)\r\n+        {\r\n+            box = this.gameObject.AddComponent<BoxCollider>();\r\n+        }\r\n+        box.size = boxDimensions;\r\n+        box.center = boxCenter;\r\n+        box.isTrigger = true;\r\n+        base.Start ();\r\n \t}\r\n \r\n \r\n-    public override bool Activate(GameObject src)\r\n+    public override void ExecuteTrap(object_base src, int triggerX, int triggerY, int State)\r\n     {\r\n-        //Debug.Log(this.name);\r\n-        GameObject triggerObj = ObjectLoader.getGameObjectAt(link);\r\n-        if (triggerObj != null)\r\n-        {\r\n-            if (triggerObj.GetComponent<trap_base>() != null)\r\n-            {\r\n-                triggerObj.GetComponent<trap_base>().Activate(this, quality, owner, flags);\r\n-            }\r\n-            else\r\n-            {\r\n-                if (triggerObj.GetComponent<trigger_base>() != null)\r\n-                {\r\n-                    triggerObj.GetComponent<trigger_base>().Activate(this.gameObject);\r\n-                }\r\n-            }\r\n-        }\r\n-        PostActivate(src);\r\n-        return true;\r\n+        //just pass to next object in chain\r\n     }\r\n \r\n+    //public override bool Activate(GameObject src)\r\n+    //{\r\n+    //    //Debug.Log(this.name);\r\n+    //    GameObject triggerObj = ObjectLoader.getGameObjectAt(link);\r\n+    //    if (triggerObj != null)\r\n+    //    {\r\n+    //        if (triggerObj.GetComponent<trap_base>() != null)\r\n+    //        {\r\n+    //            triggerObj.GetComponent<trap_base>().Activate(this, quality, owner, flags);\r\n+    //        }\r\n+    //        else\r\n+    //        {\r\n+    //            if (triggerObj.GetComponent<trigger_base>() != null)\r\n+    //            {\r\n+    //                triggerObj.GetComponent<trigger_base>().Activate(this.gameObject);\r\n+    //            }\r\n+    //        }\r\n+    //    }\r\n+    //    PostActivate(src);\r\n+    //    return true;\r\n+    //}\r\n+\r\n     public override bool WillFireRepeatedly()\r\n     {\r\n-        return (flags & 0x1) == 1;//Uses Trap rule\r\n+        //return (flags & 0x1) == 1;//Uses Trap rule\r\n+        return true;\r\n     }\r\n+\r\n+    //***Trigger behaviour\r\n+\r\n+    protected virtual void OnTriggerEnter(Collider other)\r\n+    {\r\n+        if (((other.name == UWCharacter.Instance.name) || (other.name == "Feet")) && (!GameWorldController.EditorMode) && (Quest.instance.InDreamWorld == false))\r\n+        {\r\n+            //Activate(other.gameObject);\r\n+            ExecuteTrap(this, owner, quality, flags);\r\n+        }\r\n+    }\r\n+\r\n }\r\ndiff --git a/UnityScripts/scripts/Traps/a_skill_trap.cs b/UnityScripts/scripts/Traps/a_skill_trap.cs\nindex ab32bd98..6c060b18 100644\n--- a/UnityScripts/scripts/Traps/a_skill_trap.cs\n+++ b/UnityScripts/scripts/Traps/a_skill_trap.cs\n@@ -17,7 +17,7 @@ public class a_skill_trap : trap_base {\n \n \tpublic override void ExecuteTrap (object_base src, int triggerX, int triggerY, int State)\n \t{\n-\t\tDebug.Log(this.name + " called with params q=" + quality + " o=" + owner);\n-\t\tbase.ExecuteTrap (src, triggerX, triggerY, State);\n+\t\t//Debug.Log(this.name + " called with params q=" + quality + " o=" + owner);\n+\t\t//base.ExecuteTrap (src, triggerX, triggerY, State);\n \t}\n }\ndiff --git a/UnityScripts/scripts/Traps/an_oscillator_trap.cs b/UnityScripts/scripts/Traps/an_oscillator_trap.cs\nindex 339ce1e9..8295f374 100644\n--- a/UnityScripts/scripts/Traps/an_oscillator_trap.cs\n+++ b/UnityScripts/scripts/Traps/an_oscillator_trap.cs\n@@ -66,19 +66,7 @@ public class an_oscillator_trap : trap_base\n \r\n         if (xpos == 1)\r\n         {//moving up\r\n-            CurrentTileMap().Tiles[triggerX, triggerY].floorHeight += 2;\r\n-            StartCoroutine(MoveTile(platformTile.transform, new Vector3(0f, 0.3f, 0f), 0.1f));\r\n-            if (CurrentTileMap().Tiles[triggerX, triggerY].floorHeight >= 30)\r\n-            {\r\n-                if (\r\n-                        (TileMap.visitTileX == triggerX)\r\n-                        &&\r\n-                        (TileMap.visitTileY == triggerY)\r\n-                )\r\n-                {//Kill the player if they are in the tile  (ouch my head)\r\n-                    UWCharacter.Instance.CurVIT -= 1000;\r\n-                }\r\n-            }\r\n+            MoveTileUp(triggerX, triggerY);\r\n         }\r\n         else\r\n         {//moving down\r\n@@ -87,6 +75,23 @@ public class an_oscillator_trap : trap_base\n         }\r\n     }\r\n \r\n+    private void MoveTileUp(int triggerX, int triggerY)\r\n+    {\r\n+        CurrentTileMap().Tiles[triggerX, triggerY].floorHeight += 2;\r\n+        StartCoroutine(MoveTile(platformTile.transform, new Vector3(0f, 0.3f, 0f), 0.1f));\r\n+        if (CurrentTileMap().Tiles[triggerX, triggerY].floorHeight >= 30)\r\n+        {\r\n+            if (\r\n+                    (TileMap.visitTileX == triggerX)\r\n+                    &&\r\n+                    (TileMap.visitTileY == triggerY)\r\n+            )\r\n+            {//Kill the player if they are in the tile  (ouch my head)\r\n+                UWCharacter.Instance.CurVIT -= 1000;\r\n+            }\r\n+        }\r\n+    }\r\n+\r\n     protected IEnumerator MoveTile(Transform platform, Vector3 dist, float traveltime)\r\n     {\r\n         //Co-routine to move the tile to it\'s target position.\r\n@@ -132,4 +137,9 @@ public class an_oscillator_trap : trap_base\n             }\r\n         }\r\n     }\r\n+\r\n+    public override bool WillFireRepeatedly()\r\n+    {\r\n+        return true;\r\n+    }\r\n }\r\ndiff --git a/UnityScripts/scripts/Triggers/a_timer_trigger.cs b/UnityScripts/scripts/Triggers/a_timer_trigger.cs\nindex 87bc86be..105cd58f 100644\n--- a/UnityScripts/scripts/Triggers/a_timer_trigger.cs\n+++ b/UnityScripts/scripts/Triggers/a_timer_trigger.cs\n@@ -1,74 +1,74 @@\n-\ufeffusing UnityEngine;\n-using System.Collections;\n-\n-public class a_timer_trigger : trigger_base {\n-\t\t//The zpos value appears to control it\'s rate of triggering.\n-\t\tfloat traptime=0f;\n-\t\tfloat interval=1f;\n-\n-\tprotected override void Start ()\n-\t{\n-\t\tbase.Start();\n-\t\tif (zpos!=0)\n-\t\t{\n-\t\t\tinterval=(float)zpos;\n-\t\t}\n-\t\telse\n-\t\t{\n-\t\t\tinterval=1;\n-\t\t}\n-\t}\n-\n-\tpublic override void Update ()\n-\t{\n-\t\tif (GameWorldController.instance.EnableTimerTriggers)\n-\t\t{\n-\t\t\tbase.Update ();\n-\t\t\ttraptime+=Time.deltaTime;\n-\t\t\tif(traptime> interval * GameWorldController.instance.TimerRate)\n-\t\t\t{\n-\t\t\t\tActivate(this.gameObject);\n-\t\t\t\ttraptime=0f;\n-\t\t\t}\t\t\t\n-\t\t}\t\n-\t\telse\n-\t\t{\n-\t\t\tif (TriggerMeNow)\n-\t\t\t{\n-\t\t\t\t\tbase.Update();\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\n-\n-\t\t//Override to supress debug messages.\n-\tpublic override bool Activate (GameObject src)\n-\t{\n-\t\tif (EditorMode)\n-\t\t{\n-\t\t\treturn true;\n-\t\t}\n-\t\tGameObject triggerObj = ObjectLoader.getGameObjectAt(link);\n-\t\tif (triggerObj!=null)\n-\t\t{\n+\ufeffusing UnityEngine;\r\n+using System.Collections;\r\n+\r\n+public class a_timer_trigger : trigger_base {\r\n+\t\t//The zpos value appears to control it\'s rate of triggering.\r\n+\t\tfloat traptime=0f;\r\n+\t\tfloat interval=1f;\r\n+\r\n+\tprotected override void Start ()\r\n+\t{\r\n+\t\tbase.Start();\r\n+\t\tif (zpos!=0)\r\n+\t\t{\r\n+\t\t\tinterval=(float)zpos;\r\n+\t\t}\r\n+\t\telse\r\n+\t\t{\r\n+\t\t\tinterval=1;\r\n+\t\t}\r\n+\t}\r\n+\r\n+\tpublic override void Update ()\r\n+\t{\r\n+\t\tif (GameWorldController.instance.EnableTimerTriggers)\r\n+\t\t{\r\n+\t\t\tbase.Update ();\r\n+\t\t\ttraptime+=Time.deltaTime;\r\n+\t\t\tif(traptime> interval * GameWorldController.instance.TimerRate)\r\n+\t\t\t{\r\n+\t\t\t\tActivate(this.gameObject);\r\n+\t\t\t\ttraptime=0f;\r\n+\t\t\t}\t\t\t\r\n+\t\t}\t\r\n+\t\telse\r\n+\t\t{\r\n+\t\t\tif (TriggerMeNow)\r\n+\t\t\t{\r\n+\t\t\t\t\tbase.Update();\r\n+\t\t\t}\r\n+\t\t}\r\n+\t}\r\n+\r\n+\r\n+\r\n+\t\t//Override to supress debug messages.\r\n+\tpublic override bool Activate (GameObject src)\r\n+\t{\r\n+\t\tif (EditorMode)\r\n+\t\t{\r\n+\t\t\treturn true;\r\n+\t\t}\r\n+\t\tGameObject triggerObj = ObjectLoader.getGameObjectAt(link);\r\n+\t\tif (triggerObj!=null)\r\n+\t\t{\r\n             if (triggerObj.GetComponent<trap_base>()!=null)\r\n             {\r\n                 triggerObj.GetComponent<trap_base>().Activate(this, quality, owner, flags);\r\n-            }\n-            else\r\n-            {\r\n-                Debug.Log("null trap on " + this.name);\r\n-            }\n-\t\t\t\n-\t\t}\n-\n-\t\tPostActivate(src);\n-\t\treturn true;\n-\t}\n-\n-\t\t//DO not destroy\n-\t\t//public virtual void PostActivate()\n-\t\t//{\n-\t\t//}\n-}\n+            }\r\n+           // else\r\n+            //{\r\n+                   //Debug.Log("null trap on " + this.name);                 \r\n+            //}\r\n+\t\t\t\r\n+\t\t}\r\n+\r\n+\t\tPostActivate(src);\r\n+\t\treturn true;\r\n+\t}\r\n+\r\n+\t\t//DO not destroy\r\n+\t\t//public virtual void PostActivate()\r\n+\t\t//{\r\n+\t\t//}\r\n+}\r\ndiff --git a/UnityScripts/scripts/World/GameWorldController.cs b/UnityScripts/scripts/World/GameWorldController.cs\nindex b704a8dd..55d3ed29 100644\n--- a/UnityScripts/scripts/World/GameWorldController.cs\n+++ b/UnityScripts/scripts/World/GameWorldController.cs\n@@ -17,6 +17,7 @@ using UnityEngine.UI;\n public class GameWorldController : UWEBase\r\n {\r\n     public bool EnableUnderworldGenerator = false;\r\n+    public bool DoCleanUp = true;\r\n     public GameObject ceiling;\r\n \r\n     public WhatTheHellIsSCD_ARK whatTheHellIsThatFileFor;\r\ndiff --git a/UnityScripts/scripts/World/TileInfo.cs b/UnityScripts/scripts/World/TileInfo.cs\nindex cd0286c2..e402feda 100644\n--- a/UnityScripts/scripts/World/TileInfo.cs\n+++ b/UnityScripts/scripts/World/TileInfo.cs\n@@ -212,6 +212,13 @@ public class TileInfo : Loader\n                 break;\r\n         }\r\n \r\n+        if (_RES==GAME_UWDEMO)\r\n+        {//texture_map[t.floorTexture + 48];\r\n+            if (map.texture_map[floorTexture + 48] == 56)\r\n+            {\r\n+                _terrain = TerrainDatLoader.Water;\r\n+            }\r\n+        }\r\n         //There is only one possible steepness in UW so I set it\'s properties to match a similar tile in shock.\r\n         shockSlopeFlag = TileMap.SLOPE_FLOOR_ONLY;\r\n         if (tileType >= 2)\r\ndiff --git a/UnityScripts/scripts/World/TileMap.cs b/UnityScripts/scripts/World/TileMap.cs\nindex b476b568..dc580560 100644\n--- a/UnityScripts/scripts/World/TileMap.cs\n+++ b/UnityScripts/scripts/World/TileMap.cs\n@@ -696,6 +696,7 @@ Tiles[x,y].shockSouthCeilHeight =LevelInfo[x,y-1].ceilingHeight - LevelInfo[x,y-\n     /// Although the tile map renderer supports tiles of size X*Y I\'m only smart enought to optimise the tilemap into strips of X*1 or Y*1 !!\r\n     public void CleanUp(string game)\r\n     {\r\n+        if (!GameWorldController.instance.DoCleanUp) { return; }\r\n         int x; int y;\r\n \r\n         for (x = 0; x <= TileMap.TileMapSizeX; x++)\r\n', 'commit_subject': "Rough implementation of the oscillating platforms trap in the ethereal void purple region Npcs without containers won't be prevented from having conversations", 'repo_name': 'hankmorgan/UnderworldExporter', 'committer': {'name': 'hankmorgan', 'email': 'b1fd6e89686dd9eb01dc9c28a3367dc940d79455@yahoo.co.uk', 'time_sec': '1536515967', 'tz_offset': '60', 'date': {'seconds': '1536515967'}}, 'commit_tree': '508359ffc6320e4cb4c28a775b9cf5ca8c7209cd', 'commit_message': "Rough implementation of the oscillating platforms trap in the ethereal void purple region\nNpcs without containers won't be prevented from having conversations\n", 'language_name': 'C++', 'license': 'mit', 'hunks': "@@ -696,6 +696,7 @@ Tiles[x,y].shockSouthCeilHeight =LevelInfo[x,y-1].ceilingHeight - LevelInfo[x,y-\n     /// Although the tile map renderer supports tiles of size X*Y I'm only smart enought to optimise the tilemap into strips of X*1 or Y*1 !!\r\n     public void CleanUp(string game)\r\n     {\r\n+        if (!GameWorldController.instance.DoCleanUp) { return; }\r\n         int x; int y;\r\n \r\n         for (x = 0; x <= TileMap.TileMapSizeX; x++)\r\n", 'addition_count': 1, 'deletion_count': 0, 'src_file': 'a/UnityScripts/scripts/World/TileMap.cs', 'tgt_file': 'b/UnityScripts/scripts/World/TileMap.cs', 'file_extension': '.cs', 'before_file': 'using UnityEngine;\nusing System.Collections;\nusing UnityEngine.UI;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.IO;\n\n/// <summary>\n/// Tile map class for storing and accessing the tilemap and tile properties..\n/// </summary>\npublic class TileMap : Loader\n{\n\n    //Raw Data\n    public DataLoader.UWBlock lev_ark_block = new DataLoader.UWBlock();//Data containing tilemap.\n    public DataLoader.UWBlock tex_ark_block = new DataLoader.UWBlock();//Data containing texture map\n    public DataLoader.UWBlock ovl_ark_block = new DataLoader.UWBlock();//Data containing animation overlays\n\n\n    //Tile Types for UW1 & 2 and SS1. Note the diag tiles are flipped around in SS1.\n    public const short TILE_SOLID = 0;\n    public const short TILE_OPEN = 1;\n    public const short TILE_DIAG_SE = 2;\n    public const short TILE_DIAG_SW = 3;\n    public const short TILE_DIAG_NE = 4;\n    public const short TILE_DIAG_NW = 5;\n    public const short TILE_SLOPE_N = 6;\n    public const short TILE_SLOPE_S = 7;\n    public const short TILE_SLOPE_E = 8;\n    public const short TILE_SLOPE_W = 9;\n    public const short TILE_VALLEY_NW = 10;\n    public const short TILE_VALLEY_NE = 11;\n    public const short TILE_VALLEY_SE = 12;\n    public const short TILE_VALLEY_SW = 13;\n    public const short TILE_RIDGE_SE = 14;\n    public const short TILE_RIDGE_SW = 15;\n    public const short TILE_RIDGE_NW = 16;\n    public const short TILE_RIDGE_NE = 17;\n\n    /// <summary>\n    /// The tile map size along the x axis\n    /// </summary>\n    public const short TileMapSizeX = 63; //0 to 63\n\n    /// <summary>\n    /// The tile map size along the y axis.\n    /// </summary>\n    public const short TileMapSizeY = 63; //0 to 63\n\n    /// <summary>\n    /// Locaton X and Y of the object storage tile location where non map objects are kept.\n    /// </summary>\n    public const short ObjectStorageTile = 99;\n\n    public const short SURFACE_FLOOR = 1;\n    public const short SURFACE_CEIL = 2;\n    public const short SURFACE_WALL = 3;\n    public const short SURFACE_SLOPE = 4;\n\n    public const short SLOPE_BOTH_PARALLEL = 0;\n    public const short SLOPE_BOTH_OPPOSITE = 1;\n    public const short SLOPE_FLOOR_ONLY = 2;\n    public const short SLOPE_CEILING_ONLY = 3;\n\n    //Visible faces indices. Used in sorting tile surface visiblity.\n    public const short vTOP = 0;\n    public const short vEAST = 1;\n    public const short vBOTTOM = 2;\n    public const short vWEST = 3;\n    public const short vNORTH = 4;\n    public const short vSOUTH = 5;\n\n\n    //BrushFaces\n    const short fSELF = 128;\n    const short fCEIL = 64;\n    const short fNORTH = 32;\n    const short fSOUTH = 16;\n    const short fEAST = 8;\n    const short fWEST = 4;\n    const short fTOP = 2;\n    const short fBOTTOM = 1;\n\n    public const int UW1_TEXTUREMAPSIZE = 64;\n    public const int UW2_TEXTUREMAPSIZE = 70;\n    public const int UWDEMO_TEXTUREMAPSIZE = 63;\n\n    public const int UW1_NO_OF_LEVELS = 9;\n    public const int UW2_NO_OF_LEVELS = 80;\n\n    /// <summary>\n    /// The ceiling texture for this level\n    /// </summary>\n    public short UWCeilingTexture;\n\n    /// <summary>\n    /// Animation overlay. Controls how long an animated effect appears for.\n    /// </summary>\n    public struct Overlay  \n    {\n        public int header;\n        public int link;\n        public int duration;\n        public int tileX;\n        public int tileY;\n    };\n\n    /// <summary>\n    /// Lists of overlays for controlling animated items.\n    /// </summary>\n    public Overlay[] Overlays = new Overlay[64];\n\n    public short thisLevelNo; //The number of this level\n    public short UW_CEILING_HEIGHT;\n    public short CEILING_HEIGHT;\n    public short SHOCK_CEILING_HEIGHT;\n\n    /// <summary>\n    /// The texture indices for the current map.\n    /// </summary>\n    public short[] texture_map = new short[272];\n\n\n    /// <summary>\n    /// Tile info storage class\n    /// </summary>\n    public TileInfo[,] Tiles = new TileInfo[TileMap.TileMapSizeX + 1, TileMap.TileMapSizeY + 1];\n\n    /// <summary>\n    /// The current tile X that the player is in\n    /// </summary>\n    public static short visitTileX;\n    /// <summary>\n    /// The current tile Y that the player is in.\n    /// </summary>\n    public static short visitTileY;\n\n    /// The tile X that the player was in the previous frame\n    /// </summary>\n    public static short visitedTileX;\n    /// <summary>\n    /// The current tile Y that the player was in the previous frame\n    /// </summary>\n    public static short visitedTileY;\n\n\n    /// <summary>\n    /// Reference to the objects list for this level.\n    /// </summary>\n    public ObjectLoader LevelObjects\n    {\n        get\n        {\n            return GameWorldController.instance.objectList[thisLevelNo];\n        }\n    }\n\n\n    public TileMap(short NewLevelNo)\n    {\n        thisLevelNo = NewLevelNo;\n    }\n\n    /// <summary>\n    /// Checks to see if the tile at a specified location is within the valid game world. (eg is rendered and is not a solid).\n    /// Assumes the map is positioned at 0,0,0\n    /// </summary>\n    /// <returns><c>true</c>, if tile was valided, <c>false</c> otherwise.</returns>\n    /// <param name="location">Location.</param>\n    public bool ValidTile(Vector3 location)\n    {\n        int tileX = (int)(location.x / 1.2f);\n        int tileY = (int)(location.y / 1.2f);\n        if ((tileX > TileMap.TileMapSizeX) || (tileX < 0) || (tileY > TileMap.TileMapSizeY) || (tileY < 0))\n        {//Location is outside the map\n            return false;\n        }\n        int tileType = GetTileType(tileX, tileY);\n        bool isRendered = GetTileRender(tileX, tileY);\n\n        return ((tileType != TILE_SOLID) && (isRendered));\n    }\n\n    /// <summary>\n    /// Validates the tile to see if it is within the range of tiles.\n    /// </summary>\n    /// <returns><c>true</c>, if tile was valided, <c>false</c> otherwise.</returns>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    public static bool ValidTile(int tileX, int tileY)\n    {\n        return (((tileX >= 0) && (tileX <= TileMapSizeX)) && ((tileY >= 0) && (tileY <= TileMapSizeY)));\n    }\n\n    /// <summary>\n    /// Tells if the tile is one of the square open types\n    /// </summary>\n    /// <returns><c>true</c>, if tile open was ised, <c>false</c> otherwise.</returns>\n    /// <param name="TileType">Tile type.</param>\n    public static bool isTileOpen(int TileType)\n    {\n        switch (TileType)\n        {\n            case TILE_OPEN:\n            case TILE_SLOPE_N:\n            case TILE_SLOPE_S:\n            case TILE_SLOPE_E:\n            case TILE_SLOPE_W:\n                {\n                    return true;\n                }\n            default:\n                {\n                    return false;\n                }\n        }\n    }\n\n    /// <summary>\n    /// Gets the height of the floor for the specified tile.\n    /// </summary>\n    /// <returns>The floor height.</returns>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    public int GetFloorHeight(int tileX, int tileY)\n    {\n        if (ValidTile(tileX, tileY))\n        {\n            return Tiles[tileX, tileY].floorHeight;\n        }\n        else\n        {\n           // Debug.Log("invalid tile for height at " + tileX + "," + tileY);\n            return 0;\n        }\n    }\n\n    /// <summary>\n    /// Gets the height of the ceiling. Will always be the same value in UW1/2 varies in SHOCK.\n    /// </summary>\n    /// <returns>The ceiling height.</returns>\n    /// <param name="LevelNo">Level no.</param>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    public int GetCeilingHeight(int tileX, int tileY)\n    {\n        return Tiles[tileX, tileY].ceilingHeight;\n    }\n\n    /// <summary>\n    /// Sets the height of the floor.\n    /// </summary>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    /// <param name="newHeight">New height.</param>\n    public void SetFloorHeight(int tileX, int tileY, short newHeight)\n    {\n        Tiles[tileX, tileY].floorHeight = newHeight;\n    }\n\n    /// <summary>\n    /// Sets the height of the ceiling.\n    /// </summary>\n    /// <param name="LevelNo">Level no.</param>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    /// <param name="newHeight">New height.</param>\n    public void SetCeilingHeight(int tileX, int tileY, short newHeight)\n    {\n        //Debug.Log ("ceil :" + newHeight + " was " + CeilingHeight[tileX,tileY]);\n        Tiles[tileX, tileY].ceilingHeight = newHeight;\n    }\n\n\n    /// <summary>\n    /// Gets the type of the tile.\n    /// </summary>\n    /// <returns>The tile type.</returns>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    public int GetTileType(int tileX, int tileY)\n    {\n        //if ((tileX>TileMap.TileMapSizeX) || (tileY>TileMap.TileMapSizeY) || (tileX<0) || (tileY<0))\n        if (!TileMap.ValidTile(tileX, tileY))\n        {//Assume out of bounds is solid\n            return TILE_SOLID;\n        }\n        else\n        {\n            return Tiles[tileX, tileY].tileType;\n        }\n    }\n\n    /// <summary>\n    /// Gets the room region at the specified tile\n    /// </summary>\n    /// <returns>The room.</returns>\n    /// <param name="TileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    public int GetRoom(int tileX, int tileY)\n    {\n        if (TileMap.ValidTile(tileX, tileY))\n        {\n            return Tiles[tileX, tileY].roomRegion;\n        }\n        else\n        {\n            return 0;\n        }\n    }\n\n\n    /// <summary>\n    /// Gets the tile render state. \n    /// </summary>\n    /// <returns>The tile render.</returns>\n    /// <param name="LevelNo">Level no.</param>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    private bool GetTileRender(int tileX, int tileY)\n    {\n        return Tiles[tileX, tileY].Render == true;\n    }\n\n    /// <summary>\n    /// Gets the vector3 at the center of the tile specified.\n    /// </summary>\n    /// <returns>The tile vector.</returns>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    public Vector3 getTileVector(int tileX, int tileY)\n    {\n        return new Vector3(\n                (((float)tileX) * 1.2f) + 0.6f,\n                (float)GetFloorHeight(tileX, tileY) * 0.15f,\n                (((float)tileY) * 1.2f) + 0.6f\n        );\n    }\n\n    /// <summary>\n    /// Gets the vector3 at the center of the tile specified.\n    /// </summary>\n    /// <returns>The tile vector.</returns>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    public Vector3 getTileVector(float tileX, float tileY)\n    {\n        return getTileVector((int)tileX, (int)tileY);\n    }\n\n    /// <summary>\n    /// Gets the vector3 at the center of the tile specified.\n    /// </summary>\n    /// <returns>The tile vector.</returns>\n    /// <param name="tileX">Tile x.</param>\n    /// <param name="tileY">Tile y.</param>\n    public Vector3 getTileVector(int tileX, int tileY, float zpos)\n    {\n        return new Vector3(\n                (((float)tileX) * 1.2f) + 0.6f,\n                zpos,\n                (((float)tileY) * 1.2f) + 0.6f\n        );\n    }\n\n\n\n    public bool BuildTileMapUW(int levelNo, DataLoader.UWBlock lev_ark, DataLoader.UWBlock tex_ark, DataLoader.UWBlock ovl_ark)\n    {\n        long address_pointer = 0;\n        short CeilingTexture = 0;\n\n        UW_CEILING_HEIGHT = ((128 >> 2) * 8 >> 3);  //Shifts the scale of the level. Idea borrowed from abysmal\n\n        CEILING_HEIGHT = UW_CEILING_HEIGHT;\n        BuildTextureMap(tex_ark, ref CeilingTexture, levelNo);\n        this.UWCeilingTexture = CeilingTexture;\n        for (short y = 0; y <= TileMap.TileMapSizeY; y++)\n        {\n            for (short x = 0; x <= TileMap.TileMapSizeX; x++)\n            {\n                int FirstTileInt = (int)DataLoader.getValAtAddress(lev_ark, (address_pointer + 0), 16);\n                int SecondTileInt = (int)DataLoader.getValAtAddress(lev_ark, (address_pointer + 2), 16);\n                Tiles[x, y] = new TileInfo(this, x, y);\n                address_pointer = address_pointer + 4;\n            }\n        }\n\n        SetTileMapWallFacesUW();\n\n\n        //if (OverlayAddress!=0)\n        switch (_RES)\n        {\n            case GAME_UW1:\n                {\n                    if (ovl_ark.DataLen != 0)\n                    {//read in the next 64 entries of length 6 bytes\t\n                        long OverlayAddress = 0;\n                        for (int overlayIndex = 0; overlayIndex < 64; overlayIndex++)\n                        {\n                            Overlays[overlayIndex].header = (int)DataLoader.getValAtAddress(ovl_ark, OverlayAddress, 16);\n                            Overlays[overlayIndex].link = (int)(DataLoader.getValAtAddress(ovl_ark, OverlayAddress, 16) >> 6) & 0x3ff;\n                            Overlays[overlayIndex].duration = (int)DataLoader.getValAtAddress(ovl_ark, OverlayAddress + 2, 16);\n                            Overlays[overlayIndex].tileX = (int)DataLoader.getValAtAddress(ovl_ark, OverlayAddress + 4, 8);\n                            Overlays[overlayIndex].tileY = (int)DataLoader.getValAtAddress(ovl_ark, OverlayAddress + 5, 8);\n                            if (Overlays[overlayIndex].link!=0)\n                            {\n                               // Debug.Log("Overlay at " + OverlayAddress\n                                //    + " obj " + Overlays[overlayIndex].link\n                               //     + " for " + Overlays[overlayIndex].duration\n                               //     + " tile " + Overlays[overlayIndex].tileX + "," + Overlays[overlayIndex].tileY\n                               //     + " header :" + Overlays[overlayIndex].header);\n                            }                            \n                            OverlayAddress += 6;\n                        }\n                    }\n                    break;\n                }\n            case GAME_UW2:\n                {\n                    long OverlayAddress = 31752;\n                    for (int overlayIndex = 0; overlayIndex < 64; overlayIndex++)\n                    {\n                        if (OverlayAddress + 5 <= lev_ark.Data.GetUpperBound(0))\n                        {\n                            Overlays[overlayIndex].header = (int)DataLoader.getValAtAddress(lev_ark, OverlayAddress, 16);\n                            Overlays[overlayIndex].link = (int)(DataLoader.getValAtAddress(lev_ark, OverlayAddress, 16)>> 6) & 0x3ff;\n                            Overlays[overlayIndex].duration = (int)DataLoader.getValAtAddress(lev_ark, OverlayAddress + 2, 16);\n                            Overlays[overlayIndex].tileX = (int)DataLoader.getValAtAddress(lev_ark, OverlayAddress + 4, 8);\n                            Overlays[overlayIndex].tileY = (int)DataLoader.getValAtAddress(lev_ark, OverlayAddress + 5, 8);\n                            if (Overlays[overlayIndex].link != 0)\n                            {\n                               // Debug.Log("Overlay at " + OverlayAddress \n                               //     + " obj " + Overlays[overlayIndex].link \n                               //     + " for " + Overlays[overlayIndex].duration \n                               //     + " tile " + Overlays[overlayIndex].tileX + "," + Overlays[overlayIndex].tileY\n                                //    + " header :" + Overlays[overlayIndex].header);\n                            }\n                        }\n                        OverlayAddress += 6;\n                    }\n                    break;\n                }\n\n        }\n\n        return true;\n    }\n\n    /// <summary>\n    /// Creates the tile map wall textures for each north, south, east and west faces\n    /// </summary>\n    /// <param name="x">The x coordinate.</param>\n    /// <param name="y">The y coordinate.</param>\n    public void SetTileMapWallFacesUW()\n    {\n        short x; short y;\n        for (y = 0; y <= TileMap.TileMapSizeY; y++)\n        {\n            for (x = 0; x <= TileMap.TileMapSizeX; x++)\n            {\n                SetTileWallFacesUW(x, y);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Sets the tile wall faces for the selected tile\n    /// </summary>\n    /// <param name="x">The x coordinate.</param>\n    /// <param name="y">The y coordinate.</param>\n    public void SetTileWallFacesUW(short x, short y)\n    {\n        if (Tiles[x, y].tileType >= 0)//was just solid only. Note: If textures are all wrong it\'s probably caused here!\n        {\n            //assign it\'s north texture\n            if (y < TileMap.TileMapSizeY)\n            {\n                Tiles[x, y].North = Tiles[x, y + 1].wallTexture;\n            }\n            else\n            {\n                Tiles[x, y].North = -1;\n            }\n            //assign it\'s southern\n            if (y > 0)\n            {\n                Tiles[x, y].South = Tiles[x, y - 1].wallTexture;\n            }\n            else\n            {\n                Tiles[x, y].South = -1;\n            }\n            //it\'s east\n            if (x < TileMap.TileMapSizeX)\n            {\n                Tiles[x, y].East = Tiles[x + 1, y].wallTexture;\n            }\n            else\n            {\n                Tiles[x, y].East = -1;\n            }\n            //assign it\'s West\n            if (x > 0)\n            {\n                Tiles[x, y].West = Tiles[x - 1, y].wallTexture;\n            }\n            else\n            {\n                Tiles[x, y].West = -1;\n            }\n        }\n    }\n\n    public bool BuildTileMapShock(char[] archive_ark, int LevelNo)\n    {\n        long address_pointer = 4;\n        //LevelInfo=new TileInfo[64,64];\n\n        //char[] archive_ark; //file data\n        DataLoader.Chunk lev_ark;\n        /*  unsigned char *tmp_ark; \nunsigned char *sub_ark;*/\n        DataLoader.Chunk tex_ark;\n        DataLoader.Chunk inf_ark;\n\n\n\n\n        //Read in the archive.\n        //if (!DataLoader.ReadStreamFile(filePath, out archive_ark))\n        //{\n        //\t\t\treturn false;\n        //}\n\n        if (!DataLoader.LoadChunk(archive_ark, LevelNo * 100 + 4004, out inf_ark))\n        {//Read in the evel properties.\n            return false;\n        }\n        //Process level properties (height c-space)\n        int HeightUnits = (int)DataLoader.getValAtAddress(inf_ark.data, 16, 32);  //Log2 value. The higher the value the lower the level height.\n        if (HeightUnits > 3)  //Any higher we lose data, \n        {\n            HeightUnits = 3;\n        }\n        //int cSpace = (int)DataLoader.getValAtAddress(inf_ark.data,24,32);  //Per docs should return 1 on cyberspace. Does\'nt appear to work.\n        SHOCK_CEILING_HEIGHT = (short)(((256 >> HeightUnits) * 8 >> 3));  //Shifts the scale of the level.\n        CEILING_HEIGHT = SHOCK_CEILING_HEIGHT;\n\n\n        //long sizeV = getValAtAddress(inf_ark,0,32);\n        //long sizeH = getValAtAddress(inf_ark,4,32);\n        //long always6_1 = getValAtAddress(inf_ark,8,32);\n        //long always6_2 = getValAtAddress(inf_ark,12,32);  \n\n        if (!DataLoader.LoadChunk(archive_ark, LevelNo * 100 + 4005, out lev_ark))\n        {//Read in the level tilemap data\n            return false;\n        }\n        //Read the main level data in\n        /* blockAddress =getShockBlockAddress(LevelNo*100+4005,archive_ark, ref chunkPackedLength,ref chunkUnpackedLength,ref chunkType); \nif (blockAddress == -1) {return false;}\nlev_ark=new char[chunkUnpackedLength]; //or 64*64*16\nLoadShockChunk(blockAddress, chunkType, archive_ark, ref lev_ark,chunkPackedLength,chunkUnpackedLength);\nAddressOfBlockStart=0;\naddress_pointer=0;  */\n\n\n        if (!DataLoader.LoadChunk(archive_ark, LevelNo * 100 + 4007, out tex_ark))\n        {//Read in the level texture data\n            return false;\n        }\n\n        //get the texture data from the archive.is never compressed?\n        //AddressOfBlockStart = getShockBlockAddress(4007+ LevelNo*100, archive_ark, ref chunkPackedLength, ref chunkUnpackedLength,ref chunkType);\n        //tex_ark = new char[chunkUnpackedLength]; \n        address_pointer = 0;\n        for (long k = 0; k < tex_ark.chunkUnpackedLength / 2; k++)\n        {\n            texture_map[k] = (short)DataLoader.getValAtAddress(tex_ark.data, address_pointer, 16);\n            address_pointer = address_pointer + 2;   //tmp_ark[AddressOfBlockStart+k];\n        }\n        address_pointer = 0;\n\n\n        //Reactor   Map 0  (chunk 40xx)\n        //Levels 1-9  Map L  (chunk 4Lxx)\n        //SHODAN c/space  Map 10 (chunk 50xx)\n        //Delta grove Map 11 (chunk 51xx)\n        //Alpha grove Map 12 (chunk 52xx)\n        //Beta grove  Map 13 (chunk 53xx)\n        //C/space L1-2    Map 14 (chunk 54xx)\n        //C/space other Map 15 (chunk 55xx)\n        for (int y = 0; y <= TileMap.TileMapSizeY; y++)\n        {\n            for (int x = 0; x <= TileMap.TileMapSizeX; x++)\n            {\n                //Read in the tile data \n                Tiles[x, y] = new TileInfo();\n                Tiles[x, y].tileX = (short)x;\n                Tiles[x, y].tileY = (short)y;\n                Tiles[x, y].tileType = (short)lev_ark.data[address_pointer];\n                switch (Tiles[x, y].tileType)\n                {//Need to swap some tile types around so that they conform to uw naming standards.\n                    case 4: { Tiles[x, y].tileType = 5; break; }\n                    case 5: { Tiles[x, y].tileType = 4; break; }\n                    case 7: { Tiles[x, y].tileType = 8; break; }\n                    case 8: { Tiles[x, y].tileType = 7; break; }\n                }\n                Tiles[x, y].indexObjectList = 0;\n                Tiles[x, y].Render = true;\n                Tiles[x, y].DimX = 1;\n                Tiles[x, y].DimY = 1;\n                Tiles[x, y].Grouped = false;\n                for (int v = 0; v < 6; v++)\n                {\n                    Tiles[x, y].VisibleFaces[v] = true;\n                }\n                /* word 6 contains\n0-5 Wall texture (index into texture list)\n6-10  Ceiling texture\n11-15 Floor texture\n*/\n                //Tiles[x,y].wallTexture = texture_map[(int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) & 0x3F];\n                Tiles[x, y].wallTexture = (short)(DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) & 0x3F);\n                //Tiles[x,y].shockCeilingTexture = texture_map[((int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) >> 6) & 0x1F];\n                Tiles[x, y].shockCeilingTexture = (short)((DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) >> 6) & 0x1F);\n                //Tiles[x,y].floorTexture = texture_map[((int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) >> 11) & 0x1F];\n                Tiles[x, y].floorTexture = (short)((DataLoader.getValAtAddress(lev_ark.data, address_pointer + 6, 16) >> 11) & 0x1F);\n                //Tiles[x,y].wallTexture = 270;//debug\n                //Tiles[x,y].shockCeilingTexture = 273;\n                Tiles[x, y].North = Tiles[x, y].wallTexture;\n                Tiles[x, y].South = Tiles[x, y].wallTexture;\n                Tiles[x, y].East = Tiles[x, y].wallTexture;\n                Tiles[x, y].West = Tiles[x, y].wallTexture;\n\n                //Water xTiles[x, y].isWater = false;  //No swimming in shock.\n                //Tiles[x, y].landRegion = 0;\n                //Tiles[x, y].lavaRegion = 0;\n                //Tiles[x, y].waterRegion = 0;\n                Tiles[x, y].floorHeight = (short)((lev_ark.data[address_pointer + 1]) & 0x1F);\n                Tiles[x, y].floorHeight = (short)(((Tiles[x, y].floorHeight << 3) >> HeightUnits) * 8 >> 3); //Shift it for varying height scales\n\n                Tiles[x, y].ceilingHeight = (short)((lev_ark.data[address_pointer + 2]) & 0x1F);\n                Tiles[x, y].ceilingHeight = (short)(((Tiles[x, y].ceilingHeight << 3) >> HeightUnits) * 8 >> 3); //Shift it for varying height scales\n\n                Tiles[x, y].shockFloorOrientation = (short)(((lev_ark.data[address_pointer + 1]) >> 5) & 0x3);\n                Tiles[x, y].shockCeilOrientation = (short)(((lev_ark.data[address_pointer + 2]) >> 5) & 0x3);\n\n                //Need to know heights in various directions for alignments.\n                //Will set these properly after loading levels.\n                Tiles[x, y].shockNorthCeilHeight = Tiles[x, y].ceilingHeight;\n                Tiles[x, y].shockSouthCeilHeight = Tiles[x, y].ceilingHeight;\n                Tiles[x, y].shockEastCeilHeight = Tiles[x, y].ceilingHeight;\n                Tiles[x, y].shockWestCeilHeight = Tiles[x, y].ceilingHeight;\n\n                Tiles[x, y].TileSlopeSteepness = (short)(lev_ark.data[address_pointer + 3] & 0x0f);\n                Tiles[x, y].TileSlopeSteepness = (short)(((Tiles[x, y].TileSlopeSteepness << 3) >> HeightUnits) * 8 >> 3); //Shift it for varying height scales\n\n                if ((Tiles[x, y].TileSlopeSteepness == 0) && (Tiles[x, y].tileType >= 6))//If a sloped tile has no slope then it\'s a open tile.\n                {\n                    Tiles[x, y].tileType = 1;\n                }\n                if ((Tiles[x, y].tileType == 1) && (Tiles[x, y].TileSlopeSteepness > 0))  //similarly an open tile can\'t have a slope at all\n                {\n                    Tiles[x, y].TileSlopeSteepness = 0;\n                }\n                Tiles[x, y].indexObjectList = (int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 4, 16);\n\n\n                //if(Tiles[x,y].indexObjectList!=0)\n                //  {\n                //  fprintf(LOGFILE,"At %d %d we have: %d\\n", x,y,Tiles[x,y].indexObjectList);\n                //  }\n\n                /*\nxxxxx0xx  Floor & ceiling, same direction\nxxxxx4xx  Floor & ceiling, ceiling opposite dir to tile type\nxxxxx8xx  Floor only\nxxxxxCxx  Ceiling only\n*/\n                Tiles[x, y].shockSlopeFlag = (short)((DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) >> 10) & 0x03);\n                Tiles[x, y].UseAdjacentTextures = (short)((DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) >> 8) & 0x01);\n                Tiles[x, y].shockTextureOffset = (short)(DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) & 0xF);\n                //unknownflags\n                //70E000E0\n                //  fprintf(LOGFILE,"\\nUnknownflags @ %d %d= %d",x,y, getValAtAddress(lev_ark,address_pointer+8,32) & 0x70E000E0);\n                Tiles[x, y].shockShadeLower = (short)(((int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) >> 16) & 0x0F);\n                Tiles[x, y].shockShadeUpper = (short)(((int)DataLoader.getValAtAddress(lev_ark.data, address_pointer + 8, 32) >> 24) & 0x0F);\n                //Tiles[x,y].shadeUpperGlobal = 0;\n                // Tiles[x,y].shadeLowerGlobal = 0;\n                Tiles[x, y].shockNorthOffset = Tiles[x, y].shockTextureOffset;\n                Tiles[x, y].shockSouthOffset = Tiles[x, y].shockTextureOffset;\n                Tiles[x, y].shockEastOffset = Tiles[x, y].shockTextureOffset;\n    /// Although the tile map renderer supports tiles of size X*Y I\'m only smart enought to optimise the tilemap into strips of X*1 or Y*1 !!\r\n    public void CleanUp(string game)\r\n    {\r\n        int x; int y;\r\n\r\n        for (x = 0; x <= TileMap.TileMapSizeX; x++)\r\n                //Tiles[x,y].indexObjectList=0;\n                //if (y == 0)\n                //{\n                //  Tiles[x,y].tileType = TILE_SLOPE_N;\n                //  Tiles[x,y].shockSlopeFlag=SLOPE_FLOOR_ONLY;\n                //  Tiles[x,y].floorHeight=x;\n                //  Tiles[x,y].shockSteep=11;\n                //}\n                address_pointer = address_pointer + 16;\n            }\n        }\n\n        for (int y = 1; y < TileMap.TileMapSizeY; y++) //skip the outer textures.\n        {\n            for (int x = 1; x < TileMap.TileMapSizeX; x++)\n            {\n                //if (\n                //  (Tiles[x,y].tileType  != TILE_OPEN) \n                //  ||  ((Tiles[x,y].tileType  != TILE_OPEN) && (Tiles[x,y].UseAdjacentTextures == 1))\n                //  )\n                //  {\n                //if (Tiles[x,y].UseAdjacentTextures != 1)\n                //  {\n                if (Tiles[x + 1, y].UseAdjacentTextures != 1)\n                {\n                    Tiles[x, y].East = Tiles[x + 1, y].wallTexture;\n                    Tiles[x, y].shockEastOffset = Tiles[x + 1, y].shockTextureOffset;\n                    //Tiles[x,y].shockEastCeilHeight =LevelInfo[x+1,y].ceilingHeight - LevelInfo[x+1,y].shockSteep ;\n\n                }\n                if (Tiles[x - 1, y].UseAdjacentTextures != 1)\n                {\n                    Tiles[x, y].West = Tiles[x - 1, y].wallTexture;\n                    Tiles[x, y].shockWestOffset = Tiles[x - 1, y].shockTextureOffset;\n                    //Tiles[x,y].shockWestCeilHeight =LevelInfo[x-1,y].ceilingHeight - LevelInfo[x-1,y].shockSteep ;\n\n                }\n                if (Tiles[x, y + 1].UseAdjacentTextures != 1)\n                {\n                    Tiles[x, y].North = Tiles[x, y + 1].wallTexture;\n                    Tiles[x, y].shockNorthOffset = Tiles[x, y + 1].shockTextureOffset;\n                    //Tiles[x,y].shockNorthCeilHeight =LevelInfo[x,y+1].ceilingHeight - LevelInfo[x,y+1].shockSteep ;\n\n                }\n                if (Tiles[x, y - 1].UseAdjacentTextures != 1)\n                {\n                    Tiles[x, y].South = Tiles[x, y - 1].wallTexture;\n                    Tiles[x, y].shockSouthOffset = Tiles[x, y - 1].shockTextureOffset;\n                    //Tiles[x,y].shockSouthCeilHeight =LevelInfo[x,y-1].ceilingHeight - LevelInfo[x,y-1].shockSteep ;\n\n                }\n                //Need to calculate the adjustment here with the steepness and the direction of the slope.\n                Tiles[x, y].shockEastCeilHeight = (short)CalcNeighbourCeilHeight(Tiles[x, y], Tiles[x + 1, y], fEAST);\n                Tiles[x, y].shockWestCeilHeight = (short)CalcNeighbourCeilHeight(Tiles[x, y], Tiles[x - 1, y], fWEST);\n                Tiles[x, y].shockNorthCeilHeight = (short)CalcNeighbourCeilHeight(Tiles[x, y], Tiles[x, y + 1], fNORTH);\n                Tiles[x, y].shockSouthCeilHeight = (short)CalcNeighbourCeilHeight(Tiles[x, y], Tiles[x, y - 1], fSOUTH);\n                /*        Tiles[x,y].shockEastCeilHeight =LevelInfo[x+1,y].ceilingHeight - LevelInfo[x+1,y].shockSteep ;\nTiles[x,y].shockWestCeilHeight =LevelInfo[x-1,y].ceilingHeight - LevelInfo[x-1,y].shockSteep ;\nTiles[x,y].shockNorthCeilHeight =LevelInfo[x,y+1].ceilingHeight - LevelInfo[x,y+1].shockSteep ;\nTiles[x,y].shockSouthCeilHeight =LevelInfo[x,y-1].ceilingHeight - LevelInfo[x,y-1].shockSteep ;*/\n                //}\n\n                //Tiles[x, y].UpperEast = Tiles[x, y].East;\n                //Tiles[x, y].UpperWest = Tiles[x, y].West;\n                //Tiles[x, y].UpperNorth = Tiles[x, y].North;\n                //Tiles[x, y].UpperSouth = Tiles[x, y].South;\n                //Tiles[x, y].LowerEast = Tiles[x, y].East;\n                //Tiles[x, y].LowerWest = Tiles[x, y].West;\n                //Tiles[x, y].LowerNorth = Tiles[x, y].North;\n                //Tiles[x, y].LowerSouth = Tiles[x, y].South;\n            }\n        }\n        return true;\n    }\n\n    /// <summary>\n    /// Cleans up the tilemap. Splits up the tiles into strips of tiles along the x or y axis and sets tile face visibility as required\n    /// </summary>\n    /// <param name="game">Game.</param>\n    /// Although the tile map renderer supports tiles of size X*Y I\'m only smart enought to optimise the tilemap into strips of X*1 or Y*1 !!\n    public void CleanUp(string game)\n    {\n        if (!GameWorldController.instance.DoCleanUp) { return; }\n        int x; int y;\n\n        for (x = 0; x <= TileMap.TileMapSizeX; x++)\n        {\n            for (y = 0; y <= TileMap.TileMapSizeY; y++)\n            {\n                //Set some easy tile visible settings\n                switch (Tiles[x, y].tileType)\n                {\n                    case TILE_SOLID:\n                        //Bottom and top are invisible\n                        Tiles[x, y].VisibleFaces[vBOTTOM] = false;\n                        Tiles[x, y].VisibleFaces[vTOP] = false;\n                        break;\n                    default:\n                        //Bottom and top is invisible\n                        Tiles[x, y].VisibleFaces[vBOTTOM] = false;\n                        Tiles[x, y].VisibleFaces[vTOP] = false;\n                        break;\n                }\n            }\n\n            for (x = 0; x <= TileMap.TileMapSizeX; x++)\n            {\n                for (y = 0; y <= TileMap.TileMapSizeY; y++)\n                {\n                    //lets test this tile for visibility\n                    //A tile is invisible if it only touches other solid tiles and has no objects or does not have a terrain change.\n                    if ((Tiles[x, y].tileType == 0) && (Tiles[x, y].indexObjectList == 0) && (Tiles[x, y].TerrainChange == false))\n                    {\n                        switch (y)\n                        {\n                            case 0: //bottom row\n                                switch (x)\n                                {\n                                    case 0: //bl corner\n                                        if ((Tiles[x + 1, y].tileType == 0) && (Tiles[x, y + 1].tileType == 0)\n                                                && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y + 1].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; ; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                    case TileMap.TileMapSizeX://br corner\n                                        if ((Tiles[x - 1, y].tileType == 0) && (Tiles[x, y + 1].tileType == 0)\n                                                && (Tiles[x - 1, y].TerrainChange == false) && (Tiles[x, y + 1].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                    default: // invert t\n                                        if ((Tiles[x + 1, y].tileType == 0) && (Tiles[x, y + 1].tileType == 0) && (Tiles[x + 1, y].tileType == 0)\n                                                && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x + 1, y].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                }\n                                break;\n                            case TileMap.TileMapSizeY: //Top row\n                                switch (x)\n                                {\n                                    case 0: //tl corner\n                                        if ((Tiles[x + 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0)\n                                                && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                    case TileMap.TileMapSizeX://tr corner\n                                        if ((Tiles[x - 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0)\n                                                && (Tiles[x - 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                    default: //  t\n                                        if ((Tiles[x + 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0) && (Tiles[x - 1, y].tileType == 0)\n                                                && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false) && (Tiles[x - 1, y].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                }\n                                break;\n                            default: //\n                                switch (x)\n                                {\n                                    case 0:     //left edge\n                                        if ((Tiles[x, y + 1].tileType == 0) && (Tiles[x + 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0)\n                                                && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                    case TileMap.TileMapSizeX:  //right edge\n                                        if ((Tiles[x, y + 1].tileType == 0) && (Tiles[x - 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0)\n                                                && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x - 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                    default:        //+\n                                        if ((Tiles[x, y + 1].tileType == 0) && (Tiles[x + 1, y].tileType == 0) && (Tiles[x, y - 1].tileType == 0) && (Tiles[x - 1, y].tileType == 0)\n                                                && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x, y - 1].TerrainChange == false) && (Tiles[x - 1, y].TerrainChange == false))\n                                        { Tiles[x, y].Render = false; break; }\n                                        else { Tiles[x, y].Render = true; break; }\n                                }\n                                break;\n                        }\n                    }\n                }\n            }\n        }\n\n        //return;\n        if (game == GAME_SHOCK)\n        {//TODO:FIx some z-fighting due to tile visibility.\n            return;\n        }\n        //return;\n        int j = 1;\n        //Now lets combine the solids along particular axis\n        for (x = 0; x < TileMap.TileMapSizeX; x++)\n        {\n            for (y = 0; y < TileMap.TileMapSizeY; y++)\n            {\n                if ((Tiles[x, y].Grouped == false))\n                {\n                    j = 1;\n                    while ((Tiles[x, y].Render == true) && (Tiles[x, y + j].Render == true) && (Tiles[x, y + j].Grouped == false))      //&& (Tiles[x,y].tileType ==0) && (Tiles[x,y+j].tileType ==0)\n                    {\n                        //combine these two if they match and they are not already part of a group\n                        if (DoTilesMatch(Tiles[x, y], Tiles[x, y + j]))\n                        {\n                            Tiles[x, y + j].Render = false;\n                            Tiles[x, y + j].Grouped = true;\n                            Tiles[x, y].Grouped = true;\n                            //Tiles[x,y].DimY++;\n                            j++;\n                        }\n                        else\n                        {\n                            break;\n                        }\n\n                    }\n                    Tiles[x, y].DimY = (short)(Tiles[x, y].DimY + j - 1);\n                    j = 1;\n                }\n            }\n        }\n        j = 1;\n\n        ////Now lets combine solids along the other axis\n        for (y = 0; y < TileMap.TileMapSizeY; y++)\n        {\n            for (x = 0; x < TileMap.TileMapSizeX; x++)\n            {\n                if ((Tiles[x, y].Grouped == false))\n                {\n                    j = 1;\n                    while ((Tiles[x, y].Render == true) && (Tiles[x + j, y].Render == true) && (Tiles[x + j, y].Grouped == false))      //&& (Tiles[x,y].tileType ==0) && (Tiles[x,y+j].tileType ==0)\n                    {\n                        //combine these two if they  match and they are not already part of a group\n                        if (DoTilesMatch(Tiles[x, y], Tiles[x + j, y]))\n                        {\n                            Tiles[x + j, y].Render = false;\n                            Tiles[x + j, y].Grouped = true;\n                            Tiles[x, y].Grouped = true;\n                            //Tiles[x,y].DimY++;\n                            j++;\n                        }\n                        else\n                        {\n                            break;\n                        }\n\n                    }\n                    Tiles[x, y].DimX = (short)(Tiles[x, y].DimX + j - 1);\n                    j = 1;\n                }\n            }\n        }\n\n        //Clear invisible faces on solid tiles. \n        //TODO:Support all 64x64 tiles\n        for (y = 0; y <= TileMap.TileMapSizeY; y++)\n        {\n            for (x = 0; x <= TileMap.TileMapSizeX; x++)\n            {\n                if ((Tiles[x, y].tileType == TILE_SOLID))\n                {\n                    int dimx = Tiles[x, y].DimX;\n                    int dimy = Tiles[x, y].DimY;\n\n                    if (x == 0)\n                    {\n                        Tiles[x, y].VisibleFaces[vWEST] = false;\n                    }\n                    if (x == TileMap.TileMapSizeX)\n                    {\n                        Tiles[x, y].VisibleFaces[vEAST] = false;\n                    }\n                    if (y == 0)\n                    {\n                        Tiles[x, y].VisibleFaces[vSOUTH] = false;\n                    }\n\n                    if (y == TileMap.TileMapSizeY)\n                    {\n                        Tiles[x, y].VisibleFaces[vNORTH] = false;\n                    }\n                    if ((x + dimx <= TileMap.TileMapSizeX) && (y + dimy <= TileMap.TileMapSizeY))\n                    {\n                        if ((Tiles[x + dimx, y].tileType == TILE_SOLID) && (Tiles[x + dimx, y].TerrainChange == false) && (Tiles[x, y].TerrainChange == false))//Tile to the east is a solid\n                        {\n                            Tiles[x, y].VisibleFaces[vEAST] = false;\n                            Tiles[x + dimx, y].VisibleFaces[vWEST] = false;\n                        }\n                        if ((Tiles[x, y + dimy].tileType == TILE_SOLID) && (Tiles[x, y].TerrainChange == false) && (Tiles[x, y + dimy].TerrainChange == false))//TIle to the north is a solid\n                        {\n                            Tiles[x, y].VisibleFaces[vNORTH] = false;\n                            Tiles[x, y + dimy].VisibleFaces[vSOUTH] = false;\n                        }\n                    }\n                }\n            }\n        }\n\n        //Clear invisible faces on diagonals\n        for (y = 1; y < TileMap.TileMapSizeY; y++)\n        {\n            for (x = 1; x < TileMap.TileMapSizeX; x++)\n            {\n                switch (Tiles[x, y].tileType)\n                {\n                    case TILE_DIAG_NW:\n                        {\n                            if ((Tiles[x, y - 1].tileType == TILE_SOLID) && (Tiles[x, y - 1].TerrainChange == false))\n                            {\n                                Tiles[x, y].VisibleFaces[vSOUTH] = false;\n                                Tiles[x, y - 1].VisibleFaces[vNORTH] = false;\n                            }\n                            if ((Tiles[x + 1, y].tileType == TILE_SOLID) && (Tiles[x + 1, y].TerrainChange == false))\n                            {\n                                Tiles[x, y].VisibleFaces[vEAST] = false;\n                                Tiles[x + 1, y].VisibleFaces[vWEST] = false;\n                            }\n                        }\n                        break;\n                    case TILE_DIAG_NE:\n                        {\n                            if ((Tiles[x, y - 1].tileType == TILE_SOLID) && (Tiles[x, y - 1].TerrainChange == false))\n                            {\n                                Tiles[x, y].VisibleFaces[vSOUTH] = false;\n                                Tiles[x, y - 1].VisibleFaces[vNORTH] = false;\n                            }\n                            if ((Tiles[x - 1, y].tileType == TILE_SOLID) && (Tiles[x - 1, y].TerrainChange == false))\n                            {\n                                Tiles[x, y].VisibleFaces[vWEST] = false;\n                                Tiles[x - 1, y].VisibleFaces[vEAST] = false;\n                            }\n                        }\n                        break;\n                    case TILE_DIAG_SE:\n                        {\n                            if ((Tiles[x, y + 1].tileType == TILE_SOLID) && (Tiles[x, y + 1].TerrainChange == false))\n                            {\n                                Tiles[x, y].VisibleFaces[vNORTH] = false;\n                                Tiles[x, y + 1].VisibleFaces[vSOUTH] = false;\n                            }\n                            if ((Tiles[x - 1, y].tileType == TILE_SOLID) && (Tiles[x - 1, y].TerrainChange == false))\n                            {\n                                Tiles[x, y].VisibleFaces[vWEST] = false;\n                                Tiles[x - 1, y].VisibleFaces[vEAST] = false;\n                            }\n                        }\n                        break;\n                    case TILE_DIAG_SW:\n                        {\n                            if ((Tiles[x, y + 1].tileType == TILE_SOLID) && (Tiles[x, y + 1].TerrainChange == false))\n                            {\n                                Tiles[x, y].VisibleFaces[vNORTH] = false;\n                                Tiles[x, y + 1].VisibleFaces[vSOUTH] = false;\n                            }\n                            if ((Tiles[x + 1, y].tileType == TILE_SOLID) && (Tiles[x + 1, y].TerrainChange == false))\n                            {\n                                Tiles[x, y].VisibleFaces[vEAST] = false;\n                                Tiles[x + 1, y].VisibleFaces[vWEST] = false;\n                            }\n                        }\n                        break;\n                }\n\n            }\n\n        }\n\n        for (y = 1; y < TileMap.TileMapSizeY; y++)\n        {\n            for (x = 1; x < TileMap.TileMapSizeX; x++)\n            {\n                if ((Tiles[x, y].tileType == TILE_OPEN) && (Tiles[x, y].TerrainChange == false))\n                {\n                    if (\n                            ((Tiles[x + 1, y].tileType == TILE_OPEN) && (Tiles[x + 1, y].TerrainChange == false) && (Tiles[x + 1, y].floorHeight >= Tiles[x, y].floorHeight))\n                            ||\n                            (Tiles[x + 1, y].tileType == TILE_SOLID) && (Tiles[x + 1, y].TerrainChange == false)\n                    )\n                    {\n                        Tiles[x, y].VisibleFaces[vEAST] = false;\n                    }\n\n\n                    if (\n                            ((Tiles[x - 1, y].tileType == TILE_OPEN) && (Tiles[x - 1, y].TerrainChange == false) && (Tiles[x - 1, y].floorHeight >= Tiles[x, y].floorHeight))\n                            ||\n                            (Tiles[x - 1, y].tileType == TILE_SOLID) && (Tiles[x - 1, y].TerrainChange == false)\n                    )\n                    {\n                        Tiles[x, y].VisibleFaces[vWEST] = false;\n                    }\n\n\n                    if (\n                            ((Tiles[x, y + 1].tileType == TILE_OPEN) && (Tiles[x, y + 1].TerrainChange == false) && (Tiles[x, y + 1].floorHeight >= Tiles[x, y].floorHeight))\n                            ||\n                            (Tiles[x, y + 1].tileType == TILE_SOLID) && (Tiles[x, y + 1].TerrainChange == false)\n                    )\n                    {\n                        Tiles[x, y].VisibleFaces[vNORTH] = false;\n                    }\n\n                    if (\n                            ((Tiles[x, y - 1].tileType == TILE_OPEN) && (Tiles[x, y - 1].TerrainChange == false) && (Tiles[x, y - 1].floorHeight >= Tiles[x, y].floorHeight))\n                            ||\n                            (Tiles[x, y - 1].tileType == TILE_SOLID) && (Tiles[x, y - 1].TerrainChange == false)\n                    )\n                    {\n                        Tiles[x, y].VisibleFaces[vSOUTH] = false;\n                    }\n                }\n\n            }\n        }\n        //Make sure solids & opens are still consistently visible.\n        for (y = 1; y < TileMap.TileMapSizeY; y++)\n        {\n            for (x = 1; x < TileMap.TileMapSizeX; x++)\n            {\n\n                if ((Tiles[x, y].tileType == TILE_SOLID) || (Tiles[x, y].tileType == TILE_OPEN))\n                {\n                    int dimx = Tiles[x, y].DimX;\n                    int dimy = Tiles[x, y].DimY;\n                    if (dimx > 1)\n                    {//Make sure the ends are set properly\n                        Tiles[x, y].VisibleFaces[vEAST] = Tiles[x + dimx - 1, y].VisibleFaces[vEAST];\n                    }\n                    if (dimy > 1)\n                    {\n                        Tiles[x, y].VisibleFaces[vNORTH] = Tiles[x, y + dimy - 1].VisibleFaces[vNORTH];\n                    }\n\n                    //Check along each axis\n                    for (int i = 0; i < Tiles[x, y].DimX; i++)\n                    {\n                        if (Tiles[x + i, y].VisibleFaces[vNORTH] == true)\n                        {\n                            Tiles[x, y].VisibleFaces[vNORTH] = true;\n                        }\n                        if (Tiles[x + i, y].VisibleFaces[vSOUTH] == true)\n                        {\n                            Tiles[x, y].VisibleFaces[vSOUTH] = true;\n                        }\n                    }\n\n                    for (int i = 0; i < Tiles[x, y].DimY; i++)\n                    {\n                        if (Tiles[x, y + i].VisibleFaces[vEAST] == true)\n                        {\n                            Tiles[x, y].VisibleFaces[vEAST] = true;\n                        }\n                        if (Tiles[x, y + i].VisibleFaces[vWEST] == true)\n                        {\n                            Tiles[x, y].VisibleFaces[vWEST] = true;\n                        }\n                    }\n\n                }\n            }\n        }\n        for (y = 0; y <= TileMap.TileMapSizeY; y++)\n        {\n            Tiles[0, y].VisibleFaces[vEAST] = true;\n            Tiles[TileMap.TileMapSizeX, y].VisibleFaces[vWEST] = true;\n        }\n        for (x = 0; x <= TileMap.TileMapSizeX; x++)\n        {\n            Tiles[x, 0].VisibleFaces[vNORTH] = true;\n            Tiles[x, TileMap.TileMapSizeY].VisibleFaces[vSOUTH] = true;\n        }\n    }\n\n\n    /// <summary>\n    /// Check if two tiles are alike\n    /// </summary>\n    /// <param name="t1"></param>\n    /// <param name="t2"></param>\n    /// <returns></returns>\n    bool DoTilesMatch(TileInfo t1, TileInfo t2)\n    {//TODO:Tiles have a lot more properties now.\n        if (_RES == GAME_SHOCK)\n        { return false; }\n        //if ((t1.tileType >1) || (t1.hasElevator==1) || (t1.TerrainChange ==1) ||  (t2.hasElevator==1) || (t2.TerrainChange ==1) || (t1.isWater ==1) || (t2.isWater ==1)){\t//autofail no none solid/open/special.\n        if ((t1.tileType > 1) || (t1.TerrainChange == true) || (t2.TerrainChange == true))\n        {   //autofail no none solid/open/special.\n            return false;\n        }\n        else\n        {\n            if ((t1.tileType == 0) && (t2.tileType == 0))   //solid\n            {\n                return ((t1.wallTexture == t2.wallTexture) && (t1.West == t2.West) && (t1.South == t2.South) && (t1.East == t2.East) && (t1.North == t2.North) && (t1.UseAdjacentTextures == t2.UseAdjacentTextures));\n            }\n            else\n            {\n                return (t1.shockCeilingTexture == t2.shockCeilingTexture)\n                        && (t1.floorTexture == t2.floorTexture)\n                        && (t1.floorHeight == t2.floorHeight)\n                        && (t1.ceilingHeight == t2.ceilingHeight)\n                        && (t1.DimX == t2.DimX) && (t1.DimY == t2.DimY)\n                        && (t1.wallTexture == t2.wallTexture)\n                        && (t1.tileType == t2.tileType)\n                        && (t1.IsDoorForNPC == false) && (t2.IsDoorForNPC == false);//\n            }\n        }\n    }\n\n     public static bool isTerrainWater(int terraintype)\n    {\n        switch (terraintype)\n        {\n            case TerrainDatLoader.Water:\n            case TerrainDatLoader.Waterfall:\n            case TerrainDatLoader.WaterFlowEast:\n            case TerrainDatLoader.WaterFlowWest:\n            case TerrainDatLoader.WaterFlowNorth:\n            case TerrainDatLoader.WaterFlowSouth:\n                return true;\n        }\n        return false;\n    }\n\n/// <summary>\n/// Checks if the terrain is lava\n/// </summary>\n/// <param name="terraintype"></param>\n/// <returns>True if it lava</returns>\n    public static bool isTerrainLava(int terraintype)\n    {\n        switch (terraintype)\n        {\n            case TerrainDatLoader.Lava:\n            case TerrainDatLoader.Lavafall:\n                return true;\n        }\n        return false;\n    }\n\n    /// <summary>\n    /// Checks if Terrain is ice\n    /// </summary>\n    /// <param name="terraintype"></param>\n    /// <returns></returns>\n    public static bool isTerrainIce(int terraintype)\n    {\n        switch (terraintype)\n        {\n            case TerrainDatLoader.Ice_wall:\n            case TerrainDatLoader.IceNonSlip:\n            case TerrainDatLoader.Ice_walls:\n                return true;\n        }\n        return false;\n    }\n\n\n    ////Temp\n    //public static bool isTextureWater(int textureNo)\n    //{\n    //    if (textureNo > GameWorldController.instance.terrainData.Terrain.GetUpperBound(0))\n    //    {\n    //        return false;\n    //    }\n    //    switch (_RES)\n    //    {\n    //        case GAME_UW2:\n    //            return\n    //                (\n    //                    GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Water\n    //                        ||\n    //                    GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Waterfall\n    //                        ||\n    //                    GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.WaterFlowEast\n    //                        ||\n    //                        GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.WaterFlowWest\n    //                        ||\n    //                        GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.WaterFlowNorth\n    //                        ||\n    //                        GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.WaterFlowSouth\n    //                );\n\n    //        default:\n    //            return GameWorldController.instance.terrainData.Terrain[256 + textureNo - 210] == TerrainDatLoader.Water;//Adjust for uw1 texturemap positions\n    //    }\n    //}\n\n    //public static bool isTextureIce(int textureNo)\n    //{\n    //    if (textureNo > GameWorldController.instance.terrainData.Terrain.GetUpperBound(0))\n    //    {\n    //        return false;\n    //    }\n    //    switch (_RES)\n    //    {\n    //        case GAME_UW2:\n    //            return (\n    //                   (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Ice_wall)\n    //                   ||\n    //                   (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.IceNonSlip)\n    //                   ||\n    //                   (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Ice_walls)\n    //                );\n    //        //GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.IceNonSlip)\n    //        //||\n\n    //        default:\n    //            return GameWorldController.instance.terrainData.Terrain[256 + textureNo - 210] == TerrainDatLoader.Water;//Adjust for uw1 texturemap positions\n    //    }\n    //}\n\n    //public static bool isTextureLava(int textureNo)\n    //{\n    //    if (textureNo > GameWorldController.instance.terrainData.Terrain.GetUpperBound(0))\n    //    {\n    //        return false;\n    //    }\n    //    switch (_RES)\n    //    {\n    //        case GAME_UW2:\n    //            return (\n    //                    (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Lava)\n    //                    ||\n    //                    (GameWorldController.instance.terrainData.Terrain[textureNo] == TerrainDatLoader.Lavafall)\n    //                );\n\n    //        default:\n    //            return GameWorldController.instance.terrainData.Terrain[256 + textureNo - 210] == TerrainDatLoader.Lava;//Adjust for uw1 texturemap positions\n    //    }\n    //}\n\n    /// <summary>\n    /// Is the texture nothing.\n    /// </summary>\n    /// <returns><c>true</c>, if texture nothing was ised, <c>false</c> otherwise.</returns>\n    /// <param name="textureNo">Texture no.</param>\n    public static bool isTextureNothing(int textureNo)\n    {\n        switch (textureNo)\n        {\n            case 236:\n                return true;\n        }\n        return false;\n    }\n\n\n    /*\n    public void MergeWaterRegions()\n    {\n            int currRegion;\n            currRegion =1;\n            for (int x = 0; x<=TileMap.TileMapSizeX; x++)\n            {\n                    for (int y = 0; y<=TileMap.TileMapSizeY; y++)\n                    {\n                            if (Tiles[x,y].hasBridge != true)\n                            {\n                                    if ((Tiles[x,y].isWater == true) && (Tiles[x,y].waterRegion == 0))//Unset water region.\n                                    {\n                                            Tiles[x,y].waterRegion = (short)currRegion;\n                                            MergeCurrentWaterRegion(currRegion, x, y);\n                                            currRegion++;\n                                    }\n                            }\n                    }\n            }\n    }\n\n    void MergeCurrentWaterRegion(int currRegion, int x, int y)\n    {\n            //north\n            if ((Tiles[x,y+1].isWater==true) && (Tiles[x,y+1].waterRegion == 0))\n            {\n                    Tiles[x,y + 1].waterRegion = (short)currRegion;\n                    MergeCurrentWaterRegion(currRegion, x, y+1);\n            }\n            //south\n            if ((Tiles[x,y - 1].isWater == true) && (Tiles[x,y - 1].waterRegion == 0))\n            {\n                    Tiles[x,y - 1].waterRegion = (short)currRegion;\n                    MergeCurrentWaterRegion(currRegion, x , y-1);\n            }\n            //east\n            if ((Tiles[x + 1,y].isWater == true) && (Tiles[x + 1,y].waterRegion == 0))\n            {\n                    Tiles[x + 1,y].waterRegion = (short)currRegion;\n                    MergeCurrentWaterRegion(currRegion, x+1, y);\n            }\n            //west\n            if ((Tiles[x - 1,y].isWater == true) && (Tiles[x - 1,y].waterRegion == 0))\n            {\n                    Tiles[x - 1,y].waterRegion = (short)currRegion;\n                    MergeCurrentWaterRegion(currRegion, x-1, y);\n            }\n    }\n*/\n    /*\n    /// <summary>\n    /// Merges the lava regions into a single region\n    /// </summary>\n    public void MergeLavaRegions()\n    {\n            int currRegion;\n            currRegion = 1;\n            for (int x = 0; x<=TileMap.TileMapSizeX; x++)\n            {\n                    for (int y = 0; y<=TileMap.TileMapSizeY; y++)\n                    {\n                            if (Tiles[x,y].hasBridge != true)\n                            {\n                                    if ((Tiles[x,y].isLava == true) && (Tiles[x,y].lavaRegion == 0))//Unset lava region.\n                                    {\n                                            Tiles[x,y].lavaRegion = (short)currRegion;\n                                            MergeCurrentLavaRegion(currRegion, x, y);\n                                            currRegion++;\n                                    }\n                            }\n                    }\n            }\n    }\n\n    void MergeCurrentLavaRegion( int currRegion, int x, int y)\n    {\n            //north\n            if ((Tiles[x,y + 1].isLava == true) && (Tiles[x,y + 1].lavaRegion == 0))\n            {\n                    Tiles[x,y + 1].lavaRegion = (short)currRegion;\n                    MergeCurrentLavaRegion(currRegion, x, y + 1);\n            }\n            //south\n            if ((Tiles[x,y - 1].isLava == true) && (Tiles[x,y - 1].lavaRegion == 0))\n            {\n                    Tiles[x,y - 1].lavaRegion =(short) currRegion;\n                    MergeCurrentLavaRegion( currRegion, x, y - 1);\n            }\n            //east\n            if ((Tiles[x + 1,y].isLava == true) && (Tiles[x + 1,y].lavaRegion == 0))\n            {\n                    Tiles[x + 1,y].lavaRegion =(short) currRegion;\n                    MergeCurrentLavaRegion( currRegion, x + 1, y);\n            }\n            //west\n            if ((Tiles[x - 1,y].isLava == true) && (Tiles[x - 1,y].lavaRegion == 0))\n            {\n                    Tiles[x - 1,y].lavaRegion = (short)currRegion;\n                    MergeCurrentLavaRegion(currRegion, x - 1, y);\n            }\n    }\n\n    */\n\n    int CalcNeighbourCeilHeight(TileInfo t1, TileInfo t2, int Direction)\n    {//TODO:Test me. I\'m terrible.\n     // fNORTH 32\n     // fSOUTH 16\n     // fEAST 8\n     // fWEST 4\n        if ((t2.tileType <= 1) || (t2.shockSlopeFlag == SLOPE_FLOOR_ONLY))\n        {//Don\'t need to do anything since it has a flat ceiling.\n            return t2.ceilingHeight;\n        }\n        else\n        {\n            //return t2.ceilingHeight;\n            switch (Direction)\n            {\n                case fNORTH:\n                    {\n                        switch (t2.tileType)\n                        {\n                            case TILE_SLOPE_N:\n                            case TILE_SLOPE_S:\n                                if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) || (t2.shockSlopeFlag == SLOPE_CEILING_ONLY))\n                                {\n                                    return t2.ceilingHeight + t2.TileSlopeSteepness;\n                                }\n                                else\n                                {\n                                    return t2.ceilingHeight;\n                                }\n                            //break;\n                            default:\n                                return t2.ceilingHeight;\n                                //break;\n                        }\n                    }\n                case fSOUTH:\n                    {\n                        switch (t2.tileType)\n                        {\n                            case TILE_SLOPE_S:\n                            case TILE_SLOPE_N:\n                                if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) || (t2.shockSlopeFlag == SLOPE_CEILING_ONLY))\n                                {\n                                    return t2.ceilingHeight + t2.TileSlopeSteepness;\n                                }\n                                else\n                                {\n                                    return t2.ceilingHeight;\n                                }\n                            //break;\n                            default:\n                                return t2.ceilingHeight;\n                                //break;\n                        }\n                        //if (t2.tileType == TILE_SLOPE_S)\n                        //  {\n                        //  if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) ||(t2.shockSlopeFlag == SLOPE_CEILING_ONLY))\n                        //    {\n                        //    return t2.ceilingHeight+t2.shockSteep ;\n                        //    }\n                        //  else\n                        //    {\n                        //    return t2.ceilingHeight;\n                        //    }\n                        //  }\n                        //break;\n                    }\n                case fEAST:\n                    {\n                        switch (t2.tileType)\n                        {\n                            case TILE_SLOPE_E:\n                            case TILE_SLOPE_W:\n                                if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) || (t2.shockSlopeFlag == SLOPE_CEILING_ONLY))\n                                {\n                                    return t2.ceilingHeight + t2.TileSlopeSteepness;\n                                }\n                                else\n                                {\n                                    return t2.ceilingHeight;\n                                }\n                            //break;\n                            default:\n                                return t2.ceilingHeight;\n                                //break;\n                        }\n                    }\n                case fWEST:\n                    {\n                        switch (t2.tileType)\n                        {\n                            case TILE_SLOPE_W:\n                            case TILE_SLOPE_E:\n                                if ((t2.shockSlopeFlag == SLOPE_BOTH_OPPOSITE) || (t2.shockSlopeFlag == SLOPE_CEILING_ONLY))\n                                {\n                                    return t2.ceilingHeight + t2.TileSlopeSteepness;\n                                }\n                                else\n                                {\n                                    return t2.ceilingHeight;\n                                }\n                            //break;\n                            default:\n                                return t2.ceilingHeight;\n                                //break;\n                        }\n                    }\n            }\n        }\n        return t2.ceilingHeight;\n    }\n\n\n    /*\tchar[] GetUW2TileMapBytes(int LevelNo, char[] lev_ark_file_data, out long datalen)\n\t\t{\t\n\t\t\t\tchar[] lev_ark;\n\t\t\t\tlong address_pointer=0;\n\t\t\t\tint NoOfBlocks=(int)DataLoader.getValAtAddress(lev_ark_file_data,0,32);\t\n\t\t\t\tdatalen=0;\n\t\t\t\taddress_pointer=6;\n\t\t\t\tint isCompressed =( ( (int)DataLoader.getValAtAddress(lev_ark_file_data,address_pointer + (NoOfBlocks*4) + (LevelNo*4) ,32)  ) >>1) & 0x01;\n\n\t\t\t\taddress_pointer=(LevelNo * 4) + 6;\n\n\t\t\t\tif ((int)DataLoader.getValAtAddress(lev_ark_file_data,address_pointer,32)==0)\n\t\t\t\t{\n\t\t\t\t\t\tDebug.Log("This should not happen in getuw2tilemapbytes");\n\t\t\t\t\t\tlev_ark= new char[1];\n\t\t\t\t\t\treturn lev_ark ;\n\t\t\t\t}\n\t\t\t\tif (isCompressed == 1)\n\t\t\t\t{\n\t\t\t\t\t\t//long datalen=0;\n\t\t\t\t\t\tlev_ark = DataLoader.unpackUW2(lev_ark_file_data,DataLoader.getValAtAddress(lev_ark_file_data,address_pointer,32), ref datalen);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t\tdatalen = 0x7c08;\n\t\t\t\t\t\tint BlockStart = (int)DataLoader.getValAtAddress(lev_ark_file_data, address_pointer, 32);\n\t\t\t\t\t\tlev_ark = new char[0x7c08];//Make sure this contains the object data as well.\n\t\t\t\t\t\tint j=0;\n\t\t\t\t\t\tfor (int i = BlockStart; i < BlockStart + 0x7c08; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlev_ark[j] = lev_ark_file_data[i];\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn lev_ark;\n\t\t}*/\n\n\n    /// <summary>\n    /// Converts this tilemap/Objectlist into an array that can be written to file.\n    /// </summary>\n    /// <returns>The map to bytes.</returns>\n    public char[] TileMapToBytes(char[] lev_ark_file_data, out long datalen)\n    {\n        //holy crap this is crap!\n        //SCRAP IT ALL\n\n        char[] TileMapData = new char[31752];//Size of tilemap + object list\n\n        //Copy filedata from tile map to data array\n        for (int i=0;i< 16384;i++)\n        {\n            TileMapData[i] = lev_ark_block.Data[i];\n        }\n\n        //Copy mobile object data block\n        for (int i = 0; i < 256 * 27; i++)\n        {\n            //  TileMapData[i] = LevelObjects.\n        }\n\n        //and so on.\n\n        //Copy Static object data block\n\n        //Copy mobile free list\n\n        //copy static free list\n\n        //   7afc    0104   unknown (260 bytes)\n\n        //7c00    0002\n        // 7c02    0002   no.entries in mobile free list minus 1\n        //7c04    0002   no.entries in static free list minus 1\n        // 7c06    0002   0x7775(\'uw\')\n\n\n        DataLoader.UWBlock uwdata = new DataLoader.UWBlock();\n\n        DataLoader.LoadUWBlock(lev_ark_file_data, thisLevelNo, 31752, out uwdata);\n\n        for (int i = 0x7afc; i < 31752; i++)//07afc\n        {\n            TileMapData[i] = uwdata.Data[i];\n        }\n\n        datalen = uwdata.DataLen;\n\n        long addptr = 0;\n        //for (int y = 0; y <= TileMap.TileMapSizeY; y++)\n        //{\n        //    for (int x = 0; x <= TileMap.TileMapSizeX; x++)\n        //    {\n        //        TileInfo t = Tiles[x, y];\n\n        //        //Shift the bits to construct my data\n        //        int tileType = t.tileType;\n        //        int floorHeight = (t.floorHeight / 2) << 4;                \n\n        //        int ByteToWrite = tileType | floorHeight;//| floorTexture | noMagic;//This will be set in the original data\n        //        TileMapData[addptr] = (char)(ByteToWrite);\n\n        //        int flags = t.flags & 0x3;\n        //        int floorTexture = t.floorTexture << 2;\n        //        int noMagic = t.noMagic << 6;\n        //        int DoorBit = t.doorBit << 7;\n        //        ByteToWrite = floorTexture | noMagic | DoorBit | flags;\n        //        TileMapData[addptr + 1] = (char)(ByteToWrite);\n\n        //        ByteToWrite = ((t.indexObjectList & 0x3FF) << 6) | (t.wallTexture & 0x3F);\n        //        TileMapData[addptr + 2] = (char)(ByteToWrite & 0xFF);\n        //        TileMapData[addptr + 3] = (char)((ByteToWrite >> 8) & 0xFF);\n\n        //        addptr += 4;\n        //    }\n        //}\n        for (int o = 0; o <= GameWorldController.instance.objectList[thisLevelNo].objInfo.GetUpperBound(0); o++)\n        {\n            ObjectLoaderInfo currobj = GameWorldController.instance.objectList[thisLevelNo].objInfo[o];\n            if (currobj != null)\n            {\n                /*\tif (currobj.instance!=null)\n                    {\n                            if (currobj.instance.transform.parent == GameWorldController.instance.InventoryMarker.transform)\n                            {\n                                    Debug.Log("Trying to save object that is in inventory list" + currobj.instance.name);\n                            }\t\t\t\t\t\t\t\t\t\n                    }\n                    else\n                    {\n                            if (currobj.InUseFlag==1)\n                            {\n                                    Debug.Log("Trying to save in use object that has no current instance:" + o);\t\t\n                            }\n                    }\t*/\n\n                if (IsObjectFree(o))\n                {\n                    TileMapData[addptr] = (char)0;\n                    TileMapData[addptr + 1] = (char)0;\n                    TileMapData[addptr + 2] = (char)0;\n                    TileMapData[addptr + 3] = (char)0;\n                    TileMapData[addptr + 4] = (char)0;\n                    TileMapData[addptr + 5] = (char)0;\n                    TileMapData[addptr + 6] = (char)0;\n                    TileMapData[addptr + 7] = (char)0;\n                    if (o < 256)\n                    {\n                        TileMapData[addptr + 8] = (char)0;\n                        TileMapData[addptr + 9] = (char)0;\n                        TileMapData[addptr + 10] = (char)0;\n                        TileMapData[addptr + 11] = (char)0;\n                        TileMapData[addptr + 12] = (char)0;\n                        TileMapData[addptr + 13] = (char)0;\n                        TileMapData[addptr + 14] = (char)0;\n                        TileMapData[addptr + 15] = (char)0;\n                        TileMapData[addptr + 16] = (char)0;\n                        TileMapData[addptr + 17] = (char)0;\n                        TileMapData[addptr + 18] = (char)0;\n                        TileMapData[addptr + 19] = (char)0;\n                        TileMapData[addptr + 20] = (char)0;\n                        TileMapData[addptr + 21] = (char)0;\n                        TileMapData[addptr + 22] = (char)0;\n                        TileMapData[addptr + 23] = (char)0;\n                        TileMapData[addptr + 24] = (char)0;\n                        TileMapData[addptr + 25] = (char)0;\n                        TileMapData[addptr + 26] = (char)0;\n                        addptr = addptr + 8 + 19;\n                    }\n                    else\n                    {\n                        addptr = addptr + 8;\n                    }\n                }\n                else\n                {\n                    int ByteToWrite = (currobj.is_quant << 15) |\n                            (currobj.invis << 14) |\n                            (currobj.doordir << 13) |\n                            (currobj.enchantment << 12) |\n                            ((currobj.flags & 0x07) << 9) |\n                            (currobj.item_id & 0x1FF);\n\n                    TileMapData[addptr] = (char)(ByteToWrite & 0xFF);\n                    TileMapData[addptr + 1] = (char)((ByteToWrite >> 8) & 0xFF);\n\n                    ByteToWrite = ((currobj.xpos & 0x7) << 13) |\n                            ((currobj.ypos & 0x7) << 10) |\n                            ((currobj.heading & 0x7) << 7) |\n                            ((currobj.zpos & 0x7F));\n                    TileMapData[addptr + 2] = (char)(ByteToWrite & 0xFF);\n                    TileMapData[addptr + 3] = (char)((ByteToWrite >> 8) & 0xFF);\n\n                    ByteToWrite = (((int)currobj.next & 0x3FF) << 6) |\n                            (currobj.quality & 0x3F);\n                    TileMapData[addptr + 4] = (char)(ByteToWrite & 0xFF);\n                    TileMapData[addptr + 5] = (char)((ByteToWrite >> 8) & 0xFF);\n\n                    ByteToWrite = ((currobj.link & 0x3FF) << 6) |\n                            (currobj.owner & 0x3F);\n                    TileMapData[addptr + 6] = (char)(ByteToWrite & 0xFF);\n                    TileMapData[addptr + 7] = (char)((ByteToWrite >> 8) & 0xFF);\n\n\n                    if (o < 256)\n                    {//Additional npc mobile data.\n\n                        TileMapData[addptr + 0x8] = (char)(currobj.npc_hp);\n                      //  TileMapData[addptr + 0x9] = (char)((currobj.ProjectileHeadingMajor & 0xE0) | ((char)(currobj.ProjectileHeadingMinor & 0x1F)));\n                        //+A is copied  unknown value\n                        //+B   bits 0-3 npc_goal, 4-11 npc_gtarg, 12-15 is unknown but needs to be copied to prevent npcs duplicating.\n                        ByteToWrite = (\n                                ((currobj.npc_goal & 0xF)) |\n                                ((currobj.npc_gtarg & 0xFF) << 4) |\n                                ((TileMapData[addptr + 0xb + 1] & 0xf0) << 8)\n                        );\n                        TileMapData[addptr + 0xb] = (char)(ByteToWrite & 0xFF);\n                        TileMapData[addptr + 0xb + 1] = (char)((ByteToWrite >> 8) & 0xFF);\n\n\n                        int val = (int)DataLoader.getValAtAddress(TileMapData, addptr + 0xd, 16);\n                        val = val & 0x1ff0;\n                        ByteToWrite = ((currobj.npc_attitude & 0x3) << 14) |\n                                ((currobj.npc_talkedto & 0x1) << 13) |\n                                (currobj.npc_level & 0xF)\n                                | val\n                                ;\n\n                        TileMapData[addptr + 0xd] = (char)(ByteToWrite & 0xFF);\n                        TileMapData[addptr + 0xd + 1] = (char)((ByteToWrite >> 8) & 0xFF);\n\n                        //TileMapData[addptr+0x14] =  (char)((TileMapData[addptr+0x14] & 0xC0) | (char)(currobj.Projectile_Pitch & 0x3F));\n\n                       //// TileMapData[addptr + 0x14] = (char)(((currobj.Projectile_Sign << 7) & 0x1) | ((currobj.Projectile_Pitch & 0x7) << 4) | (currobj.Projectile_Speed & 0xf));\n\n                        ByteToWrite = ((currobj.npc_xhome & 0x3F) << 10) |\n                                ((currobj.npc_yhome & 0x3F) << 4) |\n                                (TileMapData[addptr + 0x16] & 0xf);\n                        TileMapData[addptr + 0x16] = (char)(ByteToWrite & 0xFF);\n                        TileMapData[addptr + 0x16 + 1] = (char)((ByteToWrite >> 8) & 0xFF);\n\n\n                        ByteToWrite = (TileMapData[addptr + 0x18] & 0xE0)\n                                |\n                                (currobj.npc_heading & 0x1F);\n                        TileMapData[addptr + 0x18] = (char)(ByteToWrite & 0xFF);\n                        TileMapData[addptr + 0x18 + 1] = (char)((ByteToWrite >> 8) & 0xFF);\n\n\n                        TileMapData[addptr + 0x19] = (char)(\n                                ((currobj.npc_hunger & 0x3F))\n                        );\n\n                        TileMapData[addptr + 0x1a] = (char)(\n                                ((currobj.npc_whoami & 0xFF))\n                        );\n\n                        addptr = addptr + 8 + 19;\n                    }\n                    else\n                    {\n                        addptr = addptr + 8;\n                    }\n                }\n            }\n\n        }\n\n\n        addptr = 0x7300;//mobile object list\n        int f = 0;\n        for (int i = 0; i <= GameWorldController.instance.objectList[thisLevelNo].NoOfFreeMobile; i++)\n        {\n            int ByteToWrite = GameWorldController.instance.objectList[thisLevelNo].FreeMobileList[f];\n            TileMapData[addptr] = (char)(ByteToWrite & 0xFF);\n            TileMapData[addptr + 1] = (char)((ByteToWrite >> 8) & 0xFF);\n            f++;\n            addptr += 2;\n        }\n\n        addptr = 0x74fc;//static object list\n        f = 0;\n        for (int i = 0; i <= GameWorldController.instance.objectList[thisLevelNo].NoOfFreeStatic; i++)\n        {\n            int ByteToWrite = GameWorldController.instance.objectList[thisLevelNo].FreeStaticList[f];\n            TileMapData[addptr] = (char)(ByteToWrite & 0xFF);\n            TileMapData[addptr + 1] = (char)((ByteToWrite >> 8) & 0xFF);\n            f++;\n            addptr += 2;\n        }\n\n        //Now write the counts of free objects\n        //TileMapData[0x7c02] = (char)(GameWorldController.instance.objectList[thisLevelNo].NoOfFreeMobile & 0xFF);\n        //TileMapData[0x7c03] = (char)((GameWorldController.instance.objectList[thisLevelNo].NoOfFreeMobile >> 8) & 0xFF);\n\n       // TileMapData[0x7c04] = (char)(GameWorldController.instance.objectList[thisLevelNo].NoOfFreeStatic & 0xFF);\n       // TileMapData[0x7c05] = (char)((GameWorldController.instance.objectList[thisLevelNo].NoOfFreeStatic >> 8) & 0xFF);\n\n        return TileMapData;\n    }\n\n    bool IsObjectFree(int index)\n    {\n\n        if (index < 256)//mobile list\n        {\n            for (int i = 2; i <= GameWorldController.instance.objectList[thisLevelNo].NoOfFreeMobile; i++)\n            {\n                if (index == GameWorldController.instance.objectList[thisLevelNo].FreeMobileList[i])\n                {//obj is on free list\n                    return true;\n                }\n            }\n        }\n        else\n        {//static\n            for (int i = 0; i <= GameWorldController.instance.objectList[thisLevelNo].NoOfFreeStatic; i++)\n            {\n                if (index == GameWorldController.instance.objectList[thisLevelNo].FreeStaticList[i])\n                {//obj is on free list\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Converts the animation overlay data back to bytes\n    /// </summary>\n    /// <returns>The info to bytes.</returns>\n    public char[] OverlayInfoToBytes()\n    {\n        char[] OverLayData = new char[64 * 6];\n        int OverlayAddress = 0;\n        for (int overlayIndex = 0; overlayIndex < 64; overlayIndex++)\n        {\n            int link = Overlays[overlayIndex].link << 6;\n            OverLayData[OverlayAddress + 0] = (char)(link & 0xFF);\n            OverLayData[OverlayAddress + 1] = (char)((link >> 8) & 0xFF);\n            OverLayData[OverlayAddress + 2] = (char)(Overlays[overlayIndex].duration & 0xFF);\n            OverLayData[OverlayAddress + 3] = (char)((Overlays[overlayIndex].duration >> 8) & 0xFF);\n            OverLayData[OverlayAddress + 4] = (char)(Overlays[overlayIndex].tileX & 0xFF);\n            OverLayData[OverlayAddress + 5] = (char)(Overlays[overlayIndex].tileY & 0xFF);\n            OverlayAddress += 6;\n        }\n        return OverLayData;\n    }\n\n\n    /// <summary>\n    /// Converts the uw1 texture map to bytes.\n    /// </summary>\n    /// <returns>The map to bytes.</returns>\n    public char[] TextureMapToBytes()\n    {\n        char[] textureMapData = new char[122];\n        short textureMapSize = 64;\n        int TextureMapAddress = 0;\n        for (int i = 0; i < textureMapSize; i++)\n        {\n            if (i < 48) //Wall textures\n            {\n                textureMapData[TextureMapAddress + 0] = (char)(texture_map[i] & 0xFF);\n                textureMapData[TextureMapAddress + 1] = (char)((texture_map[i] >> 8) & 0xFF);\n                TextureMapAddress += 2;\n            }\n            else if (i <= 57)   //Floor textures are 49 to 56, ceiling is 57\n            {\n                textureMapData[TextureMapAddress + 0] = (char)((texture_map[i] - 210) & 0xFF);\n                textureMapData[TextureMapAddress + 1] = (char)(((texture_map[i] - 210) >> 8) & 0xFF);\n                TextureMapAddress += 2;\n            }\n            else\n            { //door textures\n                textureMapData[TextureMapAddress] = (char)(texture_map[i]);\n                TextureMapAddress++;\n            }\n        }\n\n        return textureMapData;\n    }\n\n\n    /// <summary>\n    /// Defines continous rooms regions.\n    /// </summary>\n    public void CreateRooms()\n    {\n        short RegionNo = 1;\n        //Reset room settings\n        for (int y = TileMapSizeY; y >= 0; y--)\n        {\n            for (int x = 0; x <= TileMapSizeX; x++)\n            {\n                Tiles[x, y].roomRegion = 0;\n            }\n        }\n\n        for (int y = TileMapSizeY; y >= 0; y--)\n        {\n            for (int x = 0; x <= TileMapSizeX; x++)\n            {\n                if (\n                    (Tiles[x, y].tileType != TILE_SOLID)\n                &&\n                        (Tiles[x, y].roomRegion == 0)\n                )\n                {//Tiles is open and room region is not set\n                    Tiles[x, y].roomRegion = RegionNo;\n                    fillRoomRegion(x, y, TileTerrainType(x, y), RegionNo);\n                    RegionNo++;\n                }\n            }\n        }\n\n        /*\tif (false)\n\t\t\t{\n\t\t\t\t\t\n\t\t\t\n\t\t\tstring output="";\n\n\t\t\tStreamWriter writer = new StreamWriter( Application.dataPath + "//..//_output.txt", true);\n\t\t\t\tfor (int y=TileMapSizeY; y>=0;y--)\n\t\t\t\t{\n\t\t\t\t\toutput +="\\n";\n\t\t\t\t\tfor (int x=0; x<=TileMapSizeX;x++)\n\t\t\t\t\t{\n\t\t\t\t\t\t\toutput += Tiles[x,y].roomRegion.ToString("d3") + ",";\n\t\t\t\t\t}\n\t\t\t}\n\t\t\twriter.WriteLine(output);\n\t\t\twriter.Close();\n\t\t\t}*/\n\n    }\n\n\n    void fillRoomRegion(int startX, int startY, int terrainType, short RegionNo)\n    {\n        short thisTileHeight = Tiles[startX, startY].floorHeight;\n        //Check in each direction\n        for (int x = -1; x <= 1; x++)\n        {\n            for (int y = -1; y <= 1; y++)\n            {\n                if (\n                    ((x == -1) && (y == 0))\n                    ||\n                    ((x == 1) && (y == 0))\n                    ||\n                    ((x == 0) && (y == -1))\n                    ||\n                    ((x == 0) && (y == +1))\n                )\n                {\n                    if (TileMap.ValidTile(startX + x, startY + y))\n                    {\n                        if (\n                            (Tiles[startX + x, startY + y].tileType != TILE_SOLID)\n                            &&\n                            (Tiles[startX + x, startY + y].roomRegion == 0)\n                            &&\n                            (terrainType == TileTerrainType(startX + x, startY + y))\n                            &&\n                            (isTileOpenFromDirection(startX + x, startY + y, x, y))\n                            &&\n                            (\n                                (\n                                (thisTileHeight >= Tiles[startX + x, startY + y].floorHeight - 2)\n                                &&\n                                (thisTileHeight <= Tiles[startX + x, startY + y].floorHeight + 2)\n                                )\n                                ||\n                                (\n                                    (\n                                    (Tiles[startX + x, startY + y].hasBridge) || (Tiles[startX, startY].hasBridge)\n                                    )\n                                    && (terrainType == 0)\n                                )\n                            )\n                        )\n                        {//Tiles is open and room region is not set and is a matching terrain type and does not drop down too far (unless it has a bridge and I\'m testing for land)\n                            Tiles[startX + x, startY + y].roomRegion = RegionNo;\n                            fillRoomRegion(startX + x, startY + y, terrainType, RegionNo);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n\n    /// <summary>\n    /// Terrain types for calculating room regions.\n    /// </summary>\n    /// <returns>The terrain type.</returns>\n    /// <param name="x">The x coordinate.</param>\n    /// <param name="y">The y coordinate.</param>\n    int TileTerrainType(int x, int y)\n    {\n        if ((Tiles[x, y].isLand) || (Tiles[x, y].hasBridge))\n        {\n            return 0;\n        }\n        else if (Tiles[x, y].isWater)\n        {\n            return 1;\n        }\n        else if (Tiles[x, y].isLava)\n        {\n            return 2;\n        }\n        else if (Tiles[x, y].isNothing)\n        {\n            return 3;\n        }\n        else\n        {\n            return 0;\n        }\n    }\n\n    /// <summary>\n    /// Determines if the tile is open (Ie no wall is in the way) from the specified direction. \n    /// </summary>\n    /// <returns><c>true</c>, if tile open from direction was ised, <c>false</c> otherwise.</returns>\n    /// <param name="X">X.</param>\n    /// <param name="Y">Y.</param>\n    /// <param name="directionX">Direction x.</param>\n    /// <param name="directionY">Direction y.</param>\n    bool isTileOpenFromDirection(int X, int Y, int directionX, int directionY)\n    {\n        switch (Tiles[X, Y].tileType)\n        {\n            case TILE_OPEN:\n            case TILE_SLOPE_N:\n            case TILE_SLOPE_S:\n            case TILE_SLOPE_E:\n            case TILE_SLOPE_W:\n                return true;\n            case TILE_DIAG_NE:\n                if ((directionX == 1) || (directionY == -1))\n                {\n                    return true;\n                }\n                break;\n            case TILE_DIAG_NW:\n                if ((directionX == 1) || (directionY == 1))\n                {\n                    return true;\n                }\n                break;\n            case TILE_DIAG_SE:\n                if ((directionX == -1) || (directionY == -1))\n                {\n                    return true;\n                }\n                break;\n            case TILE_DIAG_SW:\n                if ((directionX == -1) || (directionY == 1))\n                {\n                    return true;\n                }\n                break;\n\n            default:\n                return false;\n        }\n        return false;\n    }\n\n    /// <summary>\n    /// Create a string identifying the general shape of the level.\n    /// </summary>\n    /// <returns></returns>\n    public string getSignature()\n    {\n        string signature = "";\n        for (int x = 0; x < TileMapSizeX; x++)\n        {\n            for (int y = 0; y < TileMapSizeY; y++)\n            {\n                signature += Tiles[x, y].tileType.ToString() + Tiles[x, y].floorHeight.ToString();\n            }\n        }\n        return signature;\n    }\n\n\n    //public int getTileAgentID(int tileX, int tileY)\n    //{\n    //    if (Tiles[tileX, tileY].isWater)\n    //    {\n    //        return GameWorldController.instance.NavMeshWater.agentTypeID;\n    //    }\n    //    if (Tiles[tileX, tileY].isLava)\n    //    {\n    //        return GameWorldController.instance.NavMeshLava.agentTypeID;\n    //    }\n    //    return GameWorldController.instance.NavMeshLand.agentTypeID;\n    //}\n\n    /// <summary>\n    /// Builds a texture map from file data\n    /// </summary>\n    /// <param name="tex_ark"></param>\n    /// <param name="CeilingTexture"></param>\n    /// <param name="LevelNo"></param>\n    void BuildTextureMap(DataLoader.UWBlock tex_ark, ref short CeilingTexture, int LevelNo)\n    {\n        short textureMapSize;//=UW1_TEXTUREMAPSIZE;\n        switch (_RES)\n        {\n            case GAME_UW2:\n                textureMapSize = UW2_TEXTUREMAPSIZE;\n                break;\n            case GAME_UWDEMO:\n                textureMapSize = UWDEMO_TEXTUREMAPSIZE;\n                break;\n            default:\n                textureMapSize = UW1_TEXTUREMAPSIZE;\n                break;\n        }\n        int offset = 0;\n        for (int i = 0; i < textureMapSize; i++)//256\n        {\n            //TODO: Only use this for texture lookups.\n            switch (UWEBase._RES)\n            {\n                case UWEBase.GAME_UWDEMO:\n                    {\n                        if (i < 48)//Wall textures\n                        {\n                            texture_map[i] = (short)DataLoader.getValAtAddress(tex_ark, offset, 16);\n                            //(i * 2)\n                            offset = offset + 2;\n                        }\n                        else\n                            if (i <= 57)//Floor textures are 49 to 56, ceiling is 57\n                        {\n                            texture_map[i] = (short)(DataLoader.getValAtAddress(tex_ark, offset, 16) + 48);\n                            //(i * 2)\n                            offset = offset + 2;\n                            if (i == 57)\n                            {\n                                CeilingTexture = (short)i;\n                            }\n                        }\n                        else\n                        {\n                            //door textures are int 8s\n                            texture_map[i] = (short)DataLoader.getValAtAddress(tex_ark, offset, 8);\n                            //+210; //(i * 1)\n                            offset++;\n                        }\n                        break;\n                    }\n                case UWEBase.GAME_UW1:\n                    {\n                        if (i < 48)//Wall textures\n                        {\n                            texture_map[i] = (short)DataLoader.getValAtAddress(tex_ark, offset, 16);\n                            offset = offset + 2;\n                        }\n                        else\n                            if (i <= 57)//Floor textures are 48 to 56, ceiling is 57\n                        {\n                            texture_map[i] = (short)(DataLoader.getValAtAddress(tex_ark, offset, 16) + 210);\n                            offset = offset + 2;\n                            if (i == 57)\n                            {\n                                CeilingTexture = (short)i;\n                            }\n                        }\n                        else\n                        {\n                            //door textures are int 8s\n                            texture_map[i] = (short)DataLoader.getValAtAddress(tex_ark, offset, 8);\n                            //+210; //(i * 1)\n                            offset++;\n                        }\n                        break;\n                    }\n                case UWEBase.GAME_UW2://uw2\n                    {\n                        if (i < 64)\n                        {\n                            texture_map[i] = (short)DataLoader.getValAtAddress(tex_ark, offset, 16);\n                            //tmp //textureAddress+//(i*2)\n                            offset = offset + 2;\n                        }\n                        else\n                        {\n                            //door textures\n                            texture_map[i] = (short)DataLoader.getValAtAddress(tex_ark, offset, 8);\n                            //tmp //textureAddress+//(i*2)\n                            offset++;\n                        }\n                    }\n                    if (i == 0xf)\n                    {\n                        CeilingTexture = (short)i;\n                        //texture_map[i];\n                    }\n                    if ((LevelNo == (int)(GameWorldController.UW2_LevelNos.Ethereal4)) && (i == 16))\n                    {\n                        //Not sure why this is an exceptional case!\n                        CeilingTexture = (short)i;\n                    }\n                    break;\n            }\n        }\n    }\n}', 'message': "Rough implementation of the oscillating platforms trap in the ethereal void purple region\nNpcs without containers won't be prevented from having conversations\n", 'author_name': 'hankmorgan', 'lang': 'cs'}