/** * Make a DungeonGenerator with the given height, width, and RNG. Use this if you want to seed the * RNG. * * @param width The width of the dungeon in cells * @param height The height of the dungeon in cells * @param rng The RNG to use for all purposes in this class; if it is a StatefulRNG, then it will * be used as-is, but if it is not a StatefulRNG, a new StatefulRNG will be used, randomly * seeded by this parameter */ public DungeonGenerator(int width, int height, RNG rng) { this.rng = (rng instanceof StatefulRNG) ? (StatefulRNG) rng : new StatefulRNG(rng.nextLong()); gen = new DungeonBoneGen(this.rng); utility = new DungeonUtility(this.rng); rebuildSeed = this.rng.getState(); this.height = height; this.width = width; fx = new EnumMap<>(FillEffect.class); }
private void postMove() { phase = Phase.MONSTER_ANIM; // The next two lines are important to avoid monsters treating cells the player WAS in as goals. getToPlayer.clearGoals(); getToPlayer.resetMap(); // now that goals are cleared, we can mark the current player position as a goal. getToPlayer.setGoal(player.gridX, player.gridY); // this is an important piece of DijkstraMap usage; the argument is a Set of Points for squares // that // temporarily cannot be moved through (not walls, which are automatically known because the map // char[][] // was passed to the DijkstraMap constructor, but things like moving creatures and objects). LinkedHashSet<Coord> monplaces = monsters.positions(); pathMap = getToPlayer.scan(monplaces); // recalculate FOV, store it in fovmap for the render to use. fovmap = fov.calculateFOV(res, player.gridX, player.gridY, 8, Radius.SQUARE); // handle monster turns ArrayList<Coord> nextMovePositions = new ArrayList<Coord>(25); for (Coord pos : monsters.positions()) { Monster mon = monsters.get(pos); // monster values are used to store their aggression, 1 for actively stalking the player, 0 // for not. if (mon.state > 0 || fovmap[pos.x][pos.y] > 0.1) { if (mon.state == 0) { messages.appendMessage( "The PHANTOM cackles at you, \"" + FakeLanguageGen.RUSSIAN_AUTHENTIC.sentence( rng, 1, 3, new String[] {",", ",", ",", " -"}, new String[] {"!"}, 0.25) + "\""); } // this block is used to ensure that the monster picks the best path, or a random choice if // there // is more than one equally good best option. Direction choice = null; double best = 9999.0; Direction[] ds = new Direction[8]; rng.shuffle(Direction.OUTWARDS, ds); for (Direction d : ds) { Coord tmp = pos.translate(d); if (pathMap[tmp.x][tmp.y] < best && !checkOverlap(mon, tmp.x, tmp.y, nextMovePositions)) { // pathMap is a 2D array of doubles where 0 is the goal (the player). // we use best to store which option is closest to the goal. best = pathMap[tmp.x][tmp.y]; choice = d; } } if (choice != null) { Coord tmp = pos.translate(choice); // if we would move into the player, instead damage the player and give newMons the // current // position of this monster. if (tmp.x == player.gridX && tmp.y == player.gridY) { display.tint(player.gridX * 2, player.gridY, SColor.PURE_CRIMSON, 0, 0.415f); display.tint(player.gridX * 2 + 1, player.gridY, SColor.PURE_CRIMSON, 0, 0.415f); health--; // player.setText("" + health); monsters.positionalModify(pos, mon.change(1)); } // otherwise store the new position in newMons. else { /*if (fovmap[mon.getKey().x][mon.getKey().y] > 0.0) { display.put(mon.getKey().x, mon.getKey().y, 'M', 11); }*/ nextMovePositions.add(tmp); monsters.positionalModify(pos, mon.change(1)); monsters.move(pos, tmp); display.slide(mon.entity, tmp.x, tmp.y); } } else { monsters.positionalModify(pos, mon.change(1)); } } } }