156 lines
6.2 KiB
Python
156 lines
6.2 KiB
Python
#!/usr/bin/env python3
|
|
"""M76-C wiring pass: connect the runtime audio service to the entry shell.
|
|
|
|
Adds (once, idempotently):
|
|
* service creation + helpers in `_ready`/`_apply_runtime_settings`;
|
|
* a `_audio_enter(page, family)` call as the first statement of each page
|
|
`show_*` function (page_open cue + music family switch);
|
|
* a `_audio_sfx("<event>")` call at the first statement of each semantic
|
|
player-commit action function.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
SHELL = ROOT / "runtime/entry/entry_shell.gd"
|
|
|
|
PAGES: dict[str, tuple[str, str]] = {
|
|
"show_boot_diagnostics": ("boot", "title"),
|
|
"show_first_launch": ("setup", "title"),
|
|
"show_title": ("title", "title"),
|
|
"show_initial_company": ("initial_company", "title"),
|
|
"show_guild_handoff": ("guild_handoff", "guild"),
|
|
"show_guild_anchor": ("guild", "guild"),
|
|
"show_roster": ("roster", "guild"),
|
|
"show_recruit_detail": ("recruit_detail", "guild"),
|
|
"show_contract_choice": ("contract_choice", "prep"),
|
|
"show_market_handoff": ("market_handoff", "market"),
|
|
"show_market": ("market", "market"),
|
|
"show_recruit_review": ("recruit_review", "market"),
|
|
"show_equipment_review": ("equipment_review", "market"),
|
|
"show_party_line": ("party_line", "prep"),
|
|
"show_readiness_review": ("readiness_review", "prep"),
|
|
"show_risk_board": ("risk_board", "run"),
|
|
"show_risk_commitment": ("risk_commitment", "run"),
|
|
"show_battle_opening": ("battle_opening", "run"),
|
|
"show_battle": ("battle", "run"),
|
|
"show_battle_result": ("battle_result", ""),
|
|
"show_battle_knockout_review": ("battle_knockout_review", "result_loss"),
|
|
"show_battle_reward_choice": ("battle_reward_choice", "result_win"),
|
|
"show_battle_recovery": ("battle_recovery", "result_loss"),
|
|
"show_settings_from_guild": ("settings", ""),
|
|
"show_settings_placeholder": ("settings", ""),
|
|
"show_settings": ("settings", ""),
|
|
"show_credits": ("credits", ""),
|
|
"show_unavailable_reason": ("unavailable", ""),
|
|
}
|
|
|
|
ACTIONS: dict[str, str] = {
|
|
"commit_dismissal": "dismiss_commit",
|
|
"commit_contract_return": "run_end_voluntary",
|
|
"confirm_contract_choice": "confirm_commit",
|
|
"save_party_order": "reorder_commit",
|
|
"reset_party_order": "reorder_cancel",
|
|
"select_party_member": "unit_select",
|
|
"select_contract_difficulty": "difficulty_change_review",
|
|
"accept_readiness": "ready_check_pass",
|
|
"select_risk_option": "risk_option_focus",
|
|
"toggle_risk_commitment_confirmation": "confirm_arm",
|
|
"begin_battle": "battle_start_commit",
|
|
"commit_battle_reward": "reward_accept",
|
|
"commit_battle_recovery": "recovery_option_open",
|
|
"purchase_selected_equipment": "equip_commit",
|
|
"hire_selected_recruit": "recruit_hire_commit",
|
|
"select_battle_reward": "reward_option_focus",
|
|
"open_recruit_review": "recruit_hire_review",
|
|
"open_equipment_review": "equip_review",
|
|
"open_dismissal_review": "dismiss_arm",
|
|
"open_contract_return_review": "run_end_voluntary",
|
|
"continue_from_battle_result": "run_continue",
|
|
"select_market_offer": "offer_reveal",
|
|
}
|
|
|
|
HELPERS = '''
|
|
func _ensure_audio_service() -> void:
|
|
if audio_service != null and is_instance_valid(audio_service):
|
|
return
|
|
audio_service = AudioServiceScript.new()
|
|
audio_service.name = "AudioService"
|
|
add_child(audio_service)
|
|
|
|
|
|
func _audio_enter(page_id: String, family := "") -> void:
|
|
_ensure_audio_service()
|
|
if audio_service == null:
|
|
return
|
|
audio_page_id = page_id
|
|
if not family.is_empty():
|
|
audio_service.set_music(family)
|
|
audio_service.play_sfx("page_open")
|
|
|
|
|
|
func _audio_sfx(event_name: String) -> void:
|
|
_ensure_audio_service()
|
|
if audio_service != null:
|
|
audio_service.play_sfx(event_name)
|
|
|
|
'''
|
|
|
|
|
|
def insert_first_statement(text: str, function: str, statement: str, indent: str = "\t") -> tuple[str, bool]:
|
|
pattern = re.compile(rf"^func {re.escape(function)}\(([^\n]*)\)[^\n]*:\n", re.M)
|
|
match = pattern.search(text)
|
|
if match is None:
|
|
return text, False
|
|
insert_at = match.end()
|
|
if text[insert_at:].startswith(f"{indent}{statement}"):
|
|
return text, False
|
|
return text[:insert_at] + f"{indent}{statement}\n" + text[insert_at:], True
|
|
|
|
|
|
def main() -> int:
|
|
text = SHELL.read_text()
|
|
changed: list[str] = []
|
|
if "func _audio_enter(" not in text:
|
|
anchor = "func start_boot() -> void:"
|
|
if anchor not in text:
|
|
raise SystemExit("anchor for helpers not found")
|
|
text = text.replace(anchor, HELPERS.lstrip("\n") + anchor, 1)
|
|
changed.append("helpers")
|
|
if "var audio_service" not in text:
|
|
marker = "func _ready() -> void:\n"
|
|
text = text.replace(marker, "var audio_service: ABGAudioService\nvar audio_page_id := \"\"\n\n\n" + marker, 1)
|
|
changed.append("service vars")
|
|
if "AudioServiceScript" not in text:
|
|
preload_line = 'const AudioServiceScript = preload("res://presentation/audio_service.gd")\n'
|
|
# place after the first const block line
|
|
first_const = re.search(r"^const [A-Za-z_]+ = .*\n", text, re.M)
|
|
if first_const is None:
|
|
raise SystemExit("no const anchor")
|
|
text = text[:first_const.end()] + preload_line + text[first_const.end():]
|
|
changed.append("preload")
|
|
if "audio_service.apply_settings(settings)" not in text:
|
|
old = "\tvar master := AudioServer.get_bus_index(&\"Master\")"
|
|
if old in text:
|
|
text = text.replace(old, "\t_ensure_audio_service()\n\tif audio_service != null:\n\t\taudio_service.apply_settings(settings)\n" + old, 1)
|
|
changed.append("apply settings")
|
|
for function, (page_id, family) in PAGES.items():
|
|
statement = f'_audio_enter("{page_id}", "{family}")'
|
|
text, did = insert_first_statement(text, function, statement)
|
|
if did:
|
|
changed.append(f"page:{page_id}")
|
|
for function, event in ACTIONS.items():
|
|
statement = f'_audio_sfx("{event}")'
|
|
text, did = insert_first_statement(text, function, statement)
|
|
if did:
|
|
changed.append(f"action:{function}")
|
|
SHELL.write_text(text)
|
|
print(f"wired {len(changed)} sites: {', '.join(changed[:6])}{' ...' if len(changed) > 6 else ''}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|