class_name StandardRoom extends TileMap const TILEMAP_LAYER = 0 @export_category("Room Openings") @export var left: bool = false @export var right: bool = false @export var top: bool = false @export var bottom: bool = false ## The rect that the room occupies in the map ## from 0, 0 to room_size.x, room_size.y var room_size: Vector2i ## The size of each tile in the room var cell_size: Vector2i func _init() -> void: self.room_size = self.get_used_rect().size self.cell_size = self.tile_set.tile_size ## Returns true when the room has no exits func is_block() -> bool: if self.left or self.right or self.top or self.bottom: return false return true ## Get the position of the exit in the room func get_exits() -> Array[Vector2i]: var exits: Array[Vector2i] = [] if self.left: exits.append(Vector2i.LEFT) if self.right: exits.append(Vector2i.RIGHT) if self.top: exits.append(Vector2i.UP) if self.bottom: exits.append(Vector2i.DOWN) return exits ## Get the position of the exit in the room func get_exit_pos(exit: Vector2i) -> Vector2i: var pos: Vector2i = Vector2i.ZERO if exit == Vector2i.LEFT: pos = Vector2i(0, self.room_size.y / 2) elif exit == Vector2i.RIGHT: pos = Vector2i(self.room_size.x - 1, self.room_size.y / 2) elif exit == Vector2i.UP: pos = Vector2i(self.room_size.x / 2, 0) elif exit == Vector2i.DOWN: pos = Vector2i(self.room_size.x / 2, self.room_size.y - 1) return pos ## Get the offset of the exit position from the edge of the room func get_exit_pos_offset(edge_pos: Vector2i, exit: Vector2i) -> Vector2i: match exit: Vector2i.UP: return edge_pos + Vector2i(self.room_size.x / -2, self.room_size.y * -1) Vector2i.DOWN: return edge_pos + Vector2i(self.room_size.x / -2, 1) Vector2i.LEFT: return edge_pos + Vector2i(-self.room_size.x, -self.room_size.y / 2) Vector2i.RIGHT: return edge_pos + Vector2i(1, -self.room_size.y / 2) _: return Vector2i.ZERO ## Copy the room to the TileMap at a given position func copy_to_map(map: TileMap) -> void: for x in range(0, self.room_size.x): for y in range(0, self.room_size.y): var tile = self.get_cell_source_id(TILEMAP_LAYER, Vector2i(x, y)) var alt = self.get_cell_alternative_tile(TILEMAP_LAYER, Vector2i(x, y)) if tile != -1: map.set_cell( TILEMAP_LAYER, Vector2i(position.x + x, position.y + y), tile, Vector2i(0, 0), alt ) else: map.set_cell( TILEMAP_LAYER, Vector2i(position.x + x, position.y + y), -1, Vector2i(0, 0) ) ## Seal the exit of a room by placing a tile over it func seal_exit(map: TileMap, pos: Vector2i, exit: Vector2i) -> void: var exit_pos = get_exit_pos(exit) var seal_tile_id = 0 match exit: Vector2i.UP: map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x - 1, pos.y), seal_tile_id, Vector2i(0, 0) ) map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x, pos.y), seal_tile_id, Vector2i(0, 0) ) map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x + 1, pos.y), seal_tile_id, Vector2i(0, 0) ) Vector2i.DOWN: map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x - 1, pos.y), seal_tile_id, Vector2i(0, 0) ) map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x, pos.y), seal_tile_id, Vector2i(0, 0) ) map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x + 1, pos.y), seal_tile_id, Vector2i(0, 0) ) Vector2i.RIGHT: map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x, pos.y - 1), seal_tile_id, Vector2i(0, 0) ) map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x, pos.y), seal_tile_id, Vector2i(0, 0) ) map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x, pos.y + 1), seal_tile_id, Vector2i(0, 0) ) Vector2i.LEFT: map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x, pos.y - 1), seal_tile_id, Vector2i(0, 0) ) map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x, pos.y), seal_tile_id, Vector2i(0, 0) ) map.set_cell( TILEMAP_LAYER, exit_pos + Vector2i(pos.x, pos.y + 1), seal_tile_id, Vector2i(0, 0) ) ## Check if the room overlaps with any tiles in the map func is_overlapping(map: TileMap) -> bool: for x in range(0, self.room_size.x): for y in range(0, self.room_size.y): var tile = map.get_cell_source_id( TILEMAP_LAYER, Vector2i(self.position.x + x, self.position.y + y) ) if tile != -1: return true return false ## Validate room by checking that the top left tile is at 0, 0 and all exits are valid func _validate() -> bool: # If exit on left, check that the middle tile on the left is empty if ( self.left and self.get_cell_source_id(TILEMAP_LAYER, Vector2i(0, self.room_size.y / 2)) != -1 ): push_error("Room with exit on left must have empty middle tile on left") return false # If exit on right, check that the middle tile on the right is empty if ( self.right and ( self.get_cell_source_id( TILEMAP_LAYER, Vector2i(self.room_size.x - 1, self.room_size.y / 2) ) != -1 ) ): push_error("Room with exit on right must have empty middle tile on right") return false # If exit on top, check that the middle tile on the top is empty if self.top and self.get_cell_source_id(TILEMAP_LAYER, Vector2i(self.room_size.x / 2, 0)) != -1: push_error("Room with exit on top must have empty middle tile on top") return false # If exit on bottom, check that the middle tile on the bottom is empty if ( self.bottom and ( self.get_cell_source_id( TILEMAP_LAYER, Vector2i(self.room_size.x / 2, self.room_size.y - 1) ) != -1 ) ): push_error("Room with exit on bottom must have empty middle tile on bottom") return false return true ## Flip a vector func flip_vector(vector: Vector2i) -> Vector2i: return Vector2i(vector.x * -1, vector.y * -1) ## Disable a room exit by setting the corresponding exit variable to false func disable_room_exit_opposite(exit: Vector2i) -> void: self.disable_room_exit(self.flip_vector(exit)) ## Disable a room exit by setting the corresponding exit variable to false func disable_room_exit(exit: Vector2i) -> void: if exit == Vector2i.LEFT: self.left = false elif exit == Vector2i.RIGHT: self.right = false elif exit == Vector2i.UP: self.top = false elif exit == Vector2i.DOWN: self.bottom = false