/// <summary> /// Validates whether the neighbour of this isometric tile in the given direction satisfies the /// constraints of the tileset. /// </summary> /// <param name="dir">The direction of the neighbour to validate.</param> private void ValidateNeighbour(MapDirection dir) { IsoTile neighbour = this.neighbours[(int)dir]; if (neighbour != null) { /// To simplify the algorithm, we use terrain combinations rotated to MapDirection.NorthEast. TerrainCombination thisCombRot = MapHelper.RotateTerrainCombination(this.type.Combination, dir, MapDirection.NorthEast); TerrainCombination neighCombRot = MapHelper.RotateTerrainCombination(neighbour.type.Combination, dir, MapDirection.NorthEast); /// Generate the terrain-NESW array for this tile and the neighbour. ITerrainType[] thisNESWRot = MapHelper.GetTerrainNESW(this.type.TerrainA, this.type.TerrainB, thisCombRot); ITerrainType[] neighNESWRot = MapHelper.GetTerrainNESW(neighbour.type.TerrainA, neighbour.type.TerrainB, neighCombRot); /// Check the generated terrain-NESW arrays. if (thisNESWRot[0] != neighNESWRot[3] || thisNESWRot[1] != neighNESWRot[2]) { throw new MapException(string.Format("Invalid neighbours at {0} and {1}!", this.mapCoords, neighbour.mapCoords)); } /// Check whether the given direction satisfies the transition-length constraint. if (this.type.TerrainB != null && this.type.TerrainB.TransitionLength > 0 && thisNESWRot[0] == this.type.TerrainA && thisNESWRot[1] == this.type.TerrainA) { int remaining = this.type.TerrainB.TransitionLength; IsoTile currTile = neighbour; while (currTile != null && remaining > 0) { /// Generate the terrain-NESW array of the currently checked tile. TerrainCombination currCombRot = MapHelper.RotateTerrainCombination(currTile.type.Combination, dir, MapDirection.NorthEast); ITerrainType[] currNESWRot = MapHelper.GetTerrainNESW(currTile.type.TerrainA, currTile.type.TerrainB, currCombRot); /// Check if the currently checked tile is part of the transition. if (currNESWRot[0] != this.type.TerrainA || currNESWRot[1] != this.type.TerrainA || currNESWRot[2] != this.type.TerrainA || currNESWRot[3] != this.type.TerrainA) { /// No, it's not part of the transition. We have to check whether the upcoming terrain type /// is another child of TerrainA or not. if (currNESWRot[2] == this.type.TerrainA && currNESWRot[3] == this.type.TerrainA && (currNESWRot[0] == this.type.TerrainA || currNESWRot[0].Parent == this.type.TerrainA) && (currNESWRot[1] == this.type.TerrainA || currNESWRot[1].Parent == this.type.TerrainA)) { /// It's another child of TerrainA, no contradiction with the tileset -> OK. break; } else { /// It's not a child of TerrainA -> Error. throw new MapException(string.Format("Invalid transition from {0} in direction {1}! Length must be at least {2}!", this.mapCoords, dir, this.type.TerrainB.TransitionLength)); } } /// Yes, it's part of the transition. We can switch to the next tile in the same direction. currTile = currTile.neighbours[(int)dir]; remaining--; } } } }
/// <summary>This method is used to rotate the terrain combination of an isometric tile.</summary> /// <param name="combination">The original terrain combination to be rotated.</param> /// <param name="origDir"> /// The original direction vector of the isometric tile. /// Can be one of the followings: MapDirection.NorthEast, MapDirection.SouthEast, MapDirection.SouthWest, /// MapDirection.NorthWest. /// </param> /// <param name="newDir"> /// The new direction vector of the isometric tile. /// Can be one of the followings: MapDirection.NorthEast, MapDirection.SouthEast, MapDirection.SouthWest, /// MapDirection.NorthWest. /// </param> /// <returns>The rotated terrain combination of the tile.</returns> public static TerrainCombination RotateTerrainCombination(TerrainCombination combination, MapDirection origDir, MapDirection newDir) { /// No rotation has to be performed in case of simple terrain combination. if (combination == TerrainCombination.Simple) { return(combination); } if (newDir != MapDirection.NorthEast) { int modifiedOrigDir = ((int)MapDirection.NorthEast - (int)newDir + (int)origDir) % 8; return(MapHelper.RotateTerrainCombination(combination, (MapDirection)(modifiedOrigDir >= 0 ? modifiedOrigDir : modifiedOrigDir + 8), MapDirection.NorthEast)); } if (origDir == MapDirection.NorthEast) { /// No rotation has to be performed as the direction vector already points to MapDirection.NorthEast. return(combination); } else if (origDir == MapDirection.SouthEast) { /// Rotate by +90 degrees. if (combination == TerrainCombination.AAAB) { return(TerrainCombination.AABA); } if (combination == TerrainCombination.AABA) { return(TerrainCombination.ABAA); } if (combination == TerrainCombination.AABB) { return(TerrainCombination.ABBA); } if (combination == TerrainCombination.ABAA) { return(TerrainCombination.BAAA); } if (combination == TerrainCombination.ABAB) { return(TerrainCombination.BABA); } if (combination == TerrainCombination.ABBA) { return(TerrainCombination.BBAA); } if (combination == TerrainCombination.ABBB) { return(TerrainCombination.BBBA); } if (combination == TerrainCombination.BAAA) { return(TerrainCombination.AAAB); } if (combination == TerrainCombination.BAAB) { return(TerrainCombination.AABB); } if (combination == TerrainCombination.BABA) { return(TerrainCombination.ABAB); } if (combination == TerrainCombination.BABB) { return(TerrainCombination.ABBB); } if (combination == TerrainCombination.BBAA) { return(TerrainCombination.BAAB); } if (combination == TerrainCombination.BBAB) { return(TerrainCombination.BABB); } if (combination == TerrainCombination.BBBA) { return(TerrainCombination.BBAB); } throw new ArgumentException("Invalid terrain combination!", "combination"); } else if (origDir == MapDirection.SouthWest) { /// Rotate by +180 degrees. if (combination == TerrainCombination.AAAB) { return(TerrainCombination.ABAA); } if (combination == TerrainCombination.AABA) { return(TerrainCombination.BAAA); } if (combination == TerrainCombination.AABB) { return(TerrainCombination.BBAA); } if (combination == TerrainCombination.ABAA) { return(TerrainCombination.AAAB); } if (combination == TerrainCombination.ABAB) { return(TerrainCombination.ABAB); } if (combination == TerrainCombination.ABBA) { return(TerrainCombination.BAAB); } if (combination == TerrainCombination.ABBB) { return(TerrainCombination.BBAB); } if (combination == TerrainCombination.BAAA) { return(TerrainCombination.AABA); } if (combination == TerrainCombination.BAAB) { return(TerrainCombination.ABBA); } if (combination == TerrainCombination.BABA) { return(TerrainCombination.BABA); } if (combination == TerrainCombination.BABB) { return(TerrainCombination.BBBA); } if (combination == TerrainCombination.BBAA) { return(TerrainCombination.AABB); } if (combination == TerrainCombination.BBAB) { return(TerrainCombination.ABBB); } if (combination == TerrainCombination.BBBA) { return(TerrainCombination.BABB); } throw new ArgumentException("Invalid terrain combination!", "combination"); } else if (origDir == MapDirection.NorthWest) { /// Rotate by +270 degrees. if (combination == TerrainCombination.AAAB) { return(TerrainCombination.BAAA); } if (combination == TerrainCombination.AABA) { return(TerrainCombination.AAAB); } if (combination == TerrainCombination.AABB) { return(TerrainCombination.BAAB); } if (combination == TerrainCombination.ABAA) { return(TerrainCombination.AABA); } if (combination == TerrainCombination.ABAB) { return(TerrainCombination.BABA); } if (combination == TerrainCombination.ABBA) { return(TerrainCombination.AABB); } if (combination == TerrainCombination.ABBB) { return(TerrainCombination.BABB); } if (combination == TerrainCombination.BAAA) { return(TerrainCombination.ABAA); } if (combination == TerrainCombination.BAAB) { return(TerrainCombination.BBAA); } if (combination == TerrainCombination.BABA) { return(TerrainCombination.ABAB); } if (combination == TerrainCombination.BABB) { return(TerrainCombination.BBAB); } if (combination == TerrainCombination.BBAA) { return(TerrainCombination.ABBA); } if (combination == TerrainCombination.BBAB) { return(TerrainCombination.BBBA); } if (combination == TerrainCombination.BBBA) { return(TerrainCombination.ABBB); } throw new ArgumentException("Invalid terrain combination!", "combination"); } else { throw new ArgumentException("Invalid direction vector!", "direction"); } }