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") @onready var task_list: Node = $TaskList #Contains all tiles in a workplace. var lookup_place_to_tile: Dictionary = {} #Contains all rooms in a workplace. #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 action 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 if confirming a build is allowed var build_confirm_allowed: bool = true #The object that's currently being built var current_object: Object = null #Where that object can be placed var available_placements :Array = [] var current_placement :Vector3 #Tracks parts of the room currently being built var current_room: Object = null @onready var map :PlaceMap = $PlaceMap 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() -> void: map.temp_create_map() init_tiles() func init_tiles() -> void: for map_pos :Vector3i in map.tile_map.keys(): var real_pos :Vector3i = map_pos / 12 var tile :Tile = load_tile.instantiate() map.tile_map[map_pos]["object"] = tile tile.set_position(real_pos) #TEMP tile.map_position = map_pos tile.place_position = real_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 :Vector3) -> void: #starts a selection drag var build_start_pos :Vector3i = Vector3i(click_pos.round()) 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 :Vector3, float_build_mouse_pos :Vector3) -> void: #Creats an array of dragged tiles between mouse start and current position var select_drag_array: Array = [] var build_start_pos: Vector3i = Vector3i(float_build_start_pos.round()) var build_mouse_pos: Vector3i = Vector3i(float_build_mouse_pos.round()) 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 :Array) -> void: #Clears previous drag, then calls tile selection on all currently dragged tiles for i :Vector3i in lookup_place_to_tile.keys(): 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 :Vector3i in array: select_tile(i) func select_tile(pos :Vector3i) -> void: #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() -> bool: #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 :Vector3i 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() -> void: #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 :Vector3i in selection_dict.keys(): lookup_place_to_tile[i].selection_mode = Tile.SEL_MODE.BUILD else: build_confirm_allowed = false for i :Vector3i in selection_dict.keys(): lookup_place_to_tile[i].selection_mode = Tile.SEL_MODE.INVALID selection_drag_dict.clear() func build_selection() -> void: #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: create_room(selection_dict) for i :Vector3i in selection_dict.keys(): 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() func clear_selection() -> void: #When the clear button is clicked, it clears the selected tiles without doing anything. for i :Vector3i in selection_dict.keys(): var tile: Object = selection_dict[i] tile.selection_mode = Tile.SEL_MODE.NONE build_confirm_allowed = true selection_dict.clear() func create_room(selection :Dictionary) -> Room: #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 :Vector3i in selection.keys(): map.tile_map[i * 12]["state"] = PlaceMap.TILE_STATE.OPEN for j :Vector3i in Tile.direction_vector_dict.values(): if not selection.keys().has(i - j): map.wall_map[(i * 12) - (j * 6)]["state"] = PlaceMap.WALL_STATE.CLOSED map.room_map[room] = selection.values() for i :Tile in room.room_to_tile: i.lookup_tile_to_room = room return room func init_object(object): #Instantiates the object to be placed match object: "door": var door: Object = load_door.instantiate() init_object_placements(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_placements(object :Object) -> void: #Gets the list of locations that the object can be placed match object.placement: GameObject.PLACEMENTS.DOOR: for i :Vector3i in map.wall_map: var tile_1 :Vector3i var tile_2 :Vector3i if map.wall_map[i]["state"] == map.WALL_STATE.CLOSED: if i.x % 12 == 0: tile_1 = i + Vector3i(0, 0, -6) tile_2 = i + Vector3i(0, 0, 6) else: tile_1 = i + Vector3i(-6, 0, 0) tile_2 = i + Vector3i(6, 0, 0) if map.tile_map.has(tile_1) and map.tile_map.has(tile_2): if map.tile_map[tile_1]["state"] == map.TILE_STATE.OPEN and map.tile_map[tile_2]["state"] == map.TILE_STATE.OPEN: available_placements.append(Vector3(i) / 12) func hover_object(mouse_pos :Vector3) -> void: #Hovers the object at the closest acceptable placement location to the mouse current_object.visible = true if available_placements: var closest: Vector3 var closest_distance: float = INF for i :Vector3 in available_placements: var distance: float = mouse_pos.distance_to(i) if closest_distance > distance: closest_distance = distance closest = i current_placement = closest current_object.position = current_placement current_object.rotation_degrees = Vector3(0, 180 * fmod(closest.x, 1), 0) else: current_object.position = mouse_pos func confirm_object() -> void: #Places the object at the hovered location #TODO: this is very sloppy if current_object is Door: pass # #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.lookup_tile_to_room.room_to_door.append(current_object) # #tile_2.lookup_connected_rooms.append(tile_1.lookup_tile_to_room) # #tile_2.lookup_tile_to_room.room_to_tile.append(tile_1) # #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.lookup_tile_to_room.room_to_door.append(current_object) # #tile_1.lookup_connected_rooms.append(tile_2.lookup_tile_to_room) # #tile_1.lookup_tile_to_room.room_to_tile.append(tile_2) # #current_object.lookup_door_to_room.append(tile_1.lookup_tile_to_room) #current_object.lookup_door_to_room.append(tile_2.lookup_tile_to_room) #current_object.lookup_door_to_tile[tile_1] = tile_1_door_face #current_object.lookup_door_to_tile[tile_2] = tile_2_door_face # #var id = map.get_available_point_id() #map.add_point(id, current_object.position) #current_object.map_point = id #prints(map.get_point_ids()) #for i in tile_1.lookup_tile_to_room.room_to_door: #if i.map_point != id: #map.connect_points(i.map_point, id) #for i in tile_2.lookup_tile_to_room.room_to_door: #if i.map_point != id: #map.connect_points(i.map_point, id) #prints(map.get_point_connections(id)) elif current_object is Actor: current_object.actor_state = Actor.ACTOR_STATE.PAUSED current_room = null available_placements = [] current_object = null func give_neighbors(tile, map_position, directions): #Responds to a tile's request for it's neighbors var neighbor_dict = {} for i in directions.keys(): if lookup_place_to_tile.has(directions[i] + map_position): neighbor_dict[directions[i]] = lookup_place_to_tile[directions[i] + map_position] tile.neighbor_dict = neighbor_dict func give_walls(tile :Tile) -> void: map.give_walls(tile) func _on_tile_container_child_entered_tree(node: Node) -> void: #Connects signals from created tiles lookup_place_to_tile[node.place_position] = node node.connect("neighbor_request", give_neighbors) node.connect("wall_request", give_walls) func _on_actor_container_child_entered_tree(node: Node) -> void: #Connects signals from created actors node.connect("current_tile_request", give_tile) node.connect("map_request", give_map) if node.has_node("TaskCreator"): var tasker = node.get_node("TaskCreator") tasker.connect("record_task", record_task) tasker.connect("finish_task", finish_task) func _on_room_container_child_entered_tree(node: Node) -> void: #Connects signals from created rooms pass func give_map(actor, start, end): var end_tile:Tile = lookup_place_to_tile[end] if end_tile.construction_mode == Tile.CON_MODE.BUILT: var start_id = map.get_available_point_id() map.add_point(start_id, start) var start_room_doors = lookup_place_to_tile[start].lookup_tile_to_room.room_to_door if start_room_doors == []: actor.temp_complete_task() return for i in start_room_doors: var door_id = map.get_closest_point(i.position) map.connect_points(start_id, door_id) var end_id = map.get_available_point_id() map.add_point(end_id, end) var end_room_doors = lookup_place_to_tile[end].lookup_tile_to_room.room_to_door if end_room_doors == []: actor.temp_complete_task() return for i in end_room_doors: var door_id = map.get_closest_point(i.position) map.connect_points(end_id, door_id) var place_path_id = map.get_id_path(start_id, end_id) var place_path_pos = [] for i in place_path_id: place_path_pos.append(map.get_point_position(i)) actor.current_place_path = place_path_pos else: actor.temp_complete_task() func give_tile(actor): #Responds to an actor's request for its current tile #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 var loc = Vector3i(round(actor.position.x), 0, round(actor.position.z)) actor.current_tile = lookup_place_to_tile[loc] func record_task(task): #Records created tasks in the task list. task_list.record_task(task) func finish_task(source, task): #Marks tasks as completed in the task list. task_list.finish_task(source, task)