Release Void Bastion alpha.5
This commit is contained in:
1 parent
118061b8d7
commit
56077e88a5
18 files changed
+488
-40
No files matched your search
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user