class_name Level extends Node3D const map_marker_templates : Dictionary[String, PackedScene] = { "pawn" : preload("res://templates/markers/pawn_marker.tscn"), "friendly_hack":preload("res://templates/markers/friendly_hack_marker.tscn"), "enemy_hack": preload("res://templates/markers/enemy_hack_marker.tscn"), "item": preload("res://templates/markers/item_marker.tscn") } const pawn_controller = preload("res://templates/pawn_controller.tscn") const hack_template = preload("res://templates/hack.tscn") const camera_template = preload("res://templates/pawn_camera.tscn") const camera_offset = Vector3(0, 10, 5.25) @onready var floor_layer : GridMap = %Floor @onready var ramp_layer : GridMap = %Ramps @onready var marker_layer : GridMap = %Markers @onready var pawns_node : Node3D = %Pawns @onready var hacks_node : Node3D = %Hacks @onready var cameras_node : Node3D = %Cameras @onready var map_markers_node : Node3D = %MapMarkers @onready var spawn_points : Array[Node] = $PawnSpawner.get_children() @onready var multiplayer_level_setup : MultiplayerLevelSetup = %MultiplayerLevelSetup @export var difficulty : int = 1 var hacks : Dictionary[Vector3i, Hack] = {} var pawns : Dictionary[int, PawnController] = {} var cameras : Dictionary[int, PawnCamera] = {} var map_markers : Dictionary[Object, MapMarker] = {} func _ready() -> void: process_mode=Node.PROCESS_MODE_DISABLED Game.level = self if Game.mode == Game.Modes.STORY: setup() #add_level_hack.call_deferred(Hack.Type.PURGE, Vector3.ZERO, Vector3i(-2,2,0)) func setup() -> void: if Multiplayer.is_host(): spawn_players() @rpc("authority") func spawn_players() -> void: if Game.is_multiplayer(): spawn_players_multiplayer() else: spawn_players_singleplayer() func spawn_players_singleplayer() -> void: var pc : PawnController = pawn_controller.instantiate() pawns[1] = pc pawns_node.add_child(pc,true) var pos : Vector3 if(spawn_points == null or len(spawn_points) <= 1): pos = Vector3(0,0,0) else: pos = spawn_points[0].global_position pc.global_position = pos pc.setup(1, Game.pawns_selected[1]) add_pawn_camera(pc) cameras[1].register_pawn(1) process_mode=Node.PROCESS_MODE_INHERIT func spawn_players_multiplayer() -> void: var count = 0 multiplayer_level_setup.set_players_unready(Multiplayer.players.values()) multiplayer_level_setup.set_pawns_expected.rpc(Game.pawns_selected.size()) for key in Game.pawns_selected: var pc : PawnController = pawn_controller.instantiate() pawns[key] = pc pawns_node.add_child(pc,true) await multiplayer_level_setup.all_players_ready for key in pawns: var pc = pawns[key] var pos : Vector3 if(spawn_points == null or len(spawn_points) <= count): if key == Multiplayer.id: pos = Vector3(0,0,0) else: pos = Vector3(3,0,0) else: pos = spawn_points[count].global_position count += 1 pc.global_position = pos pc.setup.rpc(key, Game.pawns_selected[key]) multiplayer_level_setup.set_players_unready(Multiplayer.players.values()) multiplayer_level_setup.set_cameras_expected.rpc(Game.pawns_selected.size()) for pc in pawns.values(): add_pawn_camera(pc) await multiplayer_level_setup.all_players_ready setup_cameras() start_level.rpc() @rpc("authority", "call_local") func start_level() -> void: process_mode=Node.PROCESS_MODE_INHERIT func is_square_detected(crd) -> bool: return marker_layer.get_cell_item(crd + Vector3i(0,-1,0)) != GridMap.INVALID_CELL_ITEM func detect_square(crd : Vector3i, mark : bool) -> bool: var cell = floor_layer.get_cell_item(crd) if cell == GridMap.INVALID_CELL_ITEM: return false marker_layer.set_cell_item(crd, 0 if mark else GridMap.INVALID_CELL_ITEM) if mark: var hack_crd = crd + Vector3i(0,1,0) if hacks.has(hack_crd): var hack : Hack = hacks[hack_crd] if hack.hack_owner != Multiplayer.id: hack.reveal() return true func add_pawn_camera(pawn : PawnController) -> void: var camera : PawnCamera = camera_template.instantiate() camera.position = pawn.global_position + camera_offset cameras_node.add_child(camera,true) cameras[pawn.id] = camera func setup_cameras() -> void: var camera_list = cameras_node.get_children() var idx = 0 for pawn_id in pawns: camera_list[idx].register_pawn.rpc(pawn_id) cameras[pawn_id] = camera_list[idx] idx += 1 func add_hack(hack : Hack, crd : Vector3i) -> void: hack.square = crd hacks[crd] = hack hack.position = Vector3(crd) + Vector3(.5, 0, .5) add_child(hack, true) func add_projectile(shot : Projectile) -> void: add_child(shot, true) func uninstall_hack_square(crd : Vector3i) -> void: hacks.erase(crd) func get_square_hack(crd : Vector3i) -> Hack: if hacks.has(crd): return hacks[crd] else: return null func is_valid_hack_square(crd : Vector3i) -> bool: if floor_layer.get_cell_item(crd + Vector3i(0,-1,0)) == GridMap.INVALID_CELL_ITEM: return false if hacks.has(crd): return false return true func add_vfx(vfx, crd : Vector3i) -> void: vfx.position = Vector3(crd) #+ Vector3(0.5, 0, 0.5) add_child(vfx, true) func activate_hack(crd : Vector3i) -> void: if hacks.has(crd): hacks[crd].activate() func generate_hack(type : Hack.Type, dir : Vector3, square : Vector3i): var hack = hack_template.instantiate() hack.setup(type, dir, -1) add_hack(hack, square) func decompile_hack(crd : Vector3i) -> void: var hack = hacks[crd] hack.decompile() hacks.erase(crd) func remove_map_marker(target) -> void: if !map_markers.has(target): printerr("Tried to remove a map marker for %s but marker does not exist!" % target.name) else: map_markers[target].queue_free() map_markers[target] = null func add_map_marker(target) -> void: var marker : MapMarker var height : float = 0 if target is PawnController: marker = map_marker_templates.pawn.instantiate() height += 40 elif target is Hack: if target.hack_owner == Multiplayer.id: marker = map_marker_templates.friendly_hack.instantiate() else: marker = map_marker_templates.enemy_hack.instantiate() marker.visible = false target.revealed.connect(marker._on_hack_revealed) height += 30 elif target is Item: marker = map_marker_templates.item.instantiate() height += 10 marker.register_target(target) map_markers[target] = marker map_markers_node.add_child(marker) marker.position += Vector3(0, height,0) func add_level_hack(type : Hack.Type, facing : Vector3, crd : Vector3i) -> void: var hack = hack_template.instantiate() hack.setup(type, facing, -1) add_hack(hack, crd)