Add title menu flow
This commit is contained in:
@@ -461,6 +461,21 @@ var top_save_button: Button
|
||||
var top_load_button: Button
|
||||
var restart_button: Button
|
||||
var new_campaign_button: Button
|
||||
var title_screen_root: Control
|
||||
var title_panel: PanelContainer
|
||||
var title_start_button: Button
|
||||
var title_load_button: Button
|
||||
var title_settings_button: Button
|
||||
var title_status_label: Label
|
||||
var title_settings_panel: PanelContainer
|
||||
var title_bgm_toggle: CheckButton
|
||||
var title_sfx_toggle: CheckButton
|
||||
var title_edge_scroll_toggle: CheckButton
|
||||
var title_settings_back_button: Button
|
||||
var title_screen_visible := false
|
||||
var title_bgm_enabled := true
|
||||
var title_sfx_enabled := true
|
||||
var title_edge_scroll_enabled := true
|
||||
var log_box: RichTextLabel
|
||||
var dialogue_queue: Array = []
|
||||
var active_dialogue_lines: Array = []
|
||||
@@ -500,17 +515,24 @@ func _ready() -> void:
|
||||
state.objective_updated.connect(_on_objective_updated)
|
||||
campaign_state.load_campaign(CAMPAIGN_PATH)
|
||||
campaign_state.load_or_start(campaign_state.get_start_scenario_id())
|
||||
if campaign_state.has_pending_post_battle_choice():
|
||||
_load_pending_post_battle_choice()
|
||||
elif campaign_state.is_campaign_complete():
|
||||
_show_campaign_complete()
|
||||
else:
|
||||
_load_current_battle()
|
||||
_show_briefing()
|
||||
if not campaign_state.is_campaign_complete():
|
||||
if campaign_state.has_pending_post_battle_choice():
|
||||
_load_scenario(campaign_state.get_pending_post_battle_choice_scenario_id())
|
||||
else:
|
||||
_load_current_battle()
|
||||
_show_title_menu()
|
||||
_update_hud()
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if _is_title_screen_visible():
|
||||
if event is InputEventKey and event.pressed and not event.echo:
|
||||
if event.keycode == KEY_ENTER:
|
||||
_on_title_start_pressed()
|
||||
elif event.keycode == KEY_ESCAPE and title_settings_panel != null and title_settings_panel.visible:
|
||||
_on_title_settings_back_pressed()
|
||||
return
|
||||
|
||||
if _is_dialogue_visible():
|
||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||
_advance_dialogue()
|
||||
@@ -2958,6 +2980,134 @@ func _create_hud() -> void:
|
||||
next_battle_button.pressed.connect(_on_next_battle_pressed)
|
||||
result_column.add_child(next_battle_button)
|
||||
|
||||
title_screen_root = Control.new()
|
||||
title_screen_root.name = "TitleScreen"
|
||||
title_screen_root.visible = false
|
||||
title_screen_root.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
title_screen_root.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
root.add_child(title_screen_root)
|
||||
|
||||
var title_dim := ColorRect.new()
|
||||
title_dim.name = "TitleInkWash"
|
||||
title_dim.color = Color(0.025, 0.016, 0.010, 0.92)
|
||||
title_dim.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
title_screen_root.add_child(title_dim)
|
||||
|
||||
title_panel = PanelContainer.new()
|
||||
title_panel.name = "TitleMenuPanel"
|
||||
title_panel.position = Vector2(286, 76)
|
||||
title_panel.size = Vector2(708, 568)
|
||||
title_panel.custom_minimum_size = Vector2(708, 568)
|
||||
_apply_panel_style(title_panel, "paper")
|
||||
title_screen_root.add_child(title_panel)
|
||||
|
||||
var title_column := VBoxContainer.new()
|
||||
title_column.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
title_column.add_theme_constant_override("separation", 10)
|
||||
title_panel.add_child(title_column)
|
||||
title_column.add_child(_make_scroll_rod(616, 5))
|
||||
title_column.add_child(_make_seal_ribbon(616, 18))
|
||||
|
||||
var title_caption := Label.new()
|
||||
title_caption.text = "영웅전"
|
||||
title_caption.custom_minimum_size = Vector2(616, 58)
|
||||
title_caption.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
title_caption.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
_apply_label_style(title_caption, UI_PARCHMENT_TEXT, 34)
|
||||
title_column.add_child(title_caption)
|
||||
|
||||
var title_subtitle := Label.new()
|
||||
title_subtitle.text = "난세의 첫 군령"
|
||||
title_subtitle.custom_minimum_size = Vector2(616, 34)
|
||||
title_subtitle.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
title_subtitle.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
_apply_label_style(title_subtitle, UI_OLD_BRONZE, 17)
|
||||
title_column.add_child(title_subtitle)
|
||||
|
||||
var title_body_panel := PanelContainer.new()
|
||||
title_body_panel.custom_minimum_size = Vector2(616, 314)
|
||||
_apply_panel_style(title_body_panel, "edict")
|
||||
title_column.add_child(title_body_panel)
|
||||
|
||||
var title_body_row := HBoxContainer.new()
|
||||
title_body_row.add_theme_constant_override("separation", 10)
|
||||
title_body_panel.add_child(title_body_row)
|
||||
title_body_row.add_child(_make_edict_marker_stack(["", "", ""], 276))
|
||||
|
||||
var title_menu_column := VBoxContainer.new()
|
||||
title_menu_column.add_theme_constant_override("separation", 10)
|
||||
title_body_row.add_child(title_menu_column)
|
||||
|
||||
title_status_label = Label.new()
|
||||
title_status_label.custom_minimum_size = Vector2(432, 60)
|
||||
title_status_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
title_status_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
title_status_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_apply_label_style(title_status_label, UI_AGED_INK, 14)
|
||||
title_menu_column.add_child(title_status_label)
|
||||
|
||||
title_start_button = Button.new()
|
||||
title_start_button.text = "처음부터 시작"
|
||||
title_start_button.custom_minimum_size = Vector2(432, 48)
|
||||
title_start_button.tooltip_text = "새 전기를 열고 첫 전장부터 시작합니다."
|
||||
title_start_button.pressed.connect(_on_title_start_pressed)
|
||||
title_menu_column.add_child(title_start_button)
|
||||
|
||||
title_load_button = Button.new()
|
||||
title_load_button.text = "게임 로드"
|
||||
title_load_button.custom_minimum_size = Vector2(432, 48)
|
||||
title_load_button.tooltip_text = "저장된 전기를 불러옵니다."
|
||||
title_load_button.pressed.connect(_on_title_load_pressed)
|
||||
title_menu_column.add_child(title_load_button)
|
||||
|
||||
title_settings_button = Button.new()
|
||||
title_settings_button.text = "환경 설정"
|
||||
title_settings_button.custom_minimum_size = Vector2(432, 48)
|
||||
title_settings_button.tooltip_text = "소리와 전장 조작 옵션을 바꿉니다."
|
||||
title_settings_button.pressed.connect(_on_title_settings_pressed)
|
||||
title_menu_column.add_child(title_settings_button)
|
||||
|
||||
title_settings_panel = PanelContainer.new()
|
||||
title_settings_panel.visible = false
|
||||
title_settings_panel.custom_minimum_size = Vector2(432, 134)
|
||||
_apply_panel_style(title_settings_panel, "hud_info")
|
||||
title_menu_column.add_child(title_settings_panel)
|
||||
|
||||
var title_settings_column := VBoxContainer.new()
|
||||
title_settings_column.add_theme_constant_override("separation", 6)
|
||||
title_settings_panel.add_child(title_settings_column)
|
||||
|
||||
title_bgm_toggle = CheckButton.new()
|
||||
title_bgm_toggle.text = "배경음"
|
||||
title_bgm_toggle.button_pressed = title_bgm_enabled
|
||||
title_bgm_toggle.tooltip_text = "배경 음악을 켜거나 끕니다."
|
||||
title_bgm_toggle.toggled.connect(_on_title_bgm_toggled)
|
||||
title_settings_column.add_child(title_bgm_toggle)
|
||||
|
||||
title_sfx_toggle = CheckButton.new()
|
||||
title_sfx_toggle.text = "효과음"
|
||||
title_sfx_toggle.button_pressed = title_sfx_enabled
|
||||
title_sfx_toggle.tooltip_text = "버튼과 전투 효과음을 켜거나 끕니다."
|
||||
title_sfx_toggle.toggled.connect(_on_title_sfx_toggled)
|
||||
title_settings_column.add_child(title_sfx_toggle)
|
||||
|
||||
title_edge_scroll_toggle = CheckButton.new()
|
||||
title_edge_scroll_toggle.text = "가장자리 스크롤"
|
||||
title_edge_scroll_toggle.button_pressed = title_edge_scroll_enabled
|
||||
title_edge_scroll_toggle.tooltip_text = "마우스를 전장 가장자리에 두면 화면을 움직입니다."
|
||||
title_edge_scroll_toggle.toggled.connect(_on_title_edge_scroll_toggled)
|
||||
title_settings_column.add_child(title_edge_scroll_toggle)
|
||||
|
||||
title_settings_back_button = Button.new()
|
||||
title_settings_back_button.text = "설정 닫기"
|
||||
title_settings_back_button.custom_minimum_size = Vector2(432, 34)
|
||||
title_settings_back_button.tooltip_text = "환경 설정을 접습니다."
|
||||
title_settings_back_button.pressed.connect(_on_title_settings_back_pressed)
|
||||
title_menu_column.add_child(title_settings_back_button)
|
||||
|
||||
title_body_row.add_child(_make_edict_marker_stack(["", "", ""], 276))
|
||||
title_column.add_child(_make_scroll_rod(616, 4))
|
||||
|
||||
for hud_button in [
|
||||
restart_button,
|
||||
new_campaign_button,
|
||||
@@ -2995,9 +3145,16 @@ func _create_hud() -> void:
|
||||
dialogue_previous_button,
|
||||
dialogue_continue_button,
|
||||
result_restart_button,
|
||||
next_battle_button
|
||||
next_battle_button,
|
||||
title_start_button,
|
||||
title_load_button,
|
||||
title_settings_button,
|
||||
title_settings_back_button
|
||||
]:
|
||||
_apply_button_style(hud_button)
|
||||
_apply_button_style(title_bgm_toggle)
|
||||
_apply_button_style(title_sfx_toggle)
|
||||
_apply_button_style(title_edge_scroll_toggle)
|
||||
_apply_button_style(briefing_start_button, true)
|
||||
|
||||
|
||||
@@ -3010,6 +3167,8 @@ func _create_audio() -> void:
|
||||
|
||||
|
||||
func _on_bgm_finished() -> void:
|
||||
if not title_bgm_enabled:
|
||||
return
|
||||
if current_bgm_key.is_empty() or bgm_player == null or bgm_player.stream == null:
|
||||
return
|
||||
bgm_player.play()
|
||||
@@ -3018,6 +3177,10 @@ func _on_bgm_finished() -> void:
|
||||
func _play_bgm(key: String) -> void:
|
||||
if bgm_player == null:
|
||||
return
|
||||
if not title_bgm_enabled:
|
||||
current_bgm_key = key
|
||||
bgm_player.stop()
|
||||
return
|
||||
if current_bgm_key == key and bgm_player.playing:
|
||||
return
|
||||
var stream := _bgm_stream_for(key)
|
||||
@@ -3038,6 +3201,8 @@ func _bgm_stream_for(key: String) -> AudioStream:
|
||||
|
||||
|
||||
func _play_sfx(key: String, volume_db := SFX_VOLUME_DB) -> void:
|
||||
if not title_sfx_enabled:
|
||||
return
|
||||
var stream := _sfx_stream_for(key)
|
||||
if stream == null:
|
||||
return
|
||||
@@ -3626,6 +3791,8 @@ func _draw_map_view_chrome() -> void:
|
||||
|
||||
|
||||
func _draw_edge_scroll_cues(view_rect: Rect2) -> void:
|
||||
if not title_edge_scroll_enabled:
|
||||
return
|
||||
if not _is_minimap_visible():
|
||||
return
|
||||
var min_offset := _clamped_board_scroll_offset(Vector2(-9999.0, -9999.0))
|
||||
@@ -6551,6 +6718,8 @@ func _edge_scroll_next_offset(current_offset: Vector2, mouse_position: Vector2,
|
||||
|
||||
|
||||
func _update_edge_scroll(delta: float) -> bool:
|
||||
if not title_edge_scroll_enabled:
|
||||
return false
|
||||
if _is_input_locked():
|
||||
return false
|
||||
var viewport := get_viewport()
|
||||
@@ -9661,6 +9830,171 @@ func _on_battle_unit_list_row_pressed(unit_id: String) -> void:
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _show_title_menu() -> void:
|
||||
title_screen_visible = true
|
||||
_play_bgm("menu")
|
||||
_clear_dialogue()
|
||||
_hide_tactic_menu()
|
||||
_hide_item_menu()
|
||||
_hide_equip_menu()
|
||||
_hide_chapter_menu()
|
||||
_hide_shop_menu()
|
||||
_hide_talk_menu()
|
||||
_hide_armory_menu()
|
||||
_hide_roster_menu()
|
||||
_hide_formation_menu()
|
||||
_hide_save_menu()
|
||||
_hide_battle_unit_list_panel()
|
||||
_clear_pending_move_state()
|
||||
if briefing_panel != null:
|
||||
briefing_panel.visible = false
|
||||
if result_panel != null:
|
||||
result_panel.visible = false
|
||||
if title_screen_root != null:
|
||||
title_screen_root.visible = true
|
||||
title_screen_root.move_to_front()
|
||||
_set_title_settings_visible(false)
|
||||
_update_title_menu_state()
|
||||
_refresh_screen_backdrop_visibility()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _hide_title_menu() -> void:
|
||||
title_screen_visible = false
|
||||
if title_screen_root != null:
|
||||
title_screen_root.visible = false
|
||||
_refresh_screen_backdrop_visibility()
|
||||
|
||||
|
||||
func _is_title_screen_visible() -> bool:
|
||||
return title_screen_visible and title_screen_root != null and title_screen_root.visible
|
||||
|
||||
|
||||
func _update_title_menu_state() -> void:
|
||||
var has_load := campaign_state.has_save() or campaign_state.has_manual_save()
|
||||
if title_load_button != null:
|
||||
title_load_button.disabled = not has_load
|
||||
title_load_button.tooltip_text = "저장된 전기를 불러옵니다." if has_load else "저장된 전기가 없습니다."
|
||||
if title_status_label != null:
|
||||
title_status_label.text = _format_title_status_text(has_load)
|
||||
if title_settings_back_button != null:
|
||||
title_settings_back_button.visible = title_settings_panel != null and title_settings_panel.visible
|
||||
if title_bgm_toggle != null:
|
||||
title_bgm_toggle.button_pressed = title_bgm_enabled
|
||||
if title_sfx_toggle != null:
|
||||
title_sfx_toggle.button_pressed = title_sfx_enabled
|
||||
if title_edge_scroll_toggle != null:
|
||||
title_edge_scroll_toggle.button_pressed = title_edge_scroll_enabled
|
||||
|
||||
|
||||
func _format_title_status_text(has_load: bool) -> String:
|
||||
if not has_load:
|
||||
return "새 전기를 열어 조조와 하후돈의 첫 군령을 시작합니다."
|
||||
var summary := campaign_state.get_manual_save_summary()
|
||||
if campaign_state.has_save():
|
||||
var title := campaign_state.get_scenario_title(campaign_state.current_scenario_id)
|
||||
if title.is_empty():
|
||||
title = campaign_state.get_scenario_title(campaign_state.get_start_scenario_id())
|
||||
return "이어 할 전기: %s · %d/%d 봉인 · %d냥" % [
|
||||
title,
|
||||
campaign_state.completed_scenarios.size(),
|
||||
campaign_state.get_scenario_count(),
|
||||
campaign_state.gold
|
||||
]
|
||||
if not summary.is_empty():
|
||||
return "수동 봉인: %s · %d/%d 봉인 · %d냥" % [
|
||||
str(summary.get("current_scenario_title", "전기")),
|
||||
int(summary.get("completed_count", 0)),
|
||||
int(summary.get("total_count", 0)),
|
||||
int(summary.get("gold", 0))
|
||||
]
|
||||
return "저장된 전기가 있습니다."
|
||||
|
||||
|
||||
func _on_title_start_pressed() -> void:
|
||||
_play_ui_confirm()
|
||||
if not campaign_state.reset_save(campaign_state.get_start_scenario_id()):
|
||||
if title_status_label != null:
|
||||
title_status_label.text = "새 전기를 열지 못했습니다. 저장 권한을 확인해 주세요."
|
||||
return
|
||||
_enter_campaign_from_title()
|
||||
|
||||
|
||||
func _on_title_load_pressed() -> void:
|
||||
if title_load_button != null and title_load_button.disabled:
|
||||
return
|
||||
_play_ui_confirm()
|
||||
var loaded := false
|
||||
if campaign_state.has_save():
|
||||
loaded = campaign_state.load_game()
|
||||
elif campaign_state.has_manual_save():
|
||||
loaded = campaign_state.load_manual_game()
|
||||
if not loaded:
|
||||
if title_status_label != null:
|
||||
title_status_label.text = "저장된 전기를 열지 못했습니다."
|
||||
_update_title_menu_state()
|
||||
return
|
||||
_enter_campaign_from_title()
|
||||
|
||||
|
||||
func _enter_campaign_from_title() -> void:
|
||||
_hide_title_menu()
|
||||
if log_box != null:
|
||||
log_box.clear()
|
||||
if campaign_state.has_pending_post_battle_choice():
|
||||
_load_pending_post_battle_choice()
|
||||
_update_result_panel()
|
||||
elif campaign_state.is_campaign_complete():
|
||||
_show_campaign_complete()
|
||||
_update_result_panel()
|
||||
else:
|
||||
_load_current_battle()
|
||||
_show_briefing()
|
||||
_update_hud()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _on_title_settings_pressed() -> void:
|
||||
_play_ui_click()
|
||||
_set_title_settings_visible(true)
|
||||
_update_title_menu_state()
|
||||
|
||||
|
||||
func _on_title_settings_back_pressed() -> void:
|
||||
_play_ui_cancel()
|
||||
_set_title_settings_visible(false)
|
||||
_update_title_menu_state()
|
||||
|
||||
|
||||
func _set_title_settings_visible(visible: bool) -> void:
|
||||
if title_settings_panel != null:
|
||||
title_settings_panel.visible = visible
|
||||
if title_settings_back_button != null:
|
||||
title_settings_back_button.visible = visible
|
||||
|
||||
|
||||
func _on_title_bgm_toggled(enabled: bool) -> void:
|
||||
title_bgm_enabled = enabled
|
||||
if title_bgm_enabled:
|
||||
_play_bgm(current_bgm_key if not current_bgm_key.is_empty() else "menu")
|
||||
elif bgm_player != null:
|
||||
bgm_player.stop()
|
||||
_update_title_menu_state()
|
||||
|
||||
|
||||
func _on_title_sfx_toggled(enabled: bool) -> void:
|
||||
title_sfx_enabled = enabled
|
||||
if title_sfx_enabled:
|
||||
_play_sfx("ui_click", UI_SFX_VOLUME_DB)
|
||||
_update_title_menu_state()
|
||||
|
||||
|
||||
func _on_title_edge_scroll_toggled(enabled: bool) -> void:
|
||||
title_edge_scroll_enabled = enabled
|
||||
_update_title_menu_state()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _update_top_archive_buttons() -> void:
|
||||
var prep_available := (
|
||||
not battle_started
|
||||
@@ -10544,6 +10878,7 @@ func _sale_price_for_item(item: Dictionary) -> int:
|
||||
func _is_input_locked() -> bool:
|
||||
return (
|
||||
campaign_complete_screen
|
||||
or _is_title_screen_visible()
|
||||
or _is_dialogue_visible()
|
||||
or _is_auto_end_turn_prompt_visible()
|
||||
or _has_active_battle_presentation_sequence()
|
||||
|
||||
Reference in New Issue
Block a user