extends Node2D const PLAYER := preload("res://scenes/game/player_ship.tscn") const ENEMY := preload("res://scenes/game/enemy_ship.tscn") const DRONES := preload("res://resources/items/combat_drones.tres") func _ready() -> void: GameState.start_new_run() var ship := PLAYER.instantiate() as CharacterBody2D add_child(ship) ship.set_physics_process(false) var weapons := ship.get_node("WeaponController") weapons.set_physics_process(false) var systems := ship.get_node("ExtensionSystems") systems.set_physics_process(false) var inventory := ship.get_node("ShipInventory") as ShipInventory # Every rank replaces the baseline, respects the energy cap, and uses one bank. for rank in range(4): GameState.captain.skills["electrician"] = rank inventory.energy_banks = 2 ship.set("energy", 0.0) assert(inventory.use_energy_bank()) assert(is_equal_approx(float(ship.get("energy")), float(ship.get("max_energy")) * [0.10, 0.15, 0.20, 0.25][rank])) ship.set("energy", float(ship.get("max_energy")) - 1.0) assert(inventory.use_energy_bank()) assert(ship.get("energy") == ship.get("max_energy")) assert(inventory.energy_banks == 0) assert(preload("res://scripts/captain/captain_skills.gd").icon("electrician") != null) assert(not GameState.captain.equip_skill(0, "electrician")) # Tactics move toward, away from, or around their target, then flee below 50%. var enemy := ENEMY.instantiate() as CharacterBody2D enemy.position = Vector2(250, 0) add_child(enemy) enemy.set_physics_process(false) enemy.set("_player", ship) enemy.set("tactic", 0) assert(enemy.call("combat_movement", Vector2(200, 0)).x > 0.0) enemy.set("tactic", 1) assert(enemy.call("combat_movement", Vector2(100, 0)).x < 0.0) assert(enemy.call("combat_movement", Vector2(700, 0)).x > 0.0) assert(absf(enemy.call("combat_movement", Vector2(420, 0)).y) > 0.0) enemy.set("hull", float(enemy.get("max_hull")) * 0.5) assert(not enemy.call("is_retreating")) enemy.set("hull", float(enemy.get("max_hull")) * 0.49) for tactic in [0, 1]: enemy.set("tactic", tactic) assert(enemy.call("is_retreating")) assert(enemy.call("combat_movement", Vector2(500, 0)).x < 0.0) enemy.set("hull", 10000.0) # Module is lootable, charges exactly 50 ammo even with the ammunition passive. assert(DRONES in preload("res://scripts/items/item_generator.gd").DEFINITIONS) var module := ItemInstance.new() module.definition = DRONES inventory.extension_slots[0] = module GameState.captain.skills["efficient_magazine"] = 3 inventory.ammunition = 49 assert(not ship.call("activate_ability", 0)) assert(inventory.ammunition == 49) inventory.ammunition = 100 var dps := inventory.get_total_dps() assert(dps > 0.0) assert(ship.call("activate_ability", 0)) assert(inventory.ammunition == 50) assert(not ship.call("activate_ability", 0)) var drones := get_tree().get_nodes_in_group("player_combat_drones") assert(drones.size() == 3) var total_dps := 0.0 for drone in drones: drone.set_physics_process(false) total_dps += float(drone.get("damage_per_shot")) / float(drone.FIRE_INTERVAL) assert(is_equal_approx(total_dps, dps * 0.5)) assert(is_equal_approx(inventory.get_total_dps(), dps)) await get_tree().physics_frame await get_tree().process_frame var before := float(enemy.get("hull")) + float(enemy.get("shields")) drones[0].position = Vector2(100, 0) drones[0].call("_fire", enemy) for bullet in get_children(): if bullet is Area2D and bullet.get_script() == preload("res://scripts/game/weapon_projectile.gd"): bullet.call("_physics_process", 0.2) assert(float(enemy.get("hull")) + float(enemy.get("shields")) < before, "Drone bullets must damage enemies") assert(inventory.ammunition == 50, "No extra ammunition charged per shot") systems.call("_physics_process", 10.0) for drone in drones: assert(drone.is_queued_for_deletion()) await get_tree().process_frame assert(get_tree().get_nodes_in_group("player_combat_drones").is_empty()) systems.call("reset_combat_state") assert(ship.call("activate_ability", 0)) var deployed := get_tree().get_nodes_in_group("player_combat_drones") for drone in deployed: drone.set_physics_process(false) get_tree().paused = true assert(not ship.call("activate_ability", 0)) await get_tree().create_timer(0.05, true).timeout assert(float(systems.get("drones_remaining")) == 10.0) get_tree().paused = false ship.set("is_docked", true) systems.call("_physics_process", 0.1) await get_tree().process_frame assert(get_tree().get_nodes_in_group("player_combat_drones").is_empty()) ship.set("is_docked", false) systems.call("reset_combat_state") inventory.ammunition = 50 assert(ship.call("activate_ability", 0)) systems.call("reset_combat_state") await get_tree().process_frame assert(get_tree().get_nodes_in_group("player_combat_drones").is_empty()) assert(float(systems.get("drones_remaining")) == 0.0) print("ELECTRICIAN_DRONES_TACTICS_TEST: PASS (four bank strengths/caps, passive icon, tactics and retreat, loot module, exact ammo cost, 3 drones, shared 50% DPS, actual bullet damage, lifetime and reset)") get_tree().quit()