extends Node2D const DATA := preload("res://scripts/planets/alien_research.gd") const ENEMY := preload("res://scenes/game/enemy_ship.tscn") var player: CharacterBody2D var progress: Resource class StraightAlien extends "res://scripts/game/enemy_ship.gd": func _laser_aim_direction(direction: Vector2) -> Vector2: return direction func enemy_at(point: Vector2) -> CharacterBody2D: var enemy := ENEMY.instantiate() as CharacterBody2D enemy.set_script(StraightAlien) add_child(enemy) enemy.set_physics_process(false) enemy.position = point enemy.max_hull = 10000.0 enemy.hull = 10000.0 enemy.max_shields = 1000.0 enemy.shields = 1000.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,"shields")) for side in ["a","b"]: var id: String = "shields_"+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(DATA.ACTIVE_IDS.size()==28) player = preload("res://scenes/game/player_ship.tscn").instantiate() add_child(player) player.set_physics_process(false) var weapon := player.get_node("WeaponController") weapon.set_physics_process(false) var enemy := enemy_at(Vector2(1000,0)) var nearby := enemy_at(Vector2(1100,0)) var chain := enemy_at(Vector2(1200,0)) progress.alien_skills = {"shields":true,"shields_a":true} enemy.take_research_weapon_hit(100,false,DamageTypes.Type.ENERGY,0,-1) assert(is_equal_approx(enemy.shields,885.0),"Shield bonuses add to 15 percent") progress.alien_skills = {"shields_a_next":true} enemy.shields = 500 enemy.take_research_weapon_hit(10,false,DamageTypes.Type.ENERGY,0,-1) assert(enemy._shield_regen_lock==5.0) enemy.regenerate_defenses(1.0) assert(enemy.shields==490.0) enemy.tick_shield_technologies(3.0) enemy.take_research_weapon_hit(10,false,DamageTypes.Type.ENERGY,0,-1) assert(enemy._shield_regen_lock==5.0) enemy.tick_shield_technologies(5.1) enemy.regenerate_defenses(1.0) assert(enemy.shields==490.0) progress.alien_skills = {"shields_a_next_next":true} enemy.shields = 50 nearby.shields = 50 enemy.take_research_weapon_hit(100,false,DamageTypes.Type.ENERGY,0,-1) assert(nearby.shields==0 and nearby.hull==9650,"Overload deals 400 percent, including spill") assert(chain.shields==1000,"Overload cannot trigger a chain") assert(enemy._shield_overload_cooldown==10) enemy.shields = 1 enemy.take_research_weapon_hit(100,false,DamageTypes.Type.ENERGY,0,-1) assert(nearby.hull==9650,"Regrown shield cannot spam overload") enemy.tick_shield_technologies(10.1) enemy.shields = 1 enemy.take_research_weapon_hit(100,false,DamageTypes.Type.ENERGY,0,-1) assert(nearby.hull==9250) progress.alien_skills = {"shields_b":true} player.shields = 20 player.apply_equipment_bonuses({}) assert(is_equal_approx(player.max_shields,player.base_max_shields*1.1) and player.shields==20) player.max_shields = 100 player.max_hull = 1000 player.hull = 1000 player.absorption = Vector3.ZERO progress.alien_skills = {"shields_b_next":true} player.shields = 40 player.take_damage(20) assert(player._shield_reserve_remaining==2 and player._shield_reserve_cooldown==15) player.energy = 5 assert(weapon._consume_energy(10) and player.energy==0,"Reduced cost is applied once") player.tick_hull_technologies(2.1) player.energy = 5 assert(not weapon._consume_energy(10),"Normal cost after reserve expires") player.shields = 40 player.take_damage(20) assert(player._shield_reserve_remaining==0,"Reserve cooldown prevents retrigger") progress.alien_skills = {"shields_b_next_next":true} player.shields = 100 player.take_damage(100) assert(player.shields==90 and player._salvo_cooldown==60) player.take_damage(20) assert(player.shields==70,"Only first hit is reduced") player.is_docked = true player.tick_hull_technologies(60) assert(player._salvo_cooldown==60,"Docking does not refresh cooldown") player.is_docked = false player.tick_hull_technologies(60) player.shields = 5 player.take_damage(100) assert(player.shields==0 and player.hull==995,"First-hit reduction also covers spill") progress.alien_skills = {"shields_b_next_next_next":true} player.hull = 1000 player.shields = 10 player.take_damage(20) assert(player.shields==25 and player.hull==990 and player._emergency_shield_cooldown==30) player.take_damage(20) assert(player.shields==15,"Emergency shield halves following hits") progress.alien_skills["shields_b_next_next"] = true player._salvo_cooldown = 0 player.take_damage(100) assert(player.shields==5,"Stronger protection applies without multiplying reductions") player.tick_hull_technologies(2.1) player.take_damage(10) assert(player.shields==0 and player.hull==985,"Emergency shield cannot retrigger during cooldown") progress.alien_skills = {"shields_a_next_next_next":true} player.shields = 100 enemy.shields = 100 player.take_enemy_weapon_hit(50,false,DamageTypes.Type.ENERGY,enemy) assert(player.shields==50 and enemy.shields==90,"Reflection uses absorbed damage and actual shooter") player.shields = 5 player.take_enemy_weapon_hit(50,false,DamageTypes.Type.ENERGY,enemy) assert(enemy.shields==89,"Hull damage is not reflected") player.take_enemy_weapon_hit(10,false,DamageTypes.Type.ENERGY,enemy) assert(enemy.shields==89,"No reflection without shields") player.shields = 100 enemy.virus_controlled = true player.take_enemy_weapon_hit(10,false,DamageTypes.Type.ENERGY,enemy) assert(enemy.shields==89,"Friendly controlled aliens do not receive reflection") enemy.virus_controlled = false player.shields = 100 var projectile := preload("res://scenes/game/weapon_projectile.tscn").instantiate() projectile.enemy_shot = true projectile.source_ship = enemy projectile.damage = 20 add_child(projectile) projectile.set_physics_process(false) projectile._apply_damage_once(player) assert(player.shields==80 and is_equal_approx(enemy.shields,85),"Enemy projectile retains its shooter for reflection") projectile.queue_free() var shooter := enemy_at(Vector2(0,-180)) shooter.weapon_kind = ItemDefinition.WeaponKind.LASER shooter.weapon_damage = 20 shooter.weapon_range = 500 shooter._combat_target = player player.shields = 100 await get_tree().physics_frame await get_tree().physics_frame var laser_damage: float = shooter.get_shot_damage() shooter._fire_plasma(Vector2.DOWN) assert(is_equal_approx(player.shields,100-laser_damage),"Actual laser hits the player") assert(is_equal_approx(shooter.shields,1000-laser_damage*0.2),"Actual laser reflection returns to the shooter") var orphan := preload("res://scenes/game/weapon_projectile.tscn").instantiate() orphan.enemy_shot = true orphan.source_ship = enemy orphan.configure(Vector2(3000,3000),Vector2.RIGHT,ItemDefinition.WeaponKind.PLASMA,600,10,1000) add_child(orphan) orphan.set_physics_process(false) enemy.free() player.shields = 100 orphan._physics_process(0.01) orphan._hit_target(player) assert(player.shields==90,"Projectile still hits safely after shooter is freed; no reflection to invalid source") print("ALIEN_SHIELD_TECHNOLOGIES_TEST: PASS (8 skills, costs, 400% overload without chains, regen lock, energy reserve, 10% first hit/60s, emergency shield, reflection)")