Randoloot/tests/ships/alien_hull_technologies_test.gd
2026-10-25 16:12:08 +01:00

185 lines
8.0 KiB
GDScript

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)")