Release Void Bastion alpha.5

This commit is contained in:
Emporex committed 2026-10-06 18:34:49 +02:00
1 parent 118061b8d7
commit 56077e88a5
18 files changed
+488 -40

No files matched your search

+58 -23
View File
@@ -14,6 +14,9 @@ const PLASMA_TEXTURE := preload("res://assets/tower_plasma.png")
const EMP_TEXTURE := preload("res://assets/tower_emp.png")
const RAILGUN_TEXTURE := preload("res://assets/tower_railgun.png")
const ENEMY_TEXTURE := preload("res://assets/enemy_ships.png")
const ENEMY_INTERCEPTOR_TEXTURE := preload("res://assets/enemy_interceptor.png")
const ENEMY_SHIELD_CARRIER_TEXTURE := preload("res://assets/enemy_shield_carrier.png")
const ENEMY_SIEGE_DESTROYER_TEXTURE := preload("res://assets/enemy_siege_destroyer.png")
const ROAD_STRAIGHT_TEXTURE := preload("res://assets/road_straight.svg")
const ROAD_CORNER_TEXTURE := preload("res://assets/road_corner.svg")
const ROAD_SURFACE_TEXTURE := preload("res://assets/road_surface_material_v1.png")
@@ -69,12 +72,12 @@ const COOP_REACTOR_RADIUS := 112.0
const DIFFICULTY_DATA := [
{"name": "LEICHT", "hp": 1.0, "speed": 1.0, "count": 1.0, "income": 1.0, "spawn_delay": 1.0, "start_credits": 450, "lives": 20, "crystals": 5},
{"name": "MITTEL", "hp": 1.32, "speed": 1.07, "count": 1.24, "income": 0.94, "spawn_delay": 0.91, "start_credits": 430, "lives": 17, "crystals": 7},
{"name": "SCHWER", "hp": 1.72, "speed": 1.15, "count": 1.48, "income": 0.84, "spawn_delay": 0.82, "start_credits": 400, "lives": 14, "crystals": 10}
{"name": "SCHWER", "hp": 1.72, "speed": 1.15, "count": 1.48, "income": 0.78, "spawn_delay": 0.82, "start_credits": 340, "lives": 12, "crystals": 12}
]
const DIFFICULTY_DESCRIPTIONS := [
"Bisheriges Balancing • 20 Reaktor • Kartenbonus 5",
"+32 % Gegnerhülle • +24 % Gegner • Kartenbonus 7",
"+72 % Gegnerhülle • +48 % Gegner • Kartenbonus 10"
"+72 % Grundhülle • stärkere Spätwellen • Start 340 • Kartenbonus 12"
]
const TOWER_DATA := [
@@ -87,9 +90,12 @@ const TOWER_DATA := [
]
const ENEMY_DATA := [
{"name": "JAEGER", "hp": 70.0, "speed": 105.0, "reward": 18, "size": 58.0},
{"name": "FREGATTE", "hp": 185.0, "speed": 72.0, "reward": 34, "size": 78.0},
{"name": "KREUZER", "hp": 520.0, "speed": 43.0, "reward": 78, "size": 112.0}
{"name": "JAEGER", "hp": 70.0, "speed": 105.0, "reward": 18, "size": 58.0, "breach_damage": 1, "shield_resistance": 0.28},
{"name": "FREGATTE", "hp": 185.0, "speed": 72.0, "reward": 34, "size": 78.0, "breach_damage": 2, "shield_resistance": 0.28},
{"name": "KREUZER", "hp": 520.0, "speed": 43.0, "reward": 78, "size": 112.0, "breach_damage": 3, "shield_resistance": 0.28},
{"name": "ABFANGJAEGER", "hp": 52.0, "speed": 178.0, "reward": 22, "size": 48.0, "breach_damage": 2, "shield_resistance": 0.28},
{"name": "SCHILDKREUZER", "hp": 260.0, "speed": 58.0, "reward": 52, "size": 92.0, "breach_damage": 2, "shield_resistance": 0.18, "default_shield": true},
{"name": "BELAGERER", "hp": 740.0, "speed": 48.0, "reward": 108, "size": 128.0, "breach_damage": 4, "shield_resistance": 0.28}
]
var path_points := PackedVector2Array()
@@ -241,9 +247,13 @@ func _ready() -> void:
_select_map(selected_map)
_load_progress()
_load_audio_settings()
music_player.stream = _build_ambient_stream()
music_player.play()
ui_sound_player.stream = _build_ui_click_stream()
# The Android AudioTrack backend currently crashes on this generated PCM stream
# on the supported emulator/device test target. Keep the game playable there
# without starting native audio until we replace it with a packaged audio asset.
if not OS.has_feature("android"):
music_player.stream = _build_ambient_stream()
music_player.play()
ui_sound_player.stream = _build_ui_click_stream()
ads_manager.energy_reward_granted.connect(_on_energy_reward_granted)
ads_manager.ad_unavailable.connect(_show_status)
ads_manager.victory_interstitial_finished.connect(_on_victory_interstitial_finished)
@@ -304,15 +314,8 @@ func _update_wave(delta: float) -> void:
func _spawn_enemy() -> void:
var type := 0
var is_boss := wave > 0 and wave % BOSS_WAVE_INTERVAL == 0 and enemies_to_spawn <= (2 if coop_mode else 1)
var roll := randf()
if is_boss:
type = 2
elif wave >= 7 and roll > 0.82:
type = 2
elif wave >= 3 and roll > 0.53:
type = 1
var type := _enemy_type_for_wave(wave, randf(), is_boss)
var data: Dictionary = ENEMY_DATA[type]
var health_scale := _enemy_health_scale(wave, is_boss)
var route_id := 0
@@ -335,18 +338,37 @@ func _spawn_enemy() -> void:
"flash": 0.0,
"boss": is_boss,
"size_scale": 1.34 if is_boss else 1.0,
"shield": wave >= 4 and randf() < minf(0.42, 0.10 + wave * 0.018 + selected_difficulty * 0.06)
"shield": bool(data.get("default_shield", false)) or (wave >= 4 and randf() < minf(0.42, 0.10 + wave * 0.018 + selected_difficulty * 0.06)),
"shield_resistance": float(data.shield_resistance)
})
if is_boss:
_show_status("WARNUNG: KOMMANDOSCHIFF IM ANFLUG")
next_enemy_id += 1
func _enemy_type_for_wave(for_wave: int, roll: float, is_boss: bool) -> int:
if is_boss:
return 5
var advanced_offset := 2 if selected_difficulty == 2 else (1 if selected_difficulty == 1 else 0)
if for_wave >= 10 - advanced_offset and roll >= 0.94:
return 5
if for_wave >= 7 - advanced_offset and roll >= 0.80:
return 4
if for_wave >= 4 - advanced_offset and roll >= 0.65:
return 3
if for_wave >= 7 and roll >= 0.45:
return 2
if for_wave >= 3 and roll >= 0.28:
return 1
return 0
func _enemy_health_scale(for_wave: int, is_boss: bool) -> float:
var early_ramp := maxf(0.0, for_wave - 1.0) * 0.20
var post_four_ramp := maxf(0.0, for_wave - 3.0) * 0.09
var hard_late_ramp := maxf(0.0, for_wave - 5.0) * 0.055 if selected_difficulty == 2 else 0.0
var endless_ramp := maxf(0.0, for_wave - MAX_WAVES) * 0.035 if endless_mode else 0.0
return (1.0 + early_ramp + post_four_ramp + endless_ramp) * (3.25 if is_boss else 1.0) * float(_difficulty().hp)
return (1.0 + early_ramp + post_four_ramp + hard_late_ramp + endless_ramp) * (3.25 if is_boss else 1.0) * float(_difficulty().hp)
func _update_enemies(delta: float) -> void:
@@ -362,7 +384,8 @@ func _update_enemies(delta: float) -> void:
enemy.path_index += 1
if enemy.path_index >= route.size():
enemies.erase(enemy)
reactor_lives -= 1 + enemy.type + (4 if enemy.boss else 0)
var enemy_data: Dictionary = ENEMY_DATA[int(enemy.type)]
reactor_lives -= int(enemy_data.breach_damage) + (4 if enemy.boss else 0)
if coop_mode:
multiplayer_manager.shared_reactor_lives = maxi(0, reactor_lives)
_spawn_burst(route[-1], Color("54dfff"), 16)
@@ -442,7 +465,7 @@ func _apply_damage(enemy: Dictionary, amount: float, owner := 0, weapon_type :=
return
var applied_damage := amount
if bool(enemy.get("shield", false)) and weapon_type not in [1, 5]:
applied_damage *= 0.28
applied_damage *= float(enemy.get("shield_resistance", 0.28))
enemy.hp -= applied_damage
enemy.flash = 0.06
if enemy.hp <= 0.0:
@@ -1142,6 +1165,8 @@ func _start_wave() -> void:
return
wave += 1
var wave_population_scale := 1.0 + maxf(0.0, wave - 3.0) * 0.08
if selected_difficulty == 2:
wave_population_scale += maxf(0.0, wave - 4.0) * 0.025
if endless_mode:
wave_population_scale += maxf(0.0, wave - MAX_WAVES) * 0.035
enemies_to_spawn = ceili((7 + wave * 2) * float(_difficulty().count) * wave_population_scale) * (2 if coop_mode else 1)
@@ -2019,15 +2044,25 @@ func _draw_tower(tower: Dictionary) -> void:
func _draw_enemy(enemy: Dictionary) -> void:
var source_width: float = ENEMY_TEXTURE.get_width() / 3.0
var source := Rect2(source_width * enemy.type, 0, source_width, ENEMY_TEXTURE.get_height())
var enemy_type := int(enemy.type)
var enemy_texture: Texture2D = ENEMY_TEXTURE
var source: Rect2
var destination: Rect2
var size: float = ENEMY_DATA[enemy.type].size * enemy.size_scale
if enemy_type < 3:
var source_width: float = ENEMY_TEXTURE.get_width() / 3.0
source = Rect2(source_width * enemy_type, 0, source_width, ENEMY_TEXTURE.get_height())
destination = Rect2(-size * 0.5, -size * 0.5, size, size)
else:
enemy_texture = [ENEMY_INTERCEPTOR_TEXTURE, ENEMY_SHIELD_CARRIER_TEXTURE, ENEMY_SIEGE_DESTROYER_TEXTURE][enemy_type - 3]
source = Rect2(Vector2.ZERO, enemy_texture.get_size())
destination = Rect2(-size * 0.75, -size * 0.5, size * 1.5, size)
var tint := Color.WHITE if enemy.flash <= 0.0 else Color("ffb6a3")
if bool(enemy.get("shield", false)):
draw_circle(enemy.pos, size * 0.63, Color(0.25, 0.80, 1.0, 0.12))
draw_arc(enemy.pos, size * 0.63, 0.0, TAU, 28, Color(0.38, 0.86, 1.0, 0.76), 2.2)
draw_set_transform(enemy.pos - camera_offset, enemy.angle, Vector2.ONE)
draw_texture_rect_region(ENEMY_TEXTURE, Rect2(-size * 0.5, -size * 0.5, size, size), source, tint)
draw_texture_rect_region(enemy_texture, destination, source, tint)
draw_set_transform(-camera_offset, 0.0, Vector2.ONE)
var bar_width := size * 0.72
var ratio: float = clampf(enemy.hp / enemy.max_hp, 0.0, 1.0)