extends Control # --------------------------------------------------------------------------- # Layout constants # --------------------------------------------------------------------------- const MAP_SIZE := Vector2(150, 150) const ROOM_SIZE := Vector2(18, 10) # 16:9 aspect ratio like actual rooms const ROOM_GAP := 4.0 const PADDING := 10.0 const CONNECTION_WIDTH := 2.0 # --------------------------------------------------------------------------- # Colors (brightened versions of room.gd floor colors) # --------------------------------------------------------------------------- const ROOM_COLORS := { RoomData.RoomType.START: Color(0.24, 0.24, 0.36), # blue-grey RoomData.RoomType.COMBAT: Color(0.24, 0.24, 0.36), # blue-grey RoomData.RoomType.ITEM: Color(0.20, 0.32, 0.20), # green RoomData.RoomType.SHOP: Color(0.32, 0.24, 0.16), # brown RoomData.RoomType.BOSS: Color(0.40, 0.16, 0.16), # red } const CURRENT_OUTLINE := Color(1.0, 1.0, 0.4) # bright yellow const CONNECTION_COLOR := Color(0.5, 0.5, 0.6) const UNVISITED_ALPHA := 0.35 const BACKGROUND_COLOR := Color(0.08, 0.08, 0.10, 0.85) # --------------------------------------------------------------------------- # State # --------------------------------------------------------------------------- var _rooms_data: Dictionary = {} # Vector2i -> RoomData var _current_pos: Vector2i = Vector2i.ZERO var _grid_min: Vector2i = Vector2i.ZERO var _grid_max: Vector2i = Vector2i.ZERO # --------------------------------------------------------------------------- # Setup # --------------------------------------------------------------------------- func _ready() -> void: # Position in top-right corner anchor_left = 1.0 anchor_right = 1.0 anchor_top = 0.0 anchor_bottom = 0.0 offset_left = -MAP_SIZE.x - PADDING offset_right = -PADDING offset_top = PADDING offset_bottom = MAP_SIZE.y + PADDING custom_minimum_size = MAP_SIZE # Connect signals EventBus.floor_map_ready.connect(_on_floor_map_ready) EventBus.room_entered_at.connect(_on_room_entered) EventBus.run_ended.connect(_on_run_ended) # --------------------------------------------------------------------------- # Signal handlers # --------------------------------------------------------------------------- func _on_floor_map_ready(rooms_data: Dictionary) -> void: _rooms_data = rooms_data _compute_grid_bounds() queue_redraw() func _on_room_entered(grid_pos: Vector2i) -> void: _current_pos = grid_pos queue_redraw() func _on_run_ended(_reached_hub: bool) -> void: _rooms_data.clear() queue_redraw() # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- func _compute_grid_bounds() -> void: if _rooms_data.is_empty(): _grid_min = Vector2i.ZERO _grid_max = Vector2i.ZERO return var first := true for pos in _rooms_data.keys(): if first: _grid_min = pos _grid_max = pos first = false else: _grid_min.x = mini(_grid_min.x, pos.x) _grid_min.y = mini(_grid_min.y, pos.y) _grid_max.x = maxi(_grid_max.x, pos.x) _grid_max.y = maxi(_grid_max.y, pos.y) func _get_visible_rooms() -> Dictionary: # Returns {Vector2i -> {"data": RoomData, "visited": bool}} var visible := {} var known_positions: Array[Vector2i] = [] # First pass: collect visited rooms and their adjacent positions for pos in _rooms_data.keys(): var room: RoomData = _rooms_data[pos] if room.visited: visible[pos] = {"data": room, "visited": true} for conn_pos in room.connections.values(): if conn_pos not in known_positions: known_positions.append(conn_pos) # Second pass: add adjacent (known but unvisited) rooms for pos in known_positions: if pos not in visible and _rooms_data.has(pos): visible[pos] = {"data": _rooms_data[pos], "visited": false} return visible func _grid_to_map_pos(grid_pos: Vector2i) -> Vector2: # Convert grid position to local drawing coordinates var cell_size := ROOM_SIZE + Vector2(ROOM_GAP, ROOM_GAP) var grid_size := Vector2i(_grid_max.x - _grid_min.x + 1, _grid_max.y - _grid_min.y + 1) var total_size := Vector2(grid_size.x, grid_size.y) * cell_size - Vector2(ROOM_GAP, ROOM_GAP) # Center the map within the control var centering := (MAP_SIZE - total_size) / 2.0 var offset := Vector2( (grid_pos.x - _grid_min.x) * cell_size.x, (grid_pos.y - _grid_min.y) * cell_size.y ) return centering + offset # --------------------------------------------------------------------------- # Drawing # --------------------------------------------------------------------------- func _draw() -> void: if _rooms_data.is_empty(): return # Background panel draw_rect(Rect2(Vector2.ZERO, MAP_SIZE), BACKGROUND_COLOR) var visible := _get_visible_rooms() # Draw connections first (under rooms) for pos in visible.keys(): var room: RoomData = visible[pos]["data"] var room_center := _grid_to_map_pos(pos) + ROOM_SIZE / 2.0 for dir in room.connections.keys(): var conn_pos: Vector2i = room.connections[dir] if visible.has(conn_pos): var conn_center := _grid_to_map_pos(conn_pos) + ROOM_SIZE / 2.0 # Only draw each connection once (from lower to higher grid pos) if pos.x < conn_pos.x or (pos.x == conn_pos.x and pos.y < conn_pos.y): draw_line(room_center, conn_center, CONNECTION_COLOR, CONNECTION_WIDTH) # Draw rooms for pos in visible.keys(): var info: Dictionary = visible[pos] var room: RoomData = info["data"] var is_visited: bool = info["visited"] var map_pos := _grid_to_map_pos(pos) var rect := Rect2(map_pos, ROOM_SIZE) # Room color with alpha based on visited state var color: Color = ROOM_COLORS.get(room.type, ROOM_COLORS[RoomData.RoomType.COMBAT]) if not is_visited: color.a = UNVISITED_ALPHA draw_rect(rect, color) # Current room indicator - bright outline if pos == _current_pos: draw_rect(rect, CURRENT_OUTLINE, false, 2.0)