/* * Date: 11/28/2005 * Time: 11:03 PM * * Copyright 2005, Static Boy Productions */ using System; using System.Collections.Generic; using System.Drawing; using System.Text.RegularExpressions; using Jessie.Utils; using Jessie.TTY; namespace Jessie.GameState { /// /// Description of jtbvGameLevel. /// public class jtbvGameLevel { public const int MAP_WIDTH = 80; public const int MAP_HEIGHT = 21; // include unknowns because they might be doors // don't include unknowns because they might not be doors //GRID_TERRAIN = (OPEN_DOOR,) public jtbvMapSpace[,] map = new jtbvMapSpace[MAP_WIDTH, MAP_HEIGHT]; public jtbvGameLevel() { ResetMap(); } public void ResetMap() { for (int x = 0; x < MAP_WIDTH; x++) { for (int y = 0; y < MAP_HEIGHT; y++) { map[x,y] = new jtbvMapSpace(this, x, y); } } } public jtbvMapSpace this[Point cursor] { get { if ((cursor.X >= 0) && (cursor.Y >= 0) && (cursor.X < MAP_WIDTH) && (cursor.Y < MAP_HEIGHT)) return map[cursor.X, cursor.Y]; else return null; } set { map[cursor.X, cursor.Y] = value; } } public jtbvMapSpace this[int x, int y] { get { return map[x, y]; } set { map[x, y] = value; } } public string GetViewStr() { string retVal = ""; for (int y = 0; y < MAP_HEIGHT; y++) { for (int x = 0; x < MAP_WIDTH; x++) { retVal += this[x,y].GetDrawTile(); //retVal += SearchStatus[x, y]; } retVal += "\r\n"; } return retVal; } public void UseMsgData(jtbvReceivedMessage msg, jtbvGameState gameState) { Point cursor = msg.CursorLoc; jtbvLog.WriteFile("MapProcess.log", "Using message: " + msg.ToString()); cursor.Y -= 2; for (int cnt = 0; cnt < msg.Text.Length; cnt++) { if ((cursor.X >= 0) && (cursor.Y >= 0) && (cursor.X < MAP_WIDTH) && (cursor.Y < MAP_HEIGHT)) { this[cursor].UseAppearanceData(msg.Text[cnt]); } cursor.X++; } } public void UseQueryResult(char sym, string desc) { // Groups[0] is the whole string // Groups[1] is the symbol // Groups[2] is the part inside the () if (InquireLocAppearance == sym.ToString()) this[InquireLoc].UseQueryResult(sym, desc); else jtbvLog.WriteFile("Inquiries.log", "ERROR! Query result does not match what was originally thought to be requested!"); } /// /// This is the point that the last inquiry took place on. /// public Point InquireLoc; public string InquireLocAppearance; public void RequestMoreInfo(Point cursor) { // TODO: Implement RequestMoreInfo() Point tmp = cursor; //tmp.Y += 2; if (!this.Curiosities.Contains(tmp)) { this.Curiosities.Add(tmp); } } public System.Collections.Generic.List Curiosities = new List(); public void ResetSearched () { foreach (jtbvMapSpace space in this.map) space.SearchStatus = 0; } public int GetDanger(Point loc) { int retVal = 0; if (this[loc] != null) { foreach (jtbvMapSpace curr in this[loc].AdjacentSquares) { retVal += curr.Danger; } } else { Console.WriteLine("Error! Loc = " + loc.ToString()); } jtbvLog.WriteFile("Danger.log", "The danger of the point " + loc.ToString() + " is " + retVal.ToString()); return retVal; } public Point GetAdjacentEnemy(Point loc) { Point retVal = loc; if (this[loc] != null) foreach (jtbvMapSpace curr in this[loc].AdjacentSquares) { if (curr.Danger > 0) retVal = curr.Loc; } return retVal; } public Point GetAdjacentClosedDoor(Point loc) { Point retVal = loc; if (this[loc] != null) foreach (jtbvMapSpace curr in this[loc].AdjacentSquares) { if ((curr.Tile == jtbvTile.CLOSED_DOOR) || (curr.Tile == jtbvTile.LOCKED_DOOR)) retVal = curr.Loc; } return retVal; } public bool DownStairsKnown() { bool retVal = false; if (this.FindFeature(jtbvTile.STAIRCASE_DOWN) != null) { jtbvLog.WriteFile("Descend.log", "Down stairs are known!"); retVal = true; } else { jtbvLog.WriteFile("Descend.log", "Down stairs are not known!"); } return retVal; } public bool PointWithinBounds(Point toPoint) { return ((toPoint.X >= 0) && (toPoint.Y >= 0) && (toPoint.X < MAP_WIDTH) && (toPoint.Y < MAP_HEIGHT)); } public string GoToFeature(jtbvGameState state, jtbvTile targetFeature) { string retVal = ""; jtbvMapSpace targetSpace = FindFeature(targetFeature); if (targetSpace != null) { retVal = GoTo(state, targetSpace); } return retVal; } public jtbvMapSpace FindFeature(jtbvTile targetFeature) { jtbvMapSpace retVal = null; foreach (jtbvMapSpace curr in this.map) if (curr.Tile == targetFeature) retVal = curr; return retVal; } // ********************** // **** PATH FINDING **** // ********************** public string GoTo(jtbvGameState state, jtbvMapSpace toPoint) { string retVal = ""; List path = PathFind(this[state.Player.Loc], toPoint); if (this[state.Player.Loc] == toPoint) { retVal = "."; } else if (path != null) { jtbvMapSpace nextMove = path[0]; jtbvUtils.GetDirectionFromPoint(state.Player.Loc, nextMove.Loc); } return retVal; } public List PathFind(jtbvMapSpace fromPoint, jtbvMapSpace toPoint) { this.ResetPathCrumbs(); List currentTargets = fromPoint.AdjacentSquares; List> Paths = new List>(); List InitialPath = new List(); InitialPath.Add(fromPoint); Paths.Add(InitialPath); int cnt = 0; while (cnt < 3000) // Don't go insane on the looping -- if we get stuck, break out. { cnt++; Paths.Sort(new ComparePaths()); // Sort the paths so that the shortest paths are first. List> NextPaths = new List>(); foreach (List path in Paths) { jtbvMapSpace lastPoint = (jtbvMapSpace) path[0]; List tmpTargets = lastPoint.AdjacentSquares; tmpTargets = GleanTargets(tmpTargets, lastPoint); // Remove targets that are impassible if (tmpTargets.Count != 0) { foreach (jtbvMapSpace target in tmpTargets) { if (target.BreadCrumb == false) { target.BreadCrumb = true; List tmpPath = new List(path); tmpPath.Insert(0, target); if (target == toPoint) { // Yay! We found it! return tmpPath; } // If we didn't find it, we simply add this path to our list of paths to explore next time. NextPaths.Add ( tmpPath ); } } } } Paths = NextPaths; } return null; } public jtbvMapSpace GetExploreSquare(jtbvGameState state, bool IncludeWalls) { jtbvMapSpace retVal = this[state.Player.Loc]; if (this.PointWithinBounds(state.Player.Loc)) { List path = FindExplorableTarget(this[state.Player.Loc], IncludeWalls); if (path != null) { jtbvMapSpace nextMove; if (path.Count >= 2) { nextMove = (jtbvMapSpace) path[path.Count - 2]; } else { nextMove = this[state.Player.Loc]; } retVal = nextMove; } } return retVal; } public List FindExplorableTarget(jtbvMapSpace fromPoint, bool IncludeWalls) { this.ResetPathCrumbs(); List currentTargets = fromPoint.AdjacentSquares; List> Paths = new List>(); List InitialPath = new List(); InitialPath.Add(fromPoint); Paths.Add(InitialPath); int cnt = 0; while (cnt < 3000) // Don't go insane on the looping -- if we get stuck, break out. { cnt++; Paths.Sort(new ComparePaths()); // Sort the paths so that the shortest paths are first. List> NextPaths = new List>(); foreach (List path in Paths) { jtbvMapSpace lastPoint = (jtbvMapSpace) path[0]; List tmpTargets = lastPoint.AdjacentSquares; tmpTargets = GleanTargets(tmpTargets, lastPoint); // Remove targets that are impassible if (tmpTargets.Count != 0) { foreach (jtbvMapSpace target in tmpTargets) { if (target.BreadCrumb == false) { target.BreadCrumb = true; List tmpPath = new List(path); tmpPath.Insert(0, target); foreach (jtbvMapSpace space in target.AdjacentSquares) { if ((space.Tile == jtbvTile.UNEXPLORED) && (space.SearchStatus == 0)) { // Yay! We found one! return tmpPath; } else if (IncludeWalls && (space.Tile == jtbvTile.WALL) && (space.SearchStatus == 0)) { // Yay! We found one! return tmpPath; } } NextPaths.Add ( tmpPath ); } } } } Paths = NextPaths; } return null; } private List GleanTargets(List currentTargets, jtbvMapSpace fromSquare) { List newTargets = new List(); for (int cnt=0; cnt < currentTargets.Count; cnt++) { jtbvMapSpace target = (jtbvMapSpace) currentTargets[cnt]; if ((target.IsPassable()) && (!newTargets.Contains(target))) { if (((target.Tile != jtbvTile.OPEN_DOOR) && (fromSquare.Tile != jtbvTile.OPEN_DOOR) && (target.Tile != jtbvTile.UNKNOWN) && (fromSquare.Tile != jtbvTile.UNKNOWN) && (target.Tile != jtbvTile.UNEXPLORED) && (fromSquare.Tile != jtbvTile.UNEXPLORED)) || jtbvUtils.PointsAreSquared(target, fromSquare)) { newTargets.Add(target); } } } return newTargets; } // Just like Hansel and Gretel left bread crumbs, so do we. This is the way the birds come and pick the crumbs up again. private void ResetPathCrumbs() { foreach (jtbvMapSpace space in this.map) { space.BreadCrumb = false; } } public static int GetTravelCost(List path) { int retVal = 0; foreach (jtbvMapSpace pt in path) { retVal += pt.GetTravelCost(); } return retVal; } public bool IsExplored (jtbvGameState state) { bool retVal = true; if (this.GetExploreSquare(state, false) != state.CurrDlvl[state.Player.Loc]) retVal = false; return retVal; // for( int x = 0; x < MAP_WIDTH; x++) // { // for( int y = 0; y < MAP_HEIGHT; y++) // { // if (this[x, y].IsPassable()) // { // if (this[x, y].Tile != jtbvTile.UNEXPLORED) // { // foreach (jtbvMapSpace target in this[x, y].AdjacentSquares/ { // if ((target.Tile == jtbvTile.UNEXPLORED) && (target.SearchStatus == 0)) // { // return false; // } // } // } // } // } // } // return retVal; // // } } } public class ComparePaths : IComparer> { public ComparePaths() { } public int Compare (List first, List second) { List x = first as List; List y = second as List; if ((x != null) && (y != null)) { // kludge way to get the level. :-\ int xCost = jtbvGameLevel.GetTravelCost(x); int yCost = jtbvGameLevel.GetTravelCost(y); return (xCost - yCost); } else { return 0; } } } }