Files
aetherbound-guild/runtime/main.gd
T

1027 lines
45 KiB
GDScript

extends Control
const FacadeScript = preload("res://compat/p9_0_root_facade.gd")
const P92BattleServiceScript = preload("res://domain/p9_2/battle_service.gd")
const P92BattlePresenterScript = preload("res://presentation/p9_2_battle_presenter.gd")
const P93CoreLoopControllerScript = preload("res://p9_3/core_loop_controller.gd")
const P97RuntimeControllerScript = preload("res://p9_7/runtime_controller.gd")
const P97SaveServiceScript = preload("res://p9_7/save_service.gd")
const P98RuntimeControllerScript = preload("res://p9_8/runtime_controller.gd")
const P98SaveServiceScript = preload("res://p9_8/save_service.gd")
const P99RuntimeControllerScript = preload("res://p9_9/runtime_controller.gd")
const P99SaveServiceScript = preload("res://p9_9/save_service.gd")
const P910RuntimeControllerScript = preload("res://p9_10/runtime_controller.gd")
const P910SaveServiceScript = preload("res://p9_10/save_service.gd")
const P100RuntimeControllerScript = preload("res://p10_1/runtime_controller.gd")
const P101StateScript = preload("res://p10_1/region_run_state.gd")
const P101SaveServiceScript = preload("res://p10_1/save_v7_service.gd")
const P102RuntimeControllerScript = preload("res://p10_2/runtime_controller.gd")
const P102StateScript = preload("res://p10_2/run_state.gd")
const P102SaveServiceScript = preload("res://p10_2/save_v8_service.gd")
const P103RuntimeControllerScript = preload("res://p10_3/runtime_controller.gd")
const P103StateScript = preload("res://p10_3/run_state.gd")
const P103SaveServiceScript = preload("res://p10_3/save_v9_service.gd")
const FG2RuntimeControllerScript = preload("res://campaign/fg2_graybox_controller.gd")
const FG2FixtureScript = preload("res://campaign/fg2_fixture.gd")
const EntryShellScript = preload("res://entry/entry_shell.gd")
const AppPage = FacadeScript.AppPage
const ANIMATION_SPECS = FacadeScript.ANIMATION_SPECS
const BATTLE_PHASE_DURATIONS = FacadeScript.BATTLE_PHASE_DURATIONS
const BATTLE_FEEDBACK_DURATION = FacadeScript.BATTLE_FEEDBACK_DURATION
var facade := FacadeScript.new()
var authoritative_battle_service := P92BattleServiceScript.new()
var authoritative_battle_presenter
var authoritative_battle_active := false
var authoritative_auto_advance := true
var authoritative_tick_accumulator := 0.0
var authoritative_speed_multiplier := 1
var authoritative_inspect_open := false
var authoritative_inspect_events: Array[Dictionary] = []
var authoritative_retreat_receipt: Dictionary = {}
var authoritative_last_command_code := ""
var authoritative_last_events: Array[Dictionary] = []
@export var p93_experience_enabled := true
@export var p100_experience_enabled := true
@export var p100_persistence_enabled := true
@export var fg2_review_enabled := false
var fg2_experience
var p93_experience
var p97_experience
var p98_experience
var p98_handoff_pending := false
var p98_handoff_button: Button
var p99_experience
var p99_handoff_pending := false
var p99_handoff_button: Button
var p910_experience
var p910_handoff_pending := false
var p910_handoff_button: Button
var p100_experience
var p102_experience
var p102_handoff_pending := false
var p102_handoff_button: Button
var p103_experience
var p103_handoff_pending := false
var p103_handoff_button: Button
var entry_shell
var active_battle_feedback:
get: return facade.active_battle_feedback
set(value): facade.active_battle_feedback = value
var adaptation_choice:
get: return facade.adaptation_choice
set(value): facade.adaptation_choice = value
var adaptation_committed:
get: return facade.adaptation_committed
set(value): facade.adaptation_committed = value
var added_rear:
get: return facade.added_rear
set(value): facade.added_rear = value
var audio_enabled:
get: return facade.audio_enabled
set(value): facade.audio_enabled = value
var audio_player:
get: return facade.audio_player
set(value): facade.audio_player = value
var auto_boot:
get: return facade.auto_boot
set(value): facade.auto_boot = value
var battle_clock:
get: return facade.battle_clock
set(value): facade.battle_clock = value
var battle_feedback_clock:
get: return facade.battle_feedback_clock
set(value): facade.battle_feedback_clock = value
var battle_feedback_history:
get: return facade.battle_feedback_history
set(value): facade.battle_feedback_history = value
var battle_feedback_origin:
get: return facade.battle_feedback_origin
set(value): facade.battle_feedback_origin = value
var battle_phase:
get: return facade.battle_phase
set(value): facade.battle_phase = value
var battle_playing:
get: return facade.battle_playing
set(value): facade.battle_playing = value
var boot_failed_path:
get: return facade.boot_failed_path
set(value): facade.boot_failed_path = value
var boot_index:
get: return facade.boot_index
set(value): facade.boot_index = value
var boot_paths_override:
get: return facade.boot_paths_override
set(value): facade.boot_paths_override = value
var boot_verified:
get: return facade.boot_verified
set(value): facade.boot_verified = value
var coin:
get: return facade.coin
set(value): facade.coin = value
var enemy_hp:
get: return facade.enemy_hp
set(value): facade.enemy_hp = value
var enemy_sprite:
get: return facade.enemy_sprite
set(value): facade.enemy_sprite = value
var fifth_battle_elapsed:
get: return facade.fifth_battle_elapsed
set(value): facade.fifth_battle_elapsed = value
var fifth_reward_committed:
get: return facade.fifth_reward_committed
set(value): facade.fifth_reward_committed = value
var first_reward_committed:
get: return facade.first_reward_committed
set(value): facade.first_reward_committed = value
var formation_commit_count:
get: return facade.formation_commit_count
set(value): facade.formation_commit_count = value
var fourth_battle_elapsed:
get: return facade.fourth_battle_elapsed
set(value): facade.fourth_battle_elapsed = value
var fourth_result_time:
get: return facade.fourth_result_time
set(value): facade.fourth_result_time = value
var front_choice:
get: return facade.front_choice
set(value): facade.front_choice = value
var front_hp:
get: return facade.front_hp
set(value): facade.front_hp = value
var front_sprite:
get: return facade.front_sprite
set(value): facade.front_sprite = value
var guard_events:
get: return facade.guard_events
set(value): facade.guard_events = value
var guild_choice:
get: return facade.guild_choice
set(value): facade.guild_choice = value
var guild_committed:
get: return facade.guild_committed
set(value): facade.guild_committed = value
var locale:
get: return facade.locale
set(value): facade.locale = value
var muted:
get: return facade.muted
set(value): facade.muted = value
var page:
get: return facade.page
set(value): facade.page = value
var phase_impact_committed:
get: return facade.phase_impact_committed
set(value): facade.phase_impact_committed = value
var rear_choice:
get: return facade.rear_choice
set(value): facade.rear_choice = value
var rear_events:
get: return facade.rear_events
set(value): facade.rear_events = value
var rear_hp:
get: return facade.rear_hp
set(value): facade.rear_hp = value
var rear_sprite:
get: return facade.rear_sprite
set(value): facade.rear_sprite = value
var reduced_motion:
get: return facade.reduced_motion
set(value): facade.reduced_motion = value
var restart_confirmation:
get: return facade.restart_confirmation
set(value): facade.restart_confirmation = value
var retained_item:
get: return facade.retained_item
set(value): facade.retained_item = value
var route_choice:
get: return facade.route_choice
set(value): facade.route_choice = value
var route_committed:
get: return facade.route_committed
set(value): facade.route_committed = value
var route_reward_committed:
get: return facade.route_reward_committed
set(value): facade.route_reward_committed = value
var second_battle_elapsed:
get: return facade.second_battle_elapsed
set(value): facade.second_battle_elapsed = value
var second_result_time:
get: return facade.second_result_time
set(value): facade.second_result_time = value
var selected_recruits:
get: return facade.selected_recruits
set(value): facade.selected_recruits = value
var sfx_playback:
get: return facade.sfx_playback
set(value): facade.sfx_playback = value
var text_scale:
get: return facade.text_scale
set(value): facade.text_scale = value
var third_battle_elapsed:
get: return facade.third_battle_elapsed
set(value): facade.third_battle_elapsed = value
var third_result_time:
get: return facade.third_result_time
set(value): facade.third_result_time = value
var trained_member:
get: return facade.trained_member
set(value): facade.trained_member = value
var training_choice:
get: return facade.training_choice
set(value): facade.training_choice = value
var training_committed:
get: return facade.training_committed
set(value): facade.training_committed = value
var victory_events:
get: return facade.victory_events
set(value): facade.victory_events = value
func _ready() -> void:
var should_start_entry: bool = auto_boot and not OS.has_feature("fg2_review")
if should_start_entry:
facade.auto_boot = false
var should_start_fg2: bool = auto_boot and (fg2_review_enabled or OS.has_feature("fg2_review"))
var p103_resume_snapshot: Dictionary = _p103_resume_snapshot() if p100_persistence_enabled and not should_start_fg2 else {}
var should_start_p103: bool = auto_boot and p100_experience_enabled and not p103_resume_snapshot.is_empty()
var p102_resume_snapshot: Dictionary = _p102_resume_snapshot() if p100_persistence_enabled and not should_start_fg2 and not should_start_p103 else {}
var should_start_p102: bool = auto_boot and p100_experience_enabled and not p102_resume_snapshot.is_empty()
var should_start_p100: bool = auto_boot and p100_experience_enabled and not should_start_fg2 and not should_start_p103 and not should_start_p102
var p910_resume_snapshot: Dictionary = {} if should_start_p100 or should_start_fg2 else _p910_resume_snapshot()
var p99_resume_snapshot: Dictionary = {} if should_start_p100 or should_start_fg2 else _p99_resume_snapshot()
var p98_resume_snapshot: Dictionary = {} if should_start_p100 or should_start_fg2 else _p98_resume_snapshot()
var p97_resume_snapshot: Dictionary = {} if should_start_p100 or should_start_fg2 else _p97_resume_snapshot()
var should_start_p910: bool = auto_boot and p93_experience_enabled and not p910_resume_snapshot.is_empty()
var should_start_p99: bool = auto_boot and p93_experience_enabled and not should_start_p910 and not p99_resume_snapshot.is_empty()
var should_start_p98: bool = auto_boot and p93_experience_enabled and not should_start_p910 and not should_start_p99 and not p98_resume_snapshot.is_empty()
var should_start_p97: bool = auto_boot and p93_experience_enabled and not should_start_p910 and not should_start_p99 and not should_start_p98 and not p97_resume_snapshot.is_empty()
var should_start_p93: bool = auto_boot and p93_experience_enabled and not should_start_p910 and not should_start_p99 and not should_start_p98 and not should_start_p97
if should_start_fg2 or should_start_p103 or should_start_p102 or should_start_p100 or should_start_p93 or should_start_p97 or should_start_p98 or should_start_p99 or should_start_p910:
facade.auto_boot = false
facade.name = "RuntimeFacade"
facade.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(facade)
theme = facade.theme
if should_start_entry:
facade.visible = false
entry_shell = EntryShellScript.new()
entry_shell.name = "EntryShell"
entry_shell.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(entry_shell)
return
facade.authoritative_battle_requested.connect(start_authoritative_battle)
authoritative_battle_presenter = P92BattlePresenterScript.new(self)
if should_start_fg2:
call_deferred("start_fg2_experience")
elif should_start_p103:
call_deferred("start_p103_experience", p103_resume_snapshot)
elif should_start_p102:
call_deferred("start_p102_experience", p102_resume_snapshot)
elif should_start_p100:
call_deferred("start_p100_experience", p100_persistence_enabled)
elif should_start_p910:
call_deferred("start_p910_experience", p910_resume_snapshot)
elif should_start_p99:
call_deferred("start_p99_experience", p99_resume_snapshot)
elif should_start_p93:
call_deferred("start_p93_experience")
elif should_start_p98:
call_deferred("start_p98_experience", p98_resume_snapshot)
elif should_start_p97:
call_deferred("start_p97_experience", p97_resume_snapshot)
func _get(property: StringName) -> Variant:
return facade.get(property)
func _set(property: StringName, value: Variant) -> bool:
facade.set(property, value)
return true
func _get_property_list() -> Array[Dictionary]:
var result: Array[Dictionary] = []
for property in facade.get_property_list():
var name: StringName = property["name"]
if name in [&"script", &"name", &"owner", &"process_mode", &"process_priority", &"process_physics_priority"]:
continue
result.append({
"name": name,
"type": property["type"],
"hint": property.get("hint", PROPERTY_HINT_NONE),
"hint_string": property.get("hint_string", ""),
"usage": PROPERTY_USAGE_DEFAULT,
})
return result
func _process(delta: float) -> void:
if is_instance_valid(fg2_experience):
return
if is_instance_valid(p102_experience) and _is_p103_handoff(p102_experience):
_show_p103_handoff()
if is_instance_valid(p100_experience) and _is_p102_handoff(p100_experience):
_show_p102_handoff()
if is_instance_valid(p97_experience) and p97_experience.market != null and _is_p98_handoff(p97_experience.market.state.snapshot()):
_show_p98_handoff()
if is_instance_valid(p98_experience) and p98_experience.market != null and _is_p99_handoff(p98_experience.market.state.snapshot()):
_show_p99_handoff()
if is_instance_valid(p99_experience) and p99_experience.market != null and _is_p910_handoff(p99_experience.market.state.snapshot()):
_show_p910_handoff()
if is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience) or is_instance_valid(p93_experience) or is_instance_valid(p97_experience) or is_instance_valid(p98_experience) or is_instance_valid(p99_experience) or is_instance_valid(p910_experience):
return
if authoritative_battle_active:
_process_authoritative_battle(delta)
return
facade._process(delta)
func start_p93_experience() -> void:
if is_instance_valid(fg2_experience):
return
if is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience) or is_instance_valid(p93_experience) or is_instance_valid(p97_experience) or is_instance_valid(p98_experience) or is_instance_valid(p99_experience) or is_instance_valid(p910_experience):
return
facade.visible = false
p93_experience = P93CoreLoopControllerScript.new()
p93_experience.name = "P93CoreLoop"
p93_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p93_experience.windglass_market_requested.connect(start_p97_experience)
add_child(p93_experience)
func start_p100_experience(enable_persistence := true) -> void:
if is_instance_valid(fg2_experience):
return
if is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience) or is_instance_valid(p93_experience) or is_instance_valid(p97_experience) or is_instance_valid(p98_experience) or is_instance_valid(p99_experience) or is_instance_valid(p910_experience):
return
facade.visible = false
p100_experience = P100RuntimeControllerScript.new()
p100_experience.name = "P100CanonicalRuntime"
p100_experience.persistence_enabled = enable_persistence
p100_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(p100_experience)
func start_fg2_experience() -> void:
if is_instance_valid(fg2_experience) or is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience) or is_instance_valid(p93_experience) or is_instance_valid(p97_experience) or is_instance_valid(p98_experience) or is_instance_valid(p99_experience) or is_instance_valid(p910_experience):
return
facade.visible = false
fg2_experience = FG2RuntimeControllerScript.new()
fg2_experience.name = "FG2OwnerReview"
fg2_experience.locale = facade.locale
fg2_experience.text_scale = facade.text_scale
fg2_experience.reduced_motion = facade.reduced_motion
fg2_experience.muted = false
fg2_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
fg2_experience.configure_entry(FG2FixtureScript.canonical_market_state())
add_child(fg2_experience)
func start_p102_experience(snapshot: Dictionary) -> void:
if is_instance_valid(fg2_experience):
return
if snapshot.is_empty() or is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience):
return
facade.visible = false
p102_experience = P102RuntimeControllerScript.new()
p102_experience.name = "P102SiltwakeMidRuntime"
p102_experience.persistence_enabled = p100_persistence_enabled
p102_experience.locale = facade.locale
p102_experience.text_scale = facade.text_scale
p102_experience.reduced_motion = facade.reduced_motion
p102_experience.muted = facade.muted
p102_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p102_experience.configure_entry(snapshot)
add_child(p102_experience)
p102_handoff_pending = false
p102_handoff_button = null
func _show_p102_handoff() -> void:
if p102_handoff_pending and is_instance_valid(p102_handoff_button):
return
p102_handoff_pending = false
p102_handoff_button = null
if not is_instance_valid(p100_experience):
return
var display = p100_experience.display_root
if not is_instance_valid(display):
return
p102_handoff_button = p100_experience._action_button(
"P102ContinueMidContractButton",
p100_experience._tr("继续第2轮", "CONTINUE TO ROUND 2"),
_continue_p102_handoff
)
p102_handoff_button.position = Vector2(p100_experience.size.x - 238, p100_experience.size.y - 66)
p102_handoff_button.size = Vector2(218, 52)
p102_handoff_button.z_index = 42
display.add_child(p102_handoff_button)
p102_handoff_pending = true
func _continue_p102_handoff() -> void:
if not is_instance_valid(p100_experience) or not _is_p102_handoff(p100_experience):
return
var snapshot: Dictionary = p100_experience.region_market.state.snapshot()
var source_locale: String = p100_experience.locale
var source_text_scale: float = p100_experience.text_scale
var source_reduced_motion: bool = p100_experience.reduced_motion
var source_muted: bool = p100_experience.muted
var source_low_power: bool = p100_experience.low_power
p100_experience.visible = false
p100_experience.process_mode = Node.PROCESS_MODE_DISABLED
p100_experience.queue_free()
p100_experience = null
p102_experience = P102RuntimeControllerScript.new()
p102_experience.name = "P102SiltwakeMidRuntime"
p102_experience.persistence_enabled = p100_persistence_enabled
p102_experience.locale = source_locale
p102_experience.text_scale = source_text_scale
p102_experience.reduced_motion = source_reduced_motion
p102_experience.muted = source_muted
p102_experience.low_power = source_low_power
p102_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p102_experience.configure_entry(snapshot)
add_child(p102_experience)
p102_handoff_pending = false
p102_handoff_button = null
func start_p103_experience(snapshot: Dictionary) -> void:
if is_instance_valid(fg2_experience):
return
if snapshot.is_empty() or is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience):
return
facade.visible = false
p103_experience = P103RuntimeControllerScript.new()
p103_experience.name = "P103SiltwakeDeepRuntime"
p103_experience.persistence_enabled = p100_persistence_enabled
p103_experience.locale = facade.locale
p103_experience.text_scale = facade.text_scale
p103_experience.reduced_motion = facade.reduced_motion
p103_experience.muted = facade.muted
p103_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p103_experience.configure_entry(snapshot)
add_child(p103_experience)
p103_handoff_pending = false
p103_handoff_button = null
func _show_p103_handoff() -> void:
if p103_handoff_pending and is_instance_valid(p103_handoff_button):
return
p103_handoff_pending = false
p103_handoff_button = null
if not is_instance_valid(p102_experience):
return
var display = p102_experience.display_root
if not is_instance_valid(display):
return
p103_handoff_button = p102_experience._action_button(
"P103ContinueDeepChannelsButton",
p102_experience._tr("继续深水道", "CONTINUE INTO DEEP CHANNELS"),
_continue_p103_handoff
)
p103_handoff_button.position = Vector2(p102_experience.size.x - 250, p102_experience.size.y - 66)
p103_handoff_button.size = Vector2(230, 52)
p103_handoff_button.z_index = 42
display.add_child(p103_handoff_button)
p103_handoff_pending = true
func _continue_p103_handoff() -> void:
if not is_instance_valid(p102_experience) or not _is_p103_handoff(p102_experience):
return
var snapshot: Dictionary = p102_experience.region_market.state.snapshot()
var source_locale: String = p102_experience.locale
var source_text_scale: float = p102_experience.text_scale
var source_reduced_motion: bool = p102_experience.reduced_motion
var source_muted: bool = p102_experience.muted
var source_low_power: bool = p102_experience.low_power
p102_experience.visible = false
p102_experience.process_mode = Node.PROCESS_MODE_DISABLED
p102_experience.queue_free()
p102_experience = null
p103_experience = P103RuntimeControllerScript.new()
p103_experience.name = "P103SiltwakeDeepRuntime"
p103_experience.persistence_enabled = p100_persistence_enabled
p103_experience.locale = source_locale
p103_experience.text_scale = source_text_scale
p103_experience.reduced_motion = source_reduced_motion
p103_experience.muted = source_muted
p103_experience.low_power = source_low_power
p103_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p103_experience.configure_entry(snapshot)
add_child(p103_experience)
p103_handoff_pending = false
p103_handoff_button = null
func _p103_resume_snapshot() -> Dictionary:
var loaded: Dictionary = P103SaveServiceScript.new().load_slot(
ProjectSettings.globalize_path("user://aetherbound_guild_p10_3.json")
)
if loaded.ok and String(loaded.snapshot.get("state_kind", "")) == P103StateScript.P103_STATE_KIND:
return Dictionary(loaded.snapshot).duplicate(true)
return {}
func _is_p103_handoff(experience) -> bool:
return (
is_instance_valid(experience)
and bool(experience.region_mode)
and experience.region_market != null
and String(experience.region_market.state.snapshot().get("state_kind", "")) == P102StateScript.STATE_KIND
and String(experience.region_market.state.current_run.get("phase", "")) == "market_5"
and int(experience.region_market.state.current_run.get("market_index", -1)) == 5
)
func _p102_resume_snapshot() -> Dictionary:
var loaded: Dictionary = P102SaveServiceScript.new().load_slot(
ProjectSettings.globalize_path("user://aetherbound_guild_p10_2.json")
)
if loaded.ok and String(loaded.snapshot.get("state_kind", "")) == P102StateScript.STATE_KIND:
return Dictionary(loaded.snapshot).duplicate(true)
var legacy: Dictionary = P101SaveServiceScript.new().load_slot(
ProjectSettings.globalize_path("user://aetherbound_guild_p10_1.json")
)
if (
legacy.ok
and String(legacy.snapshot.get("state_kind", "")) == P101StateScript.STATE_KIND
and String(legacy.snapshot.get("current_run", {}).get("phase", "")) == "market_2"
):
return Dictionary(legacy.snapshot).duplicate(true)
return {}
func _is_p102_handoff(experience) -> bool:
return (
is_instance_valid(experience)
and bool(experience.region_mode)
and experience.region_market != null
and String(experience.region_market.state.current_run.get("phase", "")) == "market_2"
and int(experience.region_market.state.current_run.get("market_index", -1)) == 2
)
func start_p97_experience(snapshot: Dictionary) -> void:
if is_instance_valid(fg2_experience):
return
if snapshot.is_empty() or is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience) or is_instance_valid(p97_experience) or is_instance_valid(p99_experience) or is_instance_valid(p910_experience):
return
var source_locale := facade.locale
var source_text_scale := facade.text_scale
var source_reduced_motion := facade.reduced_motion
var source_muted := facade.muted
var source_low_power := false
if is_instance_valid(p93_experience):
source_locale = p93_experience.locale
source_text_scale = p93_experience.text_scale
source_reduced_motion = p93_experience.reduced_motion
source_muted = p93_experience.muted
source_low_power = p93_experience.low_power
p93_experience.visible = false
p93_experience.process_mode = Node.PROCESS_MODE_DISABLED
p93_experience.queue_free()
p93_experience = null
facade.visible = false
p97_experience = P97RuntimeControllerScript.new()
p97_experience.name = "P97WindglassRuntime"
p97_experience.locale = source_locale
p97_experience.text_scale = source_text_scale
p97_experience.reduced_motion = source_reduced_motion
p97_experience.muted = source_muted
p97_experience.low_power = source_low_power
p97_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p97_experience.configure_entry(snapshot)
add_child(p97_experience)
func start_p98_experience(snapshot: Dictionary) -> void:
if is_instance_valid(fg2_experience):
return
if snapshot.is_empty() or is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience) or is_instance_valid(p98_experience) or is_instance_valid(p99_experience) or is_instance_valid(p910_experience):
return
var source_locale := facade.locale
var source_text_scale := facade.text_scale
var source_reduced_motion := facade.reduced_motion
var source_muted := facade.muted
var source_low_power := false
if is_instance_valid(p93_experience):
source_locale = p93_experience.locale
source_text_scale = p93_experience.text_scale
source_reduced_motion = p93_experience.reduced_motion
source_muted = p93_experience.muted
source_low_power = p93_experience.low_power
p93_experience.queue_free()
p93_experience = null
if is_instance_valid(p97_experience):
source_locale = p97_experience.locale
source_text_scale = p97_experience.text_scale
source_reduced_motion = p97_experience.reduced_motion
source_muted = p97_experience.muted
source_low_power = p97_experience.low_power
p97_experience.visible = false
p97_experience.process_mode = Node.PROCESS_MODE_DISABLED
p97_experience.queue_free()
p97_experience = null
p98_handoff_button = null
facade.visible = false
p98_experience = P98RuntimeControllerScript.new()
p98_experience.name = "P98WindglassContractRuntime"
p98_experience.locale = source_locale
p98_experience.text_scale = source_text_scale
p98_experience.reduced_motion = source_reduced_motion
p98_experience.muted = source_muted
p98_experience.low_power = source_low_power
p98_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p98_experience.configure_entry(snapshot)
add_child(p98_experience)
p98_handoff_pending = false
func start_p99_experience(snapshot: Dictionary) -> void:
if is_instance_valid(fg2_experience):
return
if snapshot.is_empty() or is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience) or is_instance_valid(p99_experience) or is_instance_valid(p910_experience):
return
var source_locale := facade.locale
var source_text_scale := facade.text_scale
var source_reduced_motion := facade.reduced_motion
var source_muted := facade.muted
var source_low_power := false
if is_instance_valid(p98_experience):
source_locale = p98_experience.locale
source_text_scale = p98_experience.text_scale
source_reduced_motion = p98_experience.reduced_motion
source_muted = p98_experience.muted
source_low_power = p98_experience.low_power
p98_experience.visible = false
p98_experience.process_mode = Node.PROCESS_MODE_DISABLED
p98_experience.queue_free()
p98_experience = null
if is_instance_valid(p97_experience):
p97_experience.queue_free()
p97_experience = null
if is_instance_valid(p93_experience):
p93_experience.queue_free()
p93_experience = null
p99_handoff_button = null
facade.visible = false
p99_experience = P99RuntimeControllerScript.new()
p99_experience.name = "P99GuildCharterRuntime"
p99_experience.locale = source_locale
p99_experience.text_scale = source_text_scale
p99_experience.reduced_motion = source_reduced_motion
p99_experience.muted = source_muted
p99_experience.low_power = source_low_power
p99_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p99_experience.configure_entry(snapshot)
add_child(p99_experience)
p99_handoff_pending = false
func start_p910_experience(snapshot: Dictionary) -> void:
if is_instance_valid(fg2_experience):
return
if snapshot.is_empty() or is_instance_valid(p103_experience) or is_instance_valid(p102_experience) or is_instance_valid(p100_experience) or is_instance_valid(p910_experience):
return
var source_locale := facade.locale
var source_text_scale := facade.text_scale
var source_reduced_motion := facade.reduced_motion
var source_muted := facade.muted
var source_low_power := false
if is_instance_valid(p99_experience):
source_locale = p99_experience.locale
source_text_scale = p99_experience.text_scale
source_reduced_motion = p99_experience.reduced_motion
source_muted = p99_experience.muted
source_low_power = p99_experience.low_power
p99_experience.visible = false
p99_experience.process_mode = Node.PROCESS_MODE_DISABLED
p99_experience.queue_free()
p99_experience = null
if is_instance_valid(p98_experience):
p98_experience.queue_free()
p98_experience = null
if is_instance_valid(p97_experience):
p97_experience.queue_free()
p97_experience = null
if is_instance_valid(p93_experience):
p93_experience.queue_free()
p93_experience = null
p910_handoff_button = null
facade.visible = false
p910_experience = P910RuntimeControllerScript.new()
p910_experience.name = "P910GaleLoomRuntime"
p910_experience.locale = source_locale
p910_experience.text_scale = source_text_scale
p910_experience.reduced_motion = source_reduced_motion
p910_experience.muted = source_muted
p910_experience.low_power = source_low_power
p910_experience.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
p910_experience.configure_entry(snapshot)
add_child(p910_experience)
p910_handoff_pending = false
func _show_p98_handoff() -> void:
if p98_handoff_pending and is_instance_valid(p98_handoff_button):
return
if not is_instance_valid(p97_experience) or p97_experience.display_root == null:
return
p98_handoff_pending = true
var value := "CONTINUE WINDGLASS CONTRACT" if p97_experience.locale == "en" else "继续风晶契约"
p98_handoff_button = p97_experience._action_button("P98ContinueContractButton", value, _continue_p98_handoff)
p98_handoff_button.position = Vector2(maxf(16, p97_experience.size.x - 258), maxf(16, p97_experience.size.y - 68))
p98_handoff_button.size = Vector2(242, 52)
p97_experience.display_root.add_child(p98_handoff_button)
func _continue_p98_handoff() -> void:
if not is_instance_valid(p97_experience) or p97_experience.market == null:
return
var snapshot: Dictionary = p97_experience.market.state.snapshot()
if not _is_p98_handoff(snapshot):
return
start_p98_experience(snapshot)
func _show_p99_handoff() -> void:
if p99_handoff_pending and is_instance_valid(p99_handoff_button):
return
if not is_instance_valid(p98_experience) or p98_experience.display_root == null:
return
p99_handoff_pending = true
var value := "OPEN GUILD CHARTER" if p98_experience.locale == "en" else "打开公会宪章"
p99_handoff_button = p98_experience._action_button("P99ContinueCharterButton", value, _continue_p99_handoff)
p99_handoff_button.position = Vector2(maxf(16, p98_experience.size.x - 246), maxf(16, p98_experience.size.y - 68))
p99_handoff_button.size = Vector2(230, 52)
p98_experience.display_root.add_child(p99_handoff_button)
func _continue_p99_handoff() -> void:
if not is_instance_valid(p98_experience) or p98_experience.market == null:
return
var snapshot: Dictionary = p98_experience.market.state.snapshot()
if not _is_p99_handoff(snapshot):
return
start_p99_experience(snapshot)
func _show_p910_handoff() -> void:
if p910_handoff_pending and is_instance_valid(p910_handoff_button):
return
if not is_instance_valid(p99_experience) or p99_experience.display_root == null:
return
p910_handoff_pending = true
var value := "ENTER THE GALE CORRIDOR" if p99_experience.locale == "en" else "进入风暴走廊"
p910_handoff_button = p99_experience._action_button("P910ContinueContractButton", value, _continue_p910_handoff)
p910_handoff_button.position = Vector2(maxf(16, p99_experience.size.x - 246), maxf(16, p99_experience.size.y - 68))
p910_handoff_button.size = Vector2(230, 52)
p99_experience.display_root.add_child(p910_handoff_button)
func _continue_p910_handoff() -> void:
if not is_instance_valid(p99_experience) or p99_experience.market == null:
return
var snapshot: Dictionary = p99_experience.market.state.snapshot()
if not _is_p910_handoff(snapshot):
return
start_p910_experience(snapshot)
func _p97_resume_snapshot() -> Dictionary:
if not auto_boot or not p93_experience_enabled:
return {}
var loaded: Dictionary = P97SaveServiceScript.new().load_snapshot()
if not loaded.ok or int(loaded.get("source_version", -1)) != 2:
return {}
return Dictionary(loaded.snapshot).duplicate(true)
func _p98_resume_snapshot() -> Dictionary:
if not auto_boot or not p93_experience_enabled:
return {}
var loaded: Dictionary = P98SaveServiceScript.new().load_snapshot()
if not loaded.ok or int(loaded.get("source_version", -1)) != 3:
return {}
return Dictionary(loaded.snapshot).duplicate(true)
func _p99_resume_snapshot() -> Dictionary:
if not auto_boot or not p93_experience_enabled:
return {}
var loaded: Dictionary = P99SaveServiceScript.new().load_snapshot()
if not loaded.ok or int(loaded.get("source_version", -1)) != 4:
return {}
return Dictionary(loaded.snapshot).duplicate(true)
func _p910_resume_snapshot() -> Dictionary:
if not auto_boot or not p93_experience_enabled:
return {}
var loaded: Dictionary = P910SaveServiceScript.new().load_snapshot()
if not loaded.ok or int(loaded.get("source_version", -1)) != 5:
return {}
return Dictionary(loaded.snapshot).duplicate(true)
func _is_p98_handoff(snapshot: Dictionary) -> bool:
return not snapshot.is_empty() and int(snapshot.get("current_market", 0)) == 8 and int(snapshot.get("cleared_rounds", 0)) == 7 and bool(snapshot.get("relay_restored", false))
func _is_p99_handoff(snapshot: Dictionary) -> bool:
return not snapshot.is_empty() and bool(snapshot.get("p98_activated", false)) and bool(snapshot.get("run_closed", false)) and "CLEAR-RG01-C01" in snapshot.get("contract_clear_ids", [])
func _is_p910_handoff(snapshot: Dictionary) -> bool:
return not snapshot.is_empty() \
and String(snapshot.get("state_kind", "")) == "p99_run" \
and int(snapshot.get("current_market", 0)) == 4 \
and int(snapshot.get("cleared_rounds", 0)) == 3 \
and bool(snapshot.get("continuation_locked", false))
func start_authoritative_battle() -> bool:
var members: Array[String] = facade.session_state.current_member_ids()
if members.is_empty():
return false
var starting_hp: Dictionary = {}
for member_id in members:
starting_hp[member_id] = facade.session_state.member_health(member_id)
var result: Dictionary = authoritative_battle_service.start_fixture(members, 9201, starting_hp)
if not result.ok:
return false
authoritative_battle_active = true
authoritative_tick_accumulator = 0.0
authoritative_speed_multiplier = 1
authoritative_inspect_open = false
authoritative_inspect_events.clear()
authoritative_retreat_receipt.clear()
authoritative_last_command_code = ""
authoritative_last_events.clear()
for event in result.events:
authoritative_last_events.append(Dictionary(event).duplicate(true))
facade.visible = false
authoritative_battle_presenter.render(authoritative_battle_service.state.current_snapshot(), authoritative_last_events)
return true
func advance_authoritative_ticks(ticks: int) -> Dictionary:
if not authoritative_battle_active:
return {"ok": false, "code": "inactive", "events": []}
var result: Dictionary = authoritative_battle_service.advance_ticks(ticks)
return _accept_authoritative_result(result)
func toggle_authoritative_pause() -> Dictionary:
if not authoritative_battle_active:
return {"ok": false, "code": "inactive", "events": []}
var result: Dictionary = authoritative_battle_service.set_paused(not authoritative_battle_service.state.paused)
return _accept_authoritative_result(result)
func set_authoritative_speed(multiplier: int) -> Dictionary:
if not authoritative_battle_active:
return {"ok": false, "code": "inactive"}
if multiplier not in [1, 2]:
return {"ok": false, "code": "invalid_speed"}
authoritative_speed_multiplier = multiplier
authoritative_tick_accumulator = 0.0
authoritative_last_command_code = "speed_%dx" % multiplier
authoritative_battle_presenter.render(authoritative_battle_service.state.current_snapshot(), authoritative_last_events)
return {"ok": true, "code": authoritative_last_command_code, "speed": multiplier}
func toggle_authoritative_inspect() -> Dictionary:
if not authoritative_battle_active:
return {"ok": false, "code": "inactive"}
var result: Dictionary = authoritative_battle_service.inspect()
if not result.ok:
return result
authoritative_inspect_open = not authoritative_inspect_open
authoritative_inspect_events.clear()
for event in result.events:
authoritative_inspect_events.append(Dictionary(event).duplicate(true))
authoritative_last_command_code = "inspect_open" if authoritative_inspect_open else "inspect_closed"
authoritative_battle_presenter.render(result.snapshot, authoritative_last_events)
return {"ok": true, "code": authoritative_last_command_code, "snapshot": result.snapshot, "events": authoritative_inspect_events.duplicate(true)}
func request_authoritative_retreat() -> Dictionary:
if not authoritative_battle_active:
return {"ok": false, "code": "inactive", "events": []}
var result: Dictionary = authoritative_battle_service.request_retreat()
return _accept_authoritative_result(result)
func retry_authoritative_battle() -> bool:
if not authoritative_battle_active or not authoritative_battle_service.state.terminal:
return false
return start_authoritative_battle()
func exit_authoritative_battle_to_home() -> void:
if not authoritative_battle_active:
return
authoritative_battle_active = false
authoritative_auto_advance = true
authoritative_tick_accumulator = 0.0
authoritative_speed_multiplier = 1
authoritative_inspect_open = false
authoritative_inspect_events.clear()
authoritative_retreat_receipt.clear()
authoritative_last_command_code = "home"
authoritative_last_events.clear()
authoritative_battle_presenter.cleanup()
facade.visible = true
facade.go_home()
func _accept_authoritative_result(result: Dictionary) -> Dictionary:
authoritative_last_command_code = String(result.get("code", ""))
authoritative_last_events.clear()
for event in result.get("events", []):
authoritative_last_events.append(Dictionary(event).duplicate(true))
if String(event.get("kind", "")) == "retreat_started":
authoritative_retreat_receipt = {
"tick": int(event.get("tick", -1)),
"resolves_at": int(event.get("resolves_at", -1)),
}
if result.has("snapshot"):
authoritative_battle_presenter.render(result.snapshot, authoritative_last_events)
return result
func _process_authoritative_battle(delta: float) -> void:
if authoritative_battle_service.state.terminal:
return
if not authoritative_auto_advance:
return
if authoritative_battle_service.state.paused:
return
authoritative_tick_accumulator += maxf(0.0, delta) * float(authoritative_speed_multiplier)
var ticks := int(floor(authoritative_tick_accumulator / 0.1))
if ticks <= 0:
return
authoritative_tick_accumulator -= float(ticks) * 0.1
advance_authoritative_ticks(ticks)
func active_boot_paths() -> Array[String]: return facade.active_boot_paths()
func adaptation_effect(id: String) -> String: return facade.adaptation_effect(id)
func adaptation_name(id: String) -> String: return facade.adaptation_name(id)
func advance_battle_phase() -> void: facade.advance_battle_phase()
func animation_frame_index(character: String, state: String, elapsed: float) -> int: return facade.animation_frame_index(character, state, elapsed)
func animation_texture(character: String, state: String, elapsed: float) -> Texture2D: return facade.animation_texture(character, state, elapsed)
func assign_automatic_formation() -> bool: return facade.assign_automatic_formation()
func back_to_main_menu() -> void: facade.back_to_main_menu()
func begin_first_battle() -> void: facade.begin_first_battle()
func begin_second_battle() -> void: facade.begin_second_battle()
func begin_third_battle() -> void: facade.begin_third_battle()
func cancel_restart() -> void: facade.cancel_restart()
func cancel_route_review() -> void: facade.cancel_route_review()
func cancel_training_review() -> void: facade.cancel_training_review()
func candidate_name(profession: String) -> String: return facade.candidate_name(profession)
func choose_adaptation(id: String) -> void: facade.choose_adaptation(id)
func choose_candidate(profession: String) -> void: facade.choose_candidate(profession)
func choose_guild_option(id: String) -> void: facade.choose_guild_option(id)
func choose_route(id: String) -> void: facade.choose_route(id)
func choose_training(slot: String) -> void: facade.choose_training(slot)
func clear_experience() -> void: facade.clear_experience()
func commit_fifth_phase_impact(phase: int, refresh_runtime := true) -> void: facade.commit_fifth_phase_impact(phase, refresh_runtime)
func commit_fifth_reward() -> void: facade.commit_fifth_reward()
func commit_first_victory_reward() -> void: facade.commit_first_victory_reward()
func commit_formation() -> void: facade.commit_formation()
func commit_fourth_phase_impact(phase: int, refresh_runtime := true) -> void: facade.commit_fourth_phase_impact(phase, refresh_runtime)
func commit_phase_impact(phase: int, refresh_runtime := true) -> void: facade.commit_phase_impact(phase, refresh_runtime)
func commit_route() -> void: facade.commit_route()
func commit_route_reward() -> void: facade.commit_route_reward()
func commit_second_phase_impact(phase: int, refresh_runtime := true) -> void: facade.commit_second_phase_impact(phase, refresh_runtime)
func commit_third_phase_impact(phase: int, refresh_runtime := true) -> void: facade.commit_third_phase_impact(phase, refresh_runtime)
func commit_training() -> void: facade.commit_training()
func confirm_restart() -> void: facade.confirm_restart()
func depart() -> void: facade.depart()
func emit_battle_feedback(phase: int, target: String, delta: int, qualifier_zh: String, qualifier_en: String, tier: String) -> void: facade.emit_battle_feedback(phase, target, delta, qualifier_zh, qualifier_en, tier)
func enter_game() -> void: facade.enter_game()
func go_home() -> void: facade.go_home()
func later_preview_supports_pair() -> bool: return facade.later_preview_supports_pair()
func member_level(slot: String) -> int: return facade.member_level(slot)
func member_slots() -> Array[String]: return facade.member_slots()
func open_adaptation() -> void: facade.open_adaptation()
func open_game_intro() -> void: facade.open_game_intro()
func open_guild_return() -> void: facade.open_guild_return()
func open_recruit_selection() -> void: facade.open_recruit_selection()
func open_route_board() -> void: facade.open_route_board()
func open_route_review() -> void: facade.open_route_review()
func open_settings() -> void: facade.open_settings()
func open_training() -> void: facade.open_training()
func open_training_review() -> void: facade.open_training_review()
func phase_duration(phase: int) -> float: return facade.phase_duration(phase)
func render() -> void: facade.render()
func request_restart() -> void: facade.request_restart()
func review_automatic_formation() -> void: facade.review_automatic_formation()
func revise_recruit_selection() -> void: facade.revise_recruit_selection()
func route_coverage_state(id: String) -> String: return facade.route_coverage_state(id)
func route_reward(id: String) -> int: return facade.route_reward(id)
func run_boot_verification() -> void: await facade.run_boot_verification()
func second_battle_event_text() -> String: return facade.second_battle_event_text()
func second_result_explanation() -> String: return facade.second_result_explanation()
func start_adventure() -> void: facade.start_adventure()
func start_new_game() -> void: facade.start_new_game()
func toggle_locale() -> void: facade.toggle_locale()
func toggle_motion() -> void: facade.toggle_motion()
func toggle_mute() -> void: facade.toggle_mute()
func toggle_recruit(profession: String) -> void: facade.toggle_recruit(profession)
func toggle_text_scale() -> void: facade.toggle_text_scale()
func tr_text(zh: String, en: String) -> String: return facade.tr_text(zh, en)
func update_battle_feedback_visual() -> void: facade.update_battle_feedback_visual()
func victory_explanation() -> String: return facade.victory_explanation()