/// <summary> /// Updates the game engine and processes any effects /// </summary> /// <param name="keyState"></param> /// <returns>Returns true if the game should cease it's update loop</returns> public bool update(KeyboardState keyState) { if (_level.levelChange != LevelChange.None) { if (_level.levelChange == LevelChange.Down) { _level.levelChange = LevelChange.None; _level = _level.downLevel; _level.setHeroInLevel(false); } else { _level.levelChange = LevelChange.None; _level = _level.upLevel; _level.setHeroInLevel(true); } _levelView = new LevelView(_level); return true; } EffectDescription? effectDescription = _level.getEffect(); if (effectDescription != null) { Effect effect = EffectBuilder.buildEffect(effectDescription.Value, _level.getHeroLocation()); _effectView.addEffect(effect); return true; } if (_effectView.empty()) { processInput(keyState); return _level.update(); } return true; }
public static Location getFirstStep(Location start, Location end, Level level) { AStarNode lastStep = aStarSearch(start, end, level); while (lastStep.parent != null && lastStep.parent.parent != null) { lastStep = lastStep.parent; } return lastStep.location; }
public static void calculateFOV(Level level) { level.setLit(level.getHeroLocation(), 0); scanOctant1(level, level.getHeroLocation(), 1, 1, 0); scanOctant2(level, level.getHeroLocation(), 1, 1, 0); scanOctant3(level, level.getHeroLocation(), 1, 1, 0); scanOctant4(level, level.getHeroLocation(), 1, 1, 0); scanOctant5(level, level.getHeroLocation(), 1, 1, 0); scanOctant6(level, level.getHeroLocation(), 1, 1, 0); scanOctant7(level, level.getHeroLocation(), 1, 1, 0); scanOctant8(level, level.getHeroLocation(), 1, 1, 0); }
public Window() { _hero = new Hero(); _level = new Level(_hero, true); _levelView = new LevelView(_level); _hud = new Hud(_hero); DungeonGenerator.generateDungeon(_level, 200, 200); _level.setHeroInLevel(false); _effectView = new EffectView(); _inputManager = new InputManager(); }
public Level(Hero hero, bool isTopLevel) { _tiles = new Dictionary<Location, Tile>(); _actors = new List<Actor>(); _items = new Dictionary<Location, Item>(); _walkables = new Dictionary<Location, Entity>(); _effectQueue = new LinkedList<EffectDescription>(); _actorLocations = new HashSet<Location>(); curActor = 0; upLevel = null; downLevel = null; levelChange = LevelChange.None; _isTopLevel = isTopLevel; _hero = hero; }
private static void scanOctant2(Level level, Location heroLocation, int depth, double startSlope, double endSlope) { if (depth >= Hero.MAX_SIGHT_DISTANCE) { return; } int y = heroLocation.y - depth; int x = heroLocation.x + (int)(startSlope * depth); while (getSlope(x, y, heroLocation.x, heroLocation.y, false) <= endSlope) { if (level.blocksSight(new Location(x, y))) { if (!level.blocksSight(new Location(x + 1, y))) { double newEndSlope = getSlope(x + 0.5, y + 0.5, heroLocation.x, heroLocation.y, false); scanOctant2(level, heroLocation, depth + 1, startSlope, newEndSlope); } } else { if (level.blocksSight(new Location(x + 1, y))) { startSlope = -getSlope(x + 0.5, y - 0.5, heroLocation.x, heroLocation.y, false); } } level.setLit(new Location(x, y), 0); x--; } x++; if (depth < Hero.MAX_SIGHT_DISTANCE && !level.blocksSight(new Location(x, y))) { scanOctant2(level, heroLocation, depth + 1, startSlope, endSlope); } }
public LevelView(Level level) { _level = level; }
private static void addChests(Level level, Rect bounds) { const int numChests = 5; for (int i = 0; i < numChests; i++) { Location chestLoc = new Location(0, 0); while (!isChestCandidate(level, chestLoc)) { chestLoc.x = Util.random.Next(bounds.x1, bounds.x2); chestLoc.y = Util.random.Next(bounds.y1, bounds.y2); } Chest chest = new Chest(); level.addWalkable(chest, chestLoc); } }
private static void addEntranceAndExit(Level level, Rect dungeon) { Location loc = new Location(0, 0); while (!isStairCandidate(level, loc)) { loc.x = Util.random.Next(dungeon.x1, dungeon.x2); loc.y = Util.random.Next(dungeon.y1, dungeon.y2); } Staircase upcase = new Staircase(true); level.addWalkable(upcase, loc); level.upStairs = loc; loc = new Location(0, 0); while (!isStairCandidate(level, loc)) { loc.x = Util.random.Next(dungeon.x1, dungeon.x2); loc.y = Util.random.Next(dungeon.y1, dungeon.y2); } Staircase downcase = new Staircase(false); level.addWalkable(downcase, loc); level.downStairs = loc; }
public void bindLevel(Level level) { this.level = level; }
public static void generateDungeon(Level level, int width, int height) { Rect dungeonRect = new Rect(0, 0, width, height); level.bounds = dungeonRect; carveRoom(level, dungeonRect, true, TileType.Dungeon_Wall); Location center = new Location(width / 2, height / 2); Rect innerRoom = createRect(center, Direction.West, Feature.Room); carveRoom(level, innerRoom, false, TileType.Dungeon_Floor); for (int i = 0; i < 100; i++) { Location doorLoc = findDoor(level, dungeonRect); //randomly choose a feature to add to the dungeon Feature[] features = {Feature.Corridor, Feature.Room}; Feature feature = Util.chooseRandomElement(features); tryAddFeature(level, doorLoc, feature); } addEntranceAndExit(level, dungeonRect); addChests(level, dungeonRect); addMonsters(level, dungeonRect); initLighting(level, dungeonRect); }
private static void tryAddFeature(Level level, Location doorLoc, Feature feature) { Direction[] directions = { Direction.North, Direction.South, Direction.West, Direction.East }; foreach (Direction direction in directions) { Rect rect = createRect(doorLoc, direction, feature); rect.expand(); if (rectIsClear(level, rect)) { rect.compress(); if (feature == Feature.Room) { carveRoom(level, rect, false, TileType.Dungeon_Floor); } else if (feature == Feature.Corridor) { carveCorridor(level, rect, false, TileType.Dungeon_Floor); } level.addTile(new Tile(false, TileType.Dungeon_Floor), doorLoc); level.addWalkable(new Door(), doorLoc); break; } } }
private static void carveRoom(Level level, Rect rect, bool blocks, TileType tileType) { for (int x = rect.x1; x <= rect.x2; x++) { for (int y = rect.y1; y <= rect.y2; y++) { Tile tile = new Tile(blocks, tileType); level.addTile(tile, new Location(x, y)); } } }
private static bool isStairCandidate(Level level, Location location) { if (!isChestCandidate(level, location)) return false; Entity interactable = level.getWalkable(location); return interactable == null; }
private static bool isDark(Level level, Location location) { if (level.getTile(location) == null || !level.getTile(location).blocksMovement) return false; Location[] neighbors = { location.getAdjLocation(Direction.North), location.getAdjLocation(Direction.South), location.getAdjLocation(Direction.West), location.getAdjLocation(Direction.East), location.getAdjLocation(Direction.NorthWest), location.getAdjLocation(Direction.SouthWest), location.getAdjLocation(Direction.NorthEast), location.getAdjLocation(Direction.SouthEast), }; int countBlockedNeighbors = 0; for (int i = 0; i < neighbors.Length; i++) { Tile tile = level.getTile(neighbors[i]); if (tile == null || tile.blocksMovement) { countBlockedNeighbors++; } } return countBlockedNeighbors == 8; }
private static void addMonsters(Level level, Rect bounds) { List<Monster> monsters = MonsterFactory.getDungeonMonsters(1); for (int i = 0; i < monsters.Count; i++) { Location monsterLocation = new Location(0, 0); while (!isMonsterCandidate(level, monsterLocation)) { monsterLocation.x = Util.random.Next(bounds.x1, bounds.x2); monsterLocation.y = Util.random.Next(bounds.y1, bounds.y2); } level.addActor(monsters[i], monsterLocation); } }
private static bool isChestCandidate(Level level, Location location) { if (level.getTile(location).blocksMovement) return false; Direction[] directions = {Direction.North, Direction.South, Direction.West, Direction.East}; bool[] blocked = new bool[4]; for (int i = 0; i < directions.Length; i++) { Location adj = location.getAdjLocation(directions[i]); if (level.getWalkable(adj) is Door) return false; Tile tile = level.getTile(adj); if (tile != null && tile.blocksMovement) { blocked[i] = true; } } return !((blocked[0] && blocked[1]) || (blocked[2] && blocked[3])); }
private static void initLighting(Level level, Rect bounds) { for (int x = bounds.x1; x <= bounds.x2; x++) { for (int y = bounds.y1; y <= bounds.y2; y++) { if (isDark(level, new Location(x, y))) { level.setLit(new Location(x, y), Entity.LIT_FULL_DARK); } } } }
private static Location findDoor(Level level, Rect dungeonRect) { Location doorLoc = new Location(0, 0); while (!isDoorCandidate(level, doorLoc)) { doorLoc = new Location( Util.random.Next(dungeonRect.x2), Util.random.Next(dungeonRect.y2)); } return doorLoc; }
public void changeLevel(LevelChange change) { if (change == LevelChange.Up && _isTopLevel) return; levelChange = change; if (levelChange == LevelChange.Down && downLevel == null) { downLevel = new Level(_hero, false); DungeonGenerator.generateDungeon(downLevel, 200, 200); downLevel.upLevel = this; } }
private static bool rectIsClear(Level level, Rect rect) { for (int x = rect.x1; x <= rect.x2; x++) { for (int y = rect.y1; y <= rect.y2; y++) { Tile tile = level.getTile(new Location(x, y)); if (tile == null || !tile.blocksMovement) return false; } } return true; }
private static bool isDoorCandidate(Level level, Location location) { if (!level.getTile(location).blocksMovement) return false; Location[] neighbors = { location.getAdjLocation(Direction.North), location.getAdjLocation(Direction.South), location.getAdjLocation(Direction.West), location.getAdjLocation(Direction.East) }; for (int i = 0; i < 4; i++) { Tile tile = level.getTile(neighbors[i]); if (tile != null && !tile.blocksMovement) return true; } return false; }
private static void carveCorridor(Level level, Rect rect, bool blocks, TileType tileType) { rect.compressCorridor(); carveRoom(level, rect, blocks, tileType); }
private static AStarNode aStarSearch(Location start, Location end, Level level) { HashSet<AStarNode> open = new HashSet<AStarNode>(); HashSet<AStarNode> closed = new HashSet<AStarNode>(); AStarNode startNode = new AStarNode(start); startNode.g = 0; startNode.h = start.distance(end); open.Add(startNode); while (open.Count > 0) { AStarNode q = new AStarNode(new Location(0, 0)); double min = 10000; foreach (AStarNode node in open) { if (node.f() < min) { min = node.f(); q = node; } } open.Remove(q); Direction[] directions = {Direction.North, Direction.South, Direction.East, Direction.West}; for (int i = 0; i < 4; i++) { Location adj = q.location.getAdjLocation(directions[i]); if (level.getTile(adj).blocksMovement) continue; AStarNode node = new AStarNode(adj); if (closed.Contains(node)) continue; node.setParent(q); if (adj.Equals(end)) return node; node.g = q.g + 1; node.h = adj.distance(end); bool add = true; foreach (AStarNode openNode in open) { if (openNode.location.Equals(node.location) && openNode.f() < node.f()) add = false; } foreach (AStarNode closedNode in closed) { if (closedNode.location.Equals(node.location) && closedNode.f() < node.f()) add = false; } if (add) { open.Add(node); } } closed.Add(q); } return startNode; }
private static bool isMonsterCandidate(Level level, Location location) { if (level.getEntities(location).Count > 1) return false; return !level.getTile(location).blocksMovement; }