extends Node3D class_name level @export var map_name : String = "Map Name" @export var gamemode : gamemode @export var player : Node @export var MAX_PARTICLES = 100 @export_group("Drops") @export var drop_chance_minimum = .1 @export var expected_ammo = {"light" : 200, "medium" : 50, "heavy" : 25,"shotgun" : 20, "rocket" : 3} #light, medium,heavy,shotgun,rocket @export var stamina_drop_enabled = true @export var money_drop_enabled = true @onready var item_pickup = preload("res://assets/item_pickup.tscn") @onready var crown = preload("res://assets/crown.tscn") var dead_player = preload("res://assets/dead_cam.tscn") const DEAD_ANNOUNCE = preload("res://assets/dead_announce.tscn") const CHEST_1 = preload("res://chest1.tscn") var level_name var paused = false var chest_spawners = [] var pickups = [] var keys = [] var guns_dict = {} var particle_number = 0 var enemy_hiveminds = [] var remaining_enemies var last_hit : Node var target_type var respawn_position var respawn_cam_rotation var respawn_rot var engine_time_scale_cache : float = 1.0 # Called when the node enters the scene tree for the first time. func _ready(): level_name = self.get_name() GameGlobals.current_level = str(self.scene_file_path) if GameGlobals.loading_gamemode != null: gamemode = GameGlobals.loading_gamemode GameGlobals.loading_gamemode = null #connect to signals SignalBus.enemy_count_changed.connect(enemy_count) GameGlobals.health = gamemode.start_health #LOAD DATA SaveLoad.load_persistent_data() SaveLoad.load_user_data() if SaveLoad.data_cleared or !gamemode.load_save: refresh_scene() GameGlobals.game_loaded = true SignalBus.emit_signal("game_loaded") else: if SaveLoad.check_save_game_exists(level_name): SaveLoad.load_save_game_data(level_name) else: refresh_scene() #Spawn Crown if GameGlobals.last_hit_path: var crown_spawn = crown.instantiate() var crown_target = get_node(GameGlobals.last_hit_path) if crown_target: crown_target.add_child(crown_spawn) crown_spawn.position = Vector3(0,2,0) if crown_target.is_in_group("enemy"): crown_target.loot_amount = 10 #global randomize function randomize() #clear spawned in objects for node in get_tree().get_nodes_in_group("spawned"): node.queue_free() #find enemy hiveminds for node in get_tree().get_nodes_in_group("enemy_hivemind"): enemy_hiveminds.append(node) #count starting enemies enemy_count() chest_spawners = get_tree().get_nodes_in_group("chest_spawner") if chest_spawners.size() > 0: for i in chest_spawners: i.visible = false var number_chests = randi_range(1,gamemode.max_number_of_chests) while number_chests > 0: var chest_loc = chest_spawners.pick_random() var instance_chest = CHEST_1.instantiate() print("SPAWNING CHEST AT : ",chest_loc.name) instance_chest.global_position = chest_loc.global_position instance_chest.global_rotation = chest_loc.global_rotation get_tree().current_scene.add_child(instance_chest) number_chests -= 1 func refresh_scene(): GameGlobals.health = gamemode.start_health respawn_position = player.camera.global_position respawn_cam_rotation = player.global_transform.basis if player: #Set up starting guns and ammo if gamemode.gun_1 != null: GameGlobals.held_guns = [gamemode.gun_1] var instance_gun = GameGlobals.held_guns[0].instantiate() player.add_ammo(true,instance_gun.gun_name,instance_gun.ammo_type,instance_gun.max_ammo,instance_gun.start_mags) if gamemode.gun_2 != null: GameGlobals.held_guns.append(gamemode.gun_2) var instance_gun_2 = GameGlobals.held_guns[1].instantiate() player.add_ammo(true,instance_gun_2.gun_name,instance_gun_2.ammo_type,instance_gun_2.max_ammo,instance_gun_2.start_mags) # Spawn first gun if gamemode.gun_1 != null: GameGlobals.current_gun_index = 0 gun_spawn(0) # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(_delta): pass func gun_spawn(index): #loop around if scrolling past available guns if index > GameGlobals.held_guns.size() - 1: index = 0 elif index < 0: index = GameGlobals.held_guns.size() - 1 GameGlobals.current_gun_index = index if GameGlobals.held_guns != []: var instance_gun = GameGlobals.held_guns[index].instantiate() instance_gun.global_transform.origin = player.weapon_spawner.position player.gun = instance_gun player.def_weapon_holder_pos = player.weapon_holder.position instance_gun.gun_index = index instance_gun.anim_player.play("swap_in") player.weapon_holder.add_child(instance_gun) func enemy_count(): var sum = 0 var enemies = get_tree().get_nodes_in_group("enemy") for i in enemies: if i.get_class() == "CharacterBody3D": sum += 1 print("enemies: " + str(sum)) if sum == 0: cleared() func cleared(): pass func die(): SignalBus.emit_signal("player_exiting_tree") #record stats GameGlobals.money_penalty() GameGlobals.weapon_penalty() if GameGlobals.player_deaths: GameGlobals.player_deaths += 1 SaveLoad.save_user_data() var deadmsg = DEAD_ANNOUNCE.instantiate() get_parent().add_child(deadmsg) var instance_dead = dead_player.instantiate() instance_dead.global_position = player.camera.global_position instance_dead.transform.basis = player.global_transform.basis if last_hit != null: instance_dead.target = last_hit GameGlobals.last_hit_path = str(last_hit.get_path()) instance_dead.target_type = target_type instance_dead.respawn_position = respawn_position instance_dead.respawn_rotation = respawn_cam_rotation instance_dead.respawn_fov = player.camera.fov get_tree().get_root().add_child(instance_dead) instance_dead.camera.current = true player.dead = true player.toggle_hud(false) player.visible = false player.health_indicator.color = Color(0.471, 0, 0, 0) func pickup_spawn(randomized): var pickup_type var ammo_type var value if randomized: #random item pickup_type = randi_range(0,3) #if item type is ammo, pick random ammo if pickup_type == 0: var player_ammo = GameGlobals.ammo_reserve.keys() ammo_type = int(player_ammo.pick_random()) #random value of pickup value = randi_range(1,50) else: var health_weight if gamemode.health_drop_enabled: health_weight = (1.0 - (GameGlobals.health / gamemode.start_health)) + drop_chance_minimum else: health_weight = 0 var stamina_weight if stamina_drop_enabled: stamina_weight = (1.0 - (player.remaining_stamina / gamemode.max_stamina)) + drop_chance_minimum else: stamina_weight = 0 var money_weight if money_drop_enabled: money_weight = 1 + drop_chance_minimum #fix this logic later once the economy makes sense else: money_weight = 0 var ammo_weight if gamemode.ammo_drop_enabled: ammo_weight = drop_chance_minimum else: ammo_weight = 0 var ammo_type_weight = {} # weight ammo player owns against expected ammo values if gamemode.ammo_drop_enabled: for i in GameGlobals.ammo_reserve.keys(): var i_weight match int(i): 0: i_weight = 1.0 - clamp(float(GameGlobals.ammo_reserve[str(i)]) / float(gamemode.expected_ammo["light"]),0,1) 1: i_weight = 1.0 - clamp(float(GameGlobals.ammo_reserve[str(i)]) / float(gamemode.expected_ammo["medium"]),0,1) 2: i_weight = 1.0 - clamp(float(GameGlobals.ammo_reserve[str(i)]) / float(gamemode.expected_ammo["heavy"]),0,1) 3: i_weight = 1.0 - clamp(float(GameGlobals.ammo_reserve[str(i)]) / float(gamemode.expected_ammo["shotgun"]),0,1) 4: i_weight = 1.0 - clamp(float(GameGlobals.ammo_reserve[str(i)]) / float(gamemode.expected_ammo["rocket"]),0,1) 5: i_weight = 0 if i_weight > ammo_weight: ammo_weight = i_weight ammo_type_weight.erase(5) ammo_type_weight[i] = i_weight + drop_chance_minimum pickup_type = HelperFuncs.weighted_random({"0" : ammo_weight, "1" : stamina_weight,"2" : health_weight,"3" : money_weight}) match pickup_type: "0": if ammo_type_weight.size() > 0: ammo_type = int(HelperFuncs.weighted_random(ammo_type_weight)) else: ammo_type = randi_range(0,4) value = randi_range(1,20) "1": value = randi_range(int(gamemode.max_stamina * .25),gamemode.max_stamina) "2": value = randi_range(int(gamemode.start_health * .25),gamemode.start_health) "3": var bill_denoms = [5,10,20,50,100] value = bill_denoms.pick_random() return {"pickup_type" : pickup_type,"ammo_type" : ammo_type,"value" : value} func save_quit(): SignalBus.emit_signal("player_exiting_tree") SaveLoad.save_game_data(self.get_name()) SaveLoad.save_user_data() SaveLoad.save_persistent_data() get_tree().quit()