extends Node3D class_name Place var tile_grid_size: int = 32 var load_tile = preload("res://tiles/base_tile/base_tile.tscn") var load_room = preload("res://places/base_place/base_room.tscn") var load_door = preload("res://tiles/base_tile/base_door.tscn") var load_actor = preload("res://actors/base_actor/base_actor.tscn") #Contains all tiles in a workplace. var lookup_place_to_tile: Dictionary = {} #Contains all rooms in a workplace. var lookup_place_to_room: Array = [] #Contains the tiles in the current selection drag var selection_drag_dict: Dictionary = {} #Contains all the tiles that have been selected in the current build var selection_dict: Dictionary = {} #Tracks the previous amount of tiles counted in a selection drac var tile_count_x_hist: int = 0 var tile_count_z_hist: int = 0 #Tracks is confirming a build is allowed var build_confirm_allowed: bool = true var current_object: Object = null var current_placement: Array = [] #Tracks parts of the room currently being built var current_room: Object = null func save(): var save_data = { # Basics "id": self.get_instance_id(), "type": "Place", "scene_file_path": scene_file_path, "parent": get_parent().get_path(), # Connections # Data } return save_data func init_grid(): #TEMP: Sets up a simple 2D grid of blank tiles. for x in range(tile_grid_size): for z in range (tile_grid_size): var pos = Vector3i(x, 0, z) var tile: Object = load_tile.instantiate() tile.set_position(pos) tile.grid_pos = pos tile.name = str("Tile", tile.get_instance_id()) tile.place_id = self.get_instance_id() tile.selection_mode = Tile.SEL_MODE.NONE tile.construction_mode = Tile.CON_MODE.CLOSED $TileContainer.add_child(tile) func draw_tile_click(click_pos): #starts a selection drag var build_start_pos: Vector3i = click_pos.floor() if lookup_place_to_tile.has(build_start_pos): if not lookup_place_to_tile[build_start_pos].construction_mode == Tile.CON_MODE.BUILT: select_tile(build_start_pos) func init_select_drag(float_build_start_pos, float_build_mouse_pos): #Creats an array of dragged tiles between mouse start and current position var select_drag_array: Array = [] var build_start_pos: Vector3i = float_build_start_pos.floor() var build_mouse_pos: Vector3i = float_build_mouse_pos.floor() var tile_count_x: int = build_mouse_pos.x - build_start_pos.x var tile_count_z: int = build_mouse_pos.z - build_start_pos.z if not tile_count_x_hist == tile_count_x or not tile_count_z_hist == tile_count_z: tile_count_x_hist = tile_count_x tile_count_z_hist = tile_count_z for x in range(min(0, tile_count_x), max(0, tile_count_x) + 1): for z in range(min(0, tile_count_z), max(0, tile_count_z) + 1): var select_drag_pos: Vector3i = build_start_pos + Vector3i(x, 0, z) if lookup_place_to_tile.has(select_drag_pos): if not lookup_place_to_tile[select_drag_pos].construction_mode == Tile.CON_MODE.BUILT: select_drag_array.append(select_drag_pos) if select_drag_array: draw_select_drag(select_drag_array) func draw_select_drag(array): #Clears previous drag, then calls tile selection on all currently dragged tiles for i in lookup_place_to_tile: if not selection_dict.has(i): var tile: Object = lookup_place_to_tile[i] tile.selection_mode = Tile.SEL_MODE.NONE selection_drag_dict.clear() for i in array: select_tile(i) func select_tile(pos): #Tells tiles to be selected var tile: Object = lookup_place_to_tile[pos] selection_drag_dict[pos] = tile if build_confirm_allowed: tile.selection_mode = Tile.SEL_MODE.BUILD else: tile.selection_mode = Tile.SEL_MODE.INVALID func verify_room(): #Verifies that a given selection is fully contiguous var verify_array: Array = selection_dict.keys() var verify_queue_array: Array = [verify_array[0]] var verify_checked_array: Array = [] while verify_array: if not verify_queue_array: return false var verify_pos: Vector3i = verify_queue_array.pop_back() var verify_neighbor_array: Array = lookup_place_to_tile[verify_pos].direction_vector_dict.values() for n in verify_neighbor_array: if selection_dict.has(verify_pos + n): if not verify_checked_array.has(verify_pos + n): if not verify_queue_array.has(verify_pos + n): verify_queue_array.append(verify_pos + n) verify_checked_array.append(verify_pos) verify_array.erase(verify_pos) return true func end_select_drag(): #Adds dragged tiles to the current selection on mouse-up if not selection_drag_dict: return tile_count_x_hist = 0 tile_count_z_hist = 0 selection_dict.merge(selection_drag_dict) if verify_room(): build_confirm_allowed = true for i in selection_dict: lookup_place_to_tile[i].selection_mode = Tile.SEL_MODE.BUILD else: build_confirm_allowed = false for i in selection_dict: lookup_place_to_tile[i].selection_mode = Tile.SEL_MODE.INVALID selection_drag_dict.clear() func build_selection(): #When the build button is clicked, changes the selected tiles to match the button's request if not build_confirm_allowed: return if selection_dict: var room: Object = create_room(selection_dict) for i in selection_dict: var tile: Object = lookup_place_to_tile[i] tile.selection_mode = Tile.SEL_MODE.NONE tile.construction_mode = Tile.CON_MODE.BUILT selection_dict.clear() return room func clear_selection(): #When the clear button is clicked, it clears the selected tiles without doing anything. for i in selection_dict: var tile: Object = selection_dict[i] tile.selection_mode = Tile.SEL_MODE.NONE build_confirm_allowed = true selection_dict.clear() func create_room(selection): #Creates a room from the selected tiles. var room: Object = load_room.instantiate() room.position = (selection.keys().min()) room.room_to_tile = selection.values() room.place_id = self.get_instance_id() room.name = str("Room", room.get_instance_id()) $RoomContainer.add_child(room) for i in room.room_to_tile: i.lookup_tile_to_room.append(room) lookup_place_to_room.append(room) return room func init_object(object): match object: "door": var door: Object = load_door.instantiate() init_object_locations(door) door.place_id = self.get_instance_id() door.visible = false $ObjectContainer.add_child(door) current_object = door "actor": var actor: Actor = load_actor.instantiate() current_object = actor actor.visible = false $ActorContainer.add_child(actor) func init_object_locations(object): match object.placement: GameObject.PLACEMENTS.DOOR: for i in lookup_place_to_tile.keys(): for j in lookup_place_to_tile[i].face_dict.keys(): if lookup_place_to_tile[i].face_dict[j] is not Door: current_placement.append((Vector3(i) + Vector3(0.5, 0, 0.5)) + Vector3(j) / 2) func hover_object(mouse_pos): #Hovers the door at the closest wall segment to the mouse in the current room current_object.visible = true if current_placement: var closest: Vector3 var closest_distance: float = INF for i in current_placement: var distance: float = mouse_pos.distance_to(i) if closest_distance > distance: closest_distance = distance closest = i current_object.position = closest current_object.rotation_degrees = Vector3(0, 180 * fmod(closest.x, 1), 0) else: current_object.position = mouse_pos func confirm_object(): var check = current_object.get_class() if current_object is Door: var tile_1: Object var tile_2: Object if fmod(current_object.position.x, 1) == 0: tile_1 = lookup_place_to_tile[Vector3i(current_object.position.x, 0, current_object.position.z)] tile_2 = lookup_place_to_tile[Vector3i(current_object.position.x - 1, 0, current_object.position.z)] else: tile_1 = lookup_place_to_tile[Vector3i(current_object.position.x, 0, current_object.position.z)] tile_2 = lookup_place_to_tile[Vector3i(current_object.position.x, 0, current_object.position.z - 1)] var tile_1_new_dict = tile_1.face_dict.duplicate() var tile_2_new_dict = tile_2.face_dict.duplicate() var tile_1_door_face: Vector3i = tile_2.position - tile_1.position tile_1_new_dict[tile_1_door_face] = current_object tile_1.update_faces(tile_1_new_dict) tile_1.lookup_tile_to_room[0].room_to_door.append(current_object) var tile_2_door_face: Vector3i = tile_1.position - tile_2.position tile_2_new_dict[tile_2_door_face] = current_object tile_2.update_faces(tile_2_new_dict) tile_2.lookup_tile_to_room[0].room_to_door.append(current_object) current_object.lookup_door_to_room.append(tile_1.lookup_tile_to_room[0]) current_object.lookup_door_to_room.append(tile_2.lookup_tile_to_room[0]) current_object.lookup_door_to_tile[tile_1] = tile_1_door_face current_object.lookup_door_to_tile[tile_2] = tile_2_door_face elif current_object is Actor: current_object.actor_state = Actor.ACTOR_STATE.ACTIVE current_room = null current_placement = [] current_object = null func give_neighbors(tile, grid_pos, directions): var neighbor_dict = {} for i in directions.keys(): if lookup_place_to_tile.has(directions[i] + grid_pos): neighbor_dict[directions[i]] = lookup_place_to_tile[directions[i] + grid_pos] tile.neighbor_dict = neighbor_dict func _on_tile_container_child_entered_tree(node: Node) -> void: lookup_place_to_tile[node.grid_pos] = node node.connect("neighbor_request", give_neighbors) func give_tile(actor): var closest: Vector3 var closest_distance: float = INF for i in lookup_place_to_tile: var distance: float = actor.position.distance_to(i) if closest_distance > distance: closest_distance = distance closest = i actor.current_tile = lookup_place_to_tile[Vector3i(closest)] func _on_actor_container_child_entered_tree(node: Node) -> void: node.connect("current_tile_request", give_tile)