class_name Rooms extends RefCounted ## Hand-authored room stamps, as text. ## ## Boss arenas are authored rather than generated: a boss fight is a designed ## space -- sightlines, cover, room to dodge a wall pattern -- and a generator ## that produces "a room" produces a bad one about as often as a good one. The ## corridors and filler rooms around them are generated; the fights are not. ## ## Legend: ## # wall o pillar ~ pit = barricade ## . floor B boss spawn D doorway (floor, corridors connect here) const LEGEND := { "#": MapGrid.Kind.WALL, "o": MapGrid.Kind.PILLAR, "~": MapGrid.Kind.PIT, "=": MapGrid.Kind.BARRICADE, ".": MapGrid.Kind.FLOOR, "B": MapGrid.Kind.FLOOR, "D": MapGrid.Kind.FLOOR, "P": MapGrid.Kind.FLOOR, "S": MapGrid.Kind.FLOOR, "T": MapGrid.Kind.FLOOR, "U": MapGrid.Kind.FLOOR, } ## Legend characters that record a position rather than only painting a tile. const MARKERS := ["B", "D", "P", "S", "T", "U"] ## Wide, with pillars to break the Warden's rings and pits that shape where you ## can retreat to. The door is deliberately on one wall only: the boss cannot ## follow you out, so the exit is a real decision rather than an accident. static func warden_hall() -> PackedStringArray: return PackedStringArray([ "#########################", "#.......................#", "#..~~~...........~~~....#", "#..~~~....o.o....~~~....#", "#.........................", "#....o.................o#", "#.............B.........#", "#....o.................o#", "D.........................", "#..~~~....o.o....~~~....#", "#..~~~..........~~~.....#", "#.......................#", "#########################", ]) ## Tighter and more claustrophobic, with barricades you can see over but not ## shoot through -- a room that rewards knowing where the boss is without ## giving you a firing lane to it. static func choir_vault() -> PackedStringArray: return PackedStringArray([ "#####################", "#...................#", "#..===.......===....#", "#...................#", "#....o.......o......#", "D.........B.........#", "#....o.......o......#", "#...................#", "#..===.......===....#", "#...................#", "#####################", ]) static func size_of(stamp: PackedStringArray) -> Vector2i: if stamp.is_empty(): return Vector2i.ZERO var w := 0 for row in stamp: w = maxi(w, row.length()) return Vector2i(w, stamp.size()) ## Paint a stamp into [param grid] with its top-left at [param origin]. ## Returns the marker positions found, keyed by their legend character. static func stamp(grid: MapGrid, s: PackedStringArray, origin: Vector2i) -> Dictionary: var markers := {} for m in MARKERS: markers[m] = [] for y in s.size(): var row := s[y] for x in row.length(): var ch := row[x] if not LEGEND.has(ch): continue var tx := origin.x + x var ty := origin.y + y grid.set_tile(tx, ty, LEGEND[ch]) if markers.has(ch): markers[ch].append(Vector2i(tx, ty)) return markers ## The hub. Hand-authored like the boss arenas. ## ## P a dungeon portal S player spawn T practice target ## U the upgrade NPC ## ## Each `P`, in reading order, opens the matching entry in Dungeons.ORDER. Two ## of them now: the real run and the Proving Grounds, side by side so they can ## be compared without restarting anything. Adding a third dungeon means adding ## a third marker here. static func lobby() -> PackedStringArray: return PackedStringArray([ "#########################################", "#.......................................#", "#.......................................#", "#.......................................#", "#..............P.........P..............#", "#.......................................#", "#.....o...........................o.....#", "#.......................................#", "#.......................................#", "#.......................................#", "#.........T...................U.........#", "#.......................................#", "#.......................................#", "#.......................................#", "#.....o...........................o.....#", "#...................S...................#", "#.......................................#", "#.......................................#", "#.......................................#", "#.......................................#", "#########################################", ])