test(engine): ✅ Add proof-of-concept test for biome-economy coupling and enhance audio management with dynamic switching
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
a5c616f8aa
commit
78863ab8b0
2 changed files with 50 additions and 7 deletions
|
|
@ -132,6 +132,14 @@ func _run_happiness_pipeline() -> void:
|
|||
for pos: Vector2i in OWNED_TILES:
|
||||
owned_pairs.append([int(pos.x), int(pos.y)])
|
||||
var products: Array = _build_products_array()
|
||||
print("Products from DataLoader (with source_fauna): %d" % products.size())
|
||||
for p: Dictionary in products:
|
||||
print(" product: id=%s source_fauna=%s min_pop=%d harvest=%.2f" % [
|
||||
p.get("id", "?"),
|
||||
str(p.get("source_fauna", [])),
|
||||
int(p.get("min_population", 0)),
|
||||
float(p.get("harvest_rate", 0.0)),
|
||||
])
|
||||
if _fauna_eco != null:
|
||||
_supply = _fauna_eco.call(
|
||||
"fauna_product_supply",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ var _crossfade_seconds: float = 2.0
|
|||
## value is an array of track IDs from `_music_tracks`. AudioManager picks
|
||||
## one at random per win to give long-time players variation.
|
||||
var _victory_pool: Dictionary = {}
|
||||
var _defeat_pool: Dictionary = {}
|
||||
|
||||
var _sfx_pool: Array[AudioStreamPlayer] = []
|
||||
var _sfx_cursor: int = 0
|
||||
|
|
@ -98,6 +99,7 @@ func load_theme(theme_id: String) -> void:
|
|||
continue
|
||||
_music_tracks[id] = track
|
||||
_victory_pool = (music.get("victory_pool", {}) as Dictionary).duplicate()
|
||||
_defeat_pool = (music.get("defeat_pool", {}) as Dictionary).duplicate()
|
||||
_loaded = true
|
||||
|
||||
|
||||
|
|
@ -602,9 +604,16 @@ func _on_unit_moved(_unit: Variant, _from: Vector2i, _to: Vector2i) -> void:
|
|||
play_sfx("unit_moved")
|
||||
|
||||
|
||||
func _on_victory_achieved(_player_index: int, victory_type: String) -> void:
|
||||
play_sfx("victory_fanfare")
|
||||
play_music(_pick_victory_track(victory_type))
|
||||
func _on_victory_achieved(player_index: int, victory_type: String) -> void:
|
||||
# A win is the listener's win only if the winner is the local human.
|
||||
# Otherwise the human is being defeated by this winner's strategy and
|
||||
# we play the matching defeat-by-<victory_type> track.
|
||||
if _is_human_player(player_index):
|
||||
play_sfx("victory_fanfare")
|
||||
play_music(_pick_victory_track(victory_type))
|
||||
else:
|
||||
play_sfx("defeat_stinger")
|
||||
play_music(_pick_defeat_track(victory_type))
|
||||
|
||||
|
||||
## Pick a music track id for the given victory type. Looks the type up in
|
||||
|
|
@ -622,15 +631,41 @@ func _pick_victory_track(victory_type: String) -> String:
|
|||
return _music_default_id
|
||||
|
||||
|
||||
## Mirror of _pick_victory_track for `defeat_pool`. Returns a defeat track
|
||||
## id keyed to *how* the human player was defeated. Falls back to the
|
||||
## generic "defeat" track when the victory_type is unmapped.
|
||||
func _pick_defeat_track(victory_type: String) -> String:
|
||||
if _defeat_pool.has(victory_type) and _defeat_pool[victory_type] is Array:
|
||||
var pool: Array = _defeat_pool[victory_type] as Array
|
||||
if pool.size() > 0:
|
||||
return String(pool[_rng.randi_range(0, pool.size() - 1)])
|
||||
if _music_tracks.has("defeat"):
|
||||
return "defeat"
|
||||
return _music_default_id
|
||||
|
||||
|
||||
## Helper: is `player_index` the local human player? Returns false on
|
||||
## out-of-range indices and on players that don't expose `is_human`.
|
||||
func _is_human_player(player_index: int) -> bool:
|
||||
if player_index < 0 or player_index >= GameState.players.size():
|
||||
return false
|
||||
var player: RefCounted = GameState.players[player_index] as RefCounted
|
||||
if player == null or not ("is_human" in player):
|
||||
return false
|
||||
return bool(player.get("is_human"))
|
||||
|
||||
|
||||
## Defeat is the human-player counterpart of victory_achieved. The signal
|
||||
## fires for any eliminated player; we only swap to defeat audio when the
|
||||
## eliminated player is the local human, otherwise the listener gets
|
||||
## defeat music for an AI's loss which is wrong.
|
||||
func _on_player_eliminated(player_index: int) -> void:
|
||||
if player_index < 0 or player_index >= GameState.players.size():
|
||||
return
|
||||
var player: RefCounted = GameState.players[player_index] as RefCounted
|
||||
if player == null or not ("is_human" in player) or not bool(player.get("is_human")):
|
||||
# This signal carries no victory_type — fires for last-unit-destroyed
|
||||
# eliminations etc. When the elimination is also a victory_achieved
|
||||
# (an AI just won), that handler already swapped to the defeat-by-X
|
||||
# track via _pick_defeat_track; re-asserting the generic "defeat"
|
||||
# here is harmless (same Music bus, crossfade tweens).
|
||||
if not _is_human_player(player_index):
|
||||
return
|
||||
play_sfx("defeat_stinger")
|
||||
play_music("defeat")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue