extends Node2D const DATA := preload("res://scripts/planets/alien_research.gd") const ENEMY := preload("res://scenes/game/enemy_ship.tscn") const PROJECTILE := preload("res://scenes/game/weapon_projectile.tscn") var player: CharacterBody2D var progress: Resource class StraightLaser extends "res://scripts/game/weapon_controller.gd": func _aim_direction_from(_origin: Vector2) -> Vector2: return Vector2.RIGHT func enemy_at(point: Vector2, hp := 1000.0, tier := 0) -> CharacterBody2D: var enemy := ENEMY.instantiate() as CharacterBody2D add_child(enemy) enemy.set_physics_process(false) enemy.position = point enemy.loot_tier = tier enemy.max_hull = hp enemy.hull = hp enemy.shields = 0.0 enemy.absorption = Vector3.ZERO enemy._player = player return enemy func _ready() -> void: GameState.start_new_run() progress = GameState.captain.expedition progress.analysis_samples = 1000 assert(DATA.purchase(progress,"general") and DATA.purchase(progress,"hull")) for side in ["a","b"]: var id: String = "hull_"+side for level in 4: assert(DATA.cost(id)==20+level*5 and DATA.purchase(progress,id)) assert(not DATA.purchase(progress,id)) id+="_next" assert(not DATA.purchase(progress,"shields_a"),"Shield category prerequisite is required") progress.alien_skills = {"hull_a":true} player = preload("res://scenes/game/player_ship.tscn").instantiate() add_child(player) player.set_physics_process(false) player.get_node("WeaponController").set_physics_process(false) var enemy := enemy_at(Vector2(5000,0)) enemy.take_research_weapon_hit(100,false,DamageTypes.Type.ENERGY,0,-1) assert(is_equal_approx(enemy.hull,895.0)) progress.alien_skills = {"hull_a_next":true} enemy.hull = 1000.0 enemy.absorption = Vector3(0,60,0) enemy.take_research_weapon_hit(100,false,DamageTypes.Type.ENERGY,0,-1) assert(enemy.hull==960.0 and enemy._hull_breach_remaining==5.0) enemy.take_research_weapon_hit(100,false,DamageTypes.Type.ENERGY,0,-1) assert(enemy.hull==890.0 and enemy._hull_breach_remaining==5.0,"Breach halves absorption without stacking") enemy._physics_process(5.1) assert(enemy._hull_breach_remaining==0.0) enemy.set_physics_process(false) progress.alien_skills = {"hull_a_next_next_next":true} var normal := enemy_at(Vector2(6000,0)) normal.configure(player,preload("res://scripts/items/alien_ship_catalog.gd").TEXTURES[0]) normal.hull = 90.0 normal.take_research_weapon_hit(10,false,DamageTypes.Type.ENERGY,0,-1) assert(normal.hull==0.0 and normal._execution_finish) var collapse_found := false for child in get_children(): if child.get_script()==preload("res://scripts/game/hull_collapse_effect.gd"): assert(child._pieces.size()==9) child._process(0.1) collapse_found = true assert(collapse_found,"Execution uses actual ship texture fragments") var boss := enemy_at(Vector2(7000,0),1000,2) boss.hull = 40.0 boss.take_research_weapon_hit(10,false,DamageTypes.Type.ENERGY,0,-1) assert(boss.hull==30.0) boss.take_research_weapon_hit(10,false,DamageTypes.Type.ENERGY,0,-1) assert(boss.hull==0.0) var shielded := enemy_at(Vector2(8000,0)) shielded.hull = 50.0 shielded.shields = 100.0 shielded.take_research_weapon_hit(10,false,DamageTypes.Type.ENERGY,0,-1) assert(shielded.hull==50.0,"A hit absorbed by shields cannot execute") progress.alien_skills = {"hull_a_next_next":true} var first := enemy_at(Vector2(100,100)) var second := enemy_at(Vector2(300,100)) var third := enemy_at(Vector2(500,100)) var shot := PROJECTILE.instantiate() shot.configure(first.position,Vector2.RIGHT,ItemDefinition.WeaponKind.PLASMA,600,100,800) add_child(shot) shot.set_physics_process(false) shot._hit_target(first) await get_tree().process_frame var continuation: Node for child in get_children(): if child.get_script()==preload("res://scripts/game/weapon_projectile.gd") and child._overpenetration_used: continuation=child assert(continuation!=null and continuation.damage==50.0) continuation.set_physics_process(false) continuation._physics_process(0.2) assert(continuation.global_position.x>150.0,"Continuation exits the pierced ship instead of getting stuck") continuation._physics_process(0.2) assert(first.hull==900.0 and second.hull==950.0 and third.hull==1000.0) assert(continuation.is_queued_for_deletion(),"A penetrating shot cannot create a third hit") first.hull = 1000.0 second.hull = 1000.0 var missile := PROJECTILE.instantiate() missile.configure(first.position,Vector2.RIGHT,ItemDefinition.WeaponKind.MISSILE,600,100,800) add_child(missile) missile.set_physics_process(false) missile._hit_target(first) await get_tree().process_frame var missile_continuation: Node for child in get_children(): if child.get_script()==preload("res://scripts/game/weapon_projectile.gd") and child._overpenetration_used and child.weapon_kind==ItemDefinition.WeaponKind.MISSILE: missile_continuation=child assert(missile_continuation!=null) missile_continuation.set_physics_process(false) missile_continuation._physics_process(0.2) missile_continuation._physics_process(0.2) assert(first.hull==900.0 and second.hull==950.0 and third.hull==1000.0,"Missile continuation deals half damage to one additional target") first.position = Vector2(160,-28) second.position = Vector2(300,-28) third.position = Vector2(450,-28) first.hull = 1000.0 second.hull = 1000.0 var laser := StraightLaser.new() player.add_child(laser) laser.set_physics_process(false) var laser_item := ItemInstance.new() laser_item.definition = preload("res://resources/items/beam_laser.tres") laser_item.damage_min = 100.0 laser_item.damage_max = 100.0 player.energy = 1000.0 await get_tree().physics_frame await get_tree().physics_frame laser._fire_laser(0,laser_item) assert(first.hull==900.0 and second.hull==950.0 and third.hull==1000.0,"Laser penetrates precisely one additional target") assert(laser._laser_lines[0].get_point_count()==3) laser.queue_free() progress.alien_skills = {"hull_b":true} var inventory: ShipInventory = player.get_node("ShipInventory") player.hull = 50.0 inventory._recalculate_ship_stats() assert(is_equal_approx(player.max_hull,player.base_max_hull*1.1) and player.hull==50.0) progress.alien_skills = {"hull_b_next":true} player.max_hull = 100.0 player.hull = 100.0 player.shields = 5.0 player.absorption = Vector3.ZERO player.take_damage(25.0) assert(player.hull==94.0 and player._reactive_armor_cooldown==15.0) player.take_damage(10.0) assert(player.hull==84.0) player.tick_hull_technologies(15.0) player.take_damage(10.0) assert(player.hull==81.0) progress.alien_skills = {"hull_b_next_next":true} player.hull = 40.0 player.shields = 0.0 player.take_damage(20.0) assert(player.hull==20.0 and player._bulkhead_cooldown==45.0) player.tick_hull_technologies(2.0) assert(player.hull==26.0) player.take_damage(1.0) player.tick_hull_technologies(3.0) assert(player.hull==34.0,"Hits do not interrupt five-second repair") player.take_damage(10.0) assert(player._bulkhead_repair_remaining==0.0,"Repair cannot retrigger during cooldown") progress.alien_skills = {"hull_b_next_next_next":true} player.hull = 10.0 player.take_damage(1000.0) assert(player.hull==1.0 and not player._is_destroyed and GameState.hull_bastion_used) player.take_damage(1000.0) assert(player.hull==1.0) player.is_docked = true player.tick_hull_technologies(10.0) assert(GameState.hull_bastion_used and player._bastion_invulnerability==2.0,"Docking does not renew Last Bastion") player.is_docked = false player.tick_hull_technologies(2.1) player.take_damage(1000.0) assert(player._is_destroyed,"Last Bastion works only once") GameState.system_level = 7 GameState.system_seed = 777 progress.distant_maps["hull_test"] = {"id":"hull_test","level":125,"seed":123} progress.deuter = 125000 assert(GameState.depart_distant("hull_test") and not GameState.hull_bastion_used) GameState.hull_bastion_used = true GameState.restore_distant_home() assert(GameState.hull_bastion_used and GameState.system_level==7,"Return preserves the home's used rescue") print("ALIEN_HULL_TECHNOLOGIES_TEST: PASS (8 technologies, costs, breach, execution thresholds, penetration, reactive armor, uninterrupted repair, persistent one-use rescue)")