Tune and optimize boss encounter
This commit is contained in:
parent
40f284dcdd
commit
68985316e5
16 changed files with 316 additions and 88 deletions
|
|
@ -35,15 +35,18 @@ func _process(_delta: float) -> void:
|
|||
var boss: Node2D = encounter.get_node("Boss")
|
||||
boss.wave_timer = 999.0
|
||||
boss.laser_timer = 999.0
|
||||
boss.phase = boss.Phase.LASER_STORM
|
||||
for i in range(3):
|
||||
boss.eyes[i].open_eye()
|
||||
boss.eyes_opened += 1
|
||||
boss.eyes[i].take_damage(999)
|
||||
# Show one of the remaining weak points in its attackable state while the
|
||||
# aggregate bar truthfully sits at half health.
|
||||
boss.open_next_eye()
|
||||
boss.spawn_wave()
|
||||
for minion in get_tree().get_nodes_in_group("boss_minions"):
|
||||
minion.speed = 0.0
|
||||
minion.acceleration = 0.0
|
||||
boss.laser_charge_time = 999.0
|
||||
boss.fire_laser_volley()
|
||||
encounter._process(0.0)
|
||||
encounter._refresh_status()
|
||||
get_tree().paused = true
|
||||
|
|
|
|||
|
|
@ -61,6 +61,15 @@ func _process(delta: float) -> bool:
|
|||
var profile: Resource = surface_profiles.get_profile("boss")
|
||||
if profile == null or profile.encounter_scene == null:
|
||||
return _fail("boss surface has no scripted encounter")
|
||||
if profile.background_field_texture == null \
|
||||
or not String(profile.background_shader.resource_path).ends_with(
|
||||
"lunar_tiled.gdshader"):
|
||||
return _fail("boss backdrop still performs procedural rendering during combat")
|
||||
var composed_background: ShaderMaterial = surface.get_node(
|
||||
"BackgroundLayer/Background").material
|
||||
if composed_background.get_shader_parameter("field_texture") \
|
||||
!= profile.background_field_texture:
|
||||
return _fail("boss backdrop did not bind its ready-made field texture")
|
||||
if profile.editor_visible or "boss" in surface_profiles.editor_profile_ids():
|
||||
return _fail("boss surface is configurable in the map editor")
|
||||
state.dev_mode = true
|
||||
|
|
@ -103,6 +112,10 @@ func _process(delta: float) -> bool:
|
|||
boss = encounter.get_node("Boss")
|
||||
boss.wave_timer = 999.0
|
||||
boss.laser_timer = 999.0
|
||||
var health_bar: ProgressBar = encounter.get_node("EncounterUI/HealthBar")
|
||||
if health_bar.max_value != boss.max_health() \
|
||||
or health_bar.value != boss.current_health():
|
||||
return _fail("aggregate boss health bar did not start full")
|
||||
if boss.eyes.size() != boss.EYE_COUNT:
|
||||
return _fail("boss has %d tentacle eyes, expected %d" \
|
||||
% [boss.eyes.size(), boss.EYE_COUNT])
|
||||
|
|
@ -126,6 +139,11 @@ func _process(delta: float) -> bool:
|
|||
minion.take_damage(999)
|
||||
if marked == null:
|
||||
return _fail("phase-one wave has no marked hatchling")
|
||||
if marked.max_hp < 5:
|
||||
return _fail("boss hatchlings still have only %d health" % marked.max_hp)
|
||||
marked.take_damage(1)
|
||||
if not is_instance_valid(marked) or marked.hp != marked.max_hp - 1:
|
||||
return _fail("a hatchling did not survive a normal weapon hit")
|
||||
if not get_nodes_in_group("boss_returns").is_empty():
|
||||
return _fail("an ordinary hatchling returned energy to the boss")
|
||||
marked.take_damage(999)
|
||||
|
|
@ -156,6 +174,9 @@ func _process(delta: float) -> bool:
|
|||
eye.take_damage(1)
|
||||
if eye.hp != hp_before - 1:
|
||||
return _fail("an open eye ignored weapon damage")
|
||||
if encounter.health_bar.value != boss.current_health() \
|
||||
or encounter.health_bar.value >= encounter.health_bar.max_value:
|
||||
return _fail("total boss health bar ignored eye damage")
|
||||
eye.take_damage(999)
|
||||
if boss.eyes_destroyed != 1:
|
||||
return _fail("destroying the first eye did not damage the boss")
|
||||
|
|
@ -188,12 +209,19 @@ func _process(delta: float) -> bool:
|
|||
var beams: Array = get_nodes_in_group("boss_lasers")
|
||||
if beams.size() != 3:
|
||||
return _fail("laser phase launched %d beams, expected three lanes" % beams.size())
|
||||
if boss.laser_interval >= 5.5 or boss.laser_charge_time >= 1.6:
|
||||
return _fail("boss lasers retained their old slow cadence")
|
||||
if beams[0].aim_direction.is_equal_approx(beams[1].aim_direction) \
|
||||
or beams[1].aim_direction.is_equal_approx(beams[2].aim_direction):
|
||||
return _fail("laser volley lanes all aim in the same direction")
|
||||
for beam in beams:
|
||||
if beam.phase != 0 or beam.charge_left <= 0.0:
|
||||
return _fail("boss laser was not telegraphed before firing")
|
||||
if not beam.infinite_range or not beam.reaches_point(
|
||||
beam.origin + beam.aim_direction * 1000000.0):
|
||||
return _fail("boss laser ray stops at a finite range")
|
||||
if beam.reaches_point(beam.origin - beam.aim_direction * 10.0):
|
||||
return _fail("boss laser extends backwards through its source")
|
||||
beam.queue_free()
|
||||
boss.spawn_wave()
|
||||
var phase_two_minions: Array = get_nodes_in_group("boss_minions")
|
||||
|
|
@ -204,6 +232,14 @@ func _process(delta: float) -> bool:
|
|||
minion.retire()
|
||||
if phase_two_minions.size() != 3 or phase_two_marked != 1:
|
||||
return _fail("laser phase no longer supplies one marked target to open remaining eyes")
|
||||
boss.spawn_wave()
|
||||
boss.spawn_wave()
|
||||
boss.spawn_wave()
|
||||
if boss.spawned_minions.size() > boss.MAX_ACTIVE_MINIONS:
|
||||
return _fail("boss waves can accumulate without a rendering/gameplay cap")
|
||||
for minion in boss.spawned_minions.duplicate():
|
||||
if is_instance_valid(minion):
|
||||
minion.retire()
|
||||
print("three broken eyes started a telegraphed three-lane laser phase")
|
||||
|
||||
# --- F. all eyes -> persistent victory ------------------------
|
||||
|
|
@ -214,6 +250,9 @@ func _process(delta: float) -> bool:
|
|||
return _fail("breaking every eye did not defeat and hide the boss")
|
||||
if not state.is_planet_conquered(state.planet_id):
|
||||
return _fail("boss victory did not persist through planet conquest state")
|
||||
if encounter.health_bar.value != 0 \
|
||||
or encounter.health_bar.max_value != boss.max_health():
|
||||
return _fail("boss health bar did not end empty with a stable total")
|
||||
print("all eyes broken: boss defeated and planet conquest persisted")
|
||||
|
||||
surface.free()
|
||||
|
|
|
|||
Loading…
Reference in a new issue