extends Node const CATALOG := preload("res://scripts/captain/captain_skills.gd") const PROGRESS := preload("res://scripts/captain/captain_progress.gd") const POI := preload("res://scripts/levels/exploration_poi.gd") func _ready() -> void: _test_offers() GameState.start_new_run() var game := preload("res://scenes/game/game.tscn").instantiate() add_child(game) game.set_physics_process(false) var ship: CharacterBody2D = game.get_node("PlayerShip") ship.set_physics_process(false) ship.get_node("WeaponController").set_physics_process(false) for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) var captain := GameState.captain var inventory: ShipInventory = ship.get_node("ShipInventory") for rank in range(1, 4): captain.skills["business_shark"] = rank assert(inventory.get_ammunition_buy_cost() == [54, 42, 24][rank - 1]) assert(inventory.get_missile_buy_cost() == [27, 21, 12][rank - 1]) assert(inventory.get_irradiated_ammunition_buy_cost() == [45, 35, 20][rank - 1]) captain.skills["efficient_magazine"] = rank captain._ammo_credit.clear() inventory.ammunition = 100 inventory.irradiated_ammunition = 100 for shot in 100: assert(inventory.consume_ammunition()) assert(inventory.consume_irradiated_ammunition()) assert(inventory.ammunition == [10, 20, 50][rank - 1]) assert(inventory.irradiated_ammunition == [10, 20, 50][rank - 1]) inventory.missile_ammunition = 2 assert(inventory.consume_missile()) assert(inventory.missile_ammunition == 1) captain.skills["reactor_overload"] = rank captain.skills["tactical_maneuver"] = rank captain.skills["power_redirect"] = rank assert(captain.equip_skill(0, "reactor_overload")) assert(captain.equip_skill(1, "tactical_maneuver")) assert(captain.equip_skill(2, "power_redirect")) captain.skill_cooldowns.clear() captain.skill_durations.clear() var base_regeneration: float = ship.get_energy_regeneration() assert(captain.activate_skill("reactor_overload", ship)) assert(is_equal_approx(ship.get_energy_regeneration(), base_regeneration * [1.2, 1.5, 2.0][rank - 1])) ship.energy = 0.0 ship._physics_process(0.1) assert(is_equal_approx(ship.energy, base_regeneration * [1.2, 1.5, 2.0][rank - 1] * 0.1)) assert(not captain.activate_skill("reactor_overload", ship)) assert(captain.activate_skill("tactical_maneuver", ship)) assert(is_equal_approx(ship.get_evasion_chance(), [0.3, 0.6, 1.0][rank - 1])) if rank == 3: var before_hit: float = ship.shields ship.take_damage(100.0) assert(ship.shields == before_hit) ship.shields = ship.max_shields * 0.24 assert(not captain.activate_skill("power_redirect", ship)) assert(not captain.skill_cooldowns.has("power_redirect")) ship.shields = ship.max_shields * 0.25 assert(captain.activate_skill("power_redirect", ship)) assert(ship.shields == 0.0) assert(is_equal_approx(captain.energy_regeneration_multiplier(), 1.0 + [0.2, 0.5, 1.0][rank - 1] + [0.5, 0.9, 1.5][rank - 1])) ship.shield_on_damage_percent = 100.0 ship.restore_shields_from_damage(100.0) assert(ship.shields == 0.0) var shield_ability := preload("res://scripts/abilities/shield_charge_ability.gd").new() shield_ability.activate(ship) assert(ship.shields == 0.0) var previous_regeneration: float = ship.shield_regeneration ship.shield_regeneration = 10.0 ship._physics_process(0.1) assert(ship.shields == 0.0) captain.tick_skills(4.9) assert(not captain.is_skill_active("power_redirect")) assert(ship.get_evasion_chance() == 0.0) assert(captain.is_skill_active("reactor_overload")) assert(is_equal_approx(captain.energy_regeneration_multiplier(), 1.0 + CATALOG.value("reactor_overload", rank))) assert(is_equal_approx(captain.skill_cooldowns["reactor_overload"], 24.9)) ship._physics_process(0.1) assert(ship.shields > 0.0) ship.shield_regeneration = previous_regeneration ship.restore_shields_from_damage(10.0) assert(ship.shields > 0.0) captain.tick_skills(10.0) assert(not captain.is_skill_active("reactor_overload")) assert(is_equal_approx(captain.energy_regeneration_multiplier(), 1.0)) captain.tick_skills(25.0) assert(captain.skill_cooldowns["reactor_overload"] == 0.0) assert(captain.equipped_skills.size() == 5) assert(not captain.equip_skill(5, "reactor_overload")) assert(not captain.equip_skill(-1, "reactor_overload")) assert(not captain.equip_skill(3, "miner")) assert(not captain.equip_skill(3, "unknown")) captain.skill_cooldowns["reactor_overload"] = 12.0 assert(captain.equip_skill(4, "reactor_overload")) assert(captain.equipped_skills[0] == "" and captain.equipped_skills[4] == "reactor_overload") assert(captain.skill_cooldowns["reactor_overload"] == 12.0) assert(captain.equip_skill(4, "")) captain.skill_cooldowns.clear() assert(not captain.activate_skill("reactor_overload", ship)) assert(captain.equip_skill(4, "reactor_overload")) captain.emit_changed() await get_tree().process_frame await get_tree().process_frame var hotkey_ui := game.get_node("HUD/CaptainSkills") var event := InputEventKey.new() event.physical_keycode = KEY_F5 event.pressed = true hotkey_ui._unhandled_key_input(event) assert(captain.is_skill_active("reactor_overload")) assert(captain.skill_cooldowns["reactor_overload"] == 30.0) assert(hotkey_ui.get("_bar").get_child_count() == 5) captain.credits = 1000 assert(inventory.buy_ammunition()) assert(captain.credits == 976) _test_mining(game, ship) inventory.ammunition = 0 inventory.irradiated_ammunition = 0 assert(not inventory.consume_ammunition() and not inventory.consume_irradiated_ammunition()) # Level-ups wait for the captain button, then advance queued choices while paused. captain.skills.clear() captain.normalize_equipped_skills() captain.skill_cooldowns.clear() captain.skill_durations.clear() captain.add_rewards(250, 0) await get_tree().process_frame await get_tree().process_frame var ui := game.get_node("HUD/CaptainSkills") assert(not get_tree().paused and captain.learning_points == 2) assert(not ui.get("_screen").visible) var level_button := game.get_node("HUD/HUDRoot/CaptainPanel/Contents/LevelUpButton") as Button assert(level_button.visible and level_button.text == "Nowy poziom") var offers := captain.skill_offers.duplicate() level_button.pressed.emit() assert(get_tree().paused and ui.get("_screen").visible) assert(offers == captain.skill_offers and offers.size() == 3) ui._close() assert(get_tree().paused) var selected: String = offers[0] ui._choose(selected) assert(captain.get_skill_rank(selected) == 1 and get_tree().paused and captain.learning_points == 1) await get_tree().process_frame assert(ui.get("_screen").visible and captain.skill_offers.size() == 3) ui._choose(captain.skill_offers[0]) assert(not get_tree().paused and captain.learning_points == 0) await get_tree().process_frame assert(not level_button.visible and not ui.get("_screen").visible) ui.open_management() assert(get_tree().paused) captain.skill_cooldowns["reactor_overload"] = 17.0 ship.set_physics_process(true) await get_tree().create_timer(0.1, true).timeout assert(captain.skill_cooldowns["reactor_overload"] == 17.0) ship.set_physics_process(false) ui._close() var profile := GameState.captain GameState.system_level = 2 game.queue_free() await get_tree().process_frame var next_system := preload("res://scenes/game/game.tscn").instantiate() add_child(next_system) next_system.get_node("PlayerShip").set_physics_process(false) assert(GameState.captain == profile and profile.get_spent_learning_points() == 2) assert(profile.skill_cooldowns.is_empty() and profile.skill_durations.is_empty()) GameState.start_new_run() assert(GameState.captain.skills.is_empty() and GameState.captain.skill_cooldowns.is_empty()) print("CAPTAIN_SKILLS_TEST: PASS (eight skills, three ranks, five equipped slots, F5 input, slot swaps preserve cooldown, new boards reset cooldown, offers, pause, economy, ammo, mining, buffs, shield lock, new run)") get_tree().quit() func _test_offers() -> void: var profile := PROGRESS.new() profile.add_rewards(250, 0) assert(profile.level == 3 and profile.learning_points == 2) assert(profile.skill_offers.size() == 3) assert(not profile.train_skill("unknown")) var choices := profile.skill_offers.duplicate() profile.prepare_skill_offers() assert(choices == profile.skill_offers) assert(profile.train_skill(choices[0])) assert(profile.get_skill_rank(choices[0]) == 1) for skill in CATALOG.IDS: profile.skills[skill] = 3 profile.skills["miner"] = 2 profile.skill_offers.clear() profile.prepare_skill_offers() assert(profile.skill_offers == ["miner"]) assert(profile.train_skill("miner")) profile.add_rewards(1000, 0) assert(profile.skill_offers.is_empty() and profile.learning_points == 0) assert(not profile.can_reset_skills()) profile.normalize_skill_ranks() assert(profile.get_skill_rank("miner") == 3) func _test_mining(game: Node, ship: CharacterBody2D) -> void: var results: Array[int] = [] for rank in range(4): GameState.captain.skills["miner"] = rank GameState.captain.minerals = {"iron": 0, "aluminium": 0, "titanium": 0, "uranium": 0} var asteroid := StaticBody2D.new() asteroid.set_script(POI) asteroid.set("kind", "asteroid") asteroid.set("player", ship) asteroid.set("reward_seed", 123) asteroid.set("poi_id", "captain_skill_test_%d" % rank) game.add_child(asteroid) assert(asteroid.claim()) var total := 0 for amount in GameState.captain.minerals.values(): total += int(amount) results.append(total) assert(results[1] == results[0] + 3 and results[2] == results[0] + 6 and results[3] == results[0] + 10)