diff --git a/scripts/scenes/battle_scene.gd b/scripts/scenes/battle_scene.gd index 4bb06b1..1874935 100644 --- a/scripts/scenes/battle_scene.gd +++ b/scripts/scenes/battle_scene.gd @@ -786,6 +786,12 @@ func _apply_button_style(button: Button, important: bool = false) -> void: _apply_control_font(button, important) +func _suppress_local_command_tooltip(button: Button) -> void: + if button == null: + return + button.tooltip_text = "" + + func _configure_hud_command_button(button: Button) -> void: if button == null: return @@ -1541,31 +1547,31 @@ func _create_hud() -> void: post_move_attack_button = Button.new() post_move_attack_button.text = "타격령" - post_move_attack_button.tooltip_text = "이 자리에서 칠 적군을 지목합니다." + _suppress_local_command_tooltip(post_move_attack_button) post_move_attack_button.pressed.connect(_on_post_move_attack_pressed) post_move_grid.add_child(post_move_attack_button) post_move_tactic_button = Button.new() post_move_tactic_button.text = "책략첩" - post_move_tactic_button.tooltip_text = "군령에 올릴 책략 죽간을 고릅니다." + _suppress_local_command_tooltip(post_move_tactic_button) post_move_tactic_button.pressed.connect(_on_post_move_tactic_pressed) post_move_grid.add_child(post_move_tactic_button) post_move_item_button = Button.new() post_move_item_button.text = "보급첩" - post_move_item_button.tooltip_text = "군령에 올릴 보급 물자를 고릅니다." + _suppress_local_command_tooltip(post_move_item_button) post_move_item_button.pressed.connect(_on_post_move_item_pressed) post_move_grid.add_child(post_move_item_button) post_move_wait_button = Button.new() post_move_wait_button.text = "대기령" - post_move_wait_button.tooltip_text = "행군을 확정하고 군령을 봉인합니다." + _suppress_local_command_tooltip(post_move_wait_button) post_move_wait_button.pressed.connect(_on_post_move_wait_pressed) post_move_grid.add_child(post_move_wait_button) post_move_cancel_button = Button.new() post_move_cancel_button.text = "발걸음 거두기" - post_move_cancel_button.tooltip_text = "처음 있던 칸으로 돌아갑니다." + _suppress_local_command_tooltip(post_move_cancel_button) post_move_cancel_button.pressed.connect(_on_post_move_cancel_pressed) post_move_column.add_child(post_move_cancel_button) @@ -1611,19 +1617,19 @@ func _create_hud() -> void: post_move_picker_back_button = Button.new() post_move_picker_back_button.text = "죽간 거두기" - post_move_picker_back_button.tooltip_text = "군령 선택으로 되돌립니다." + _suppress_local_command_tooltip(post_move_picker_back_button) post_move_picker_back_button.pressed.connect(_on_post_move_picker_back_pressed) picker_button_row.add_child(post_move_picker_back_button) post_move_picker_cancel_move_button = Button.new() post_move_picker_cancel_move_button.text = "발걸음 거두기" - post_move_picker_cancel_move_button.tooltip_text = "발걸음을 거두면 원래 자리로 되돌립니다." + _suppress_local_command_tooltip(post_move_picker_cancel_move_button) post_move_picker_cancel_move_button.pressed.connect(_on_post_move_picker_cancel_move_pressed) picker_button_row.add_child(post_move_picker_cancel_move_button) targeting_hint_panel = PanelContainer.new() targeting_hint_panel.visible = false - targeting_hint_panel.mouse_filter = Control.MOUSE_FILTER_STOP + targeting_hint_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE targeting_hint_panel.custom_minimum_size = TARGETING_HINT_PANEL_SIZE targeting_hint_panel.size = TARGETING_HINT_PANEL_SIZE _apply_panel_style(targeting_hint_panel, "target_hint") @@ -1653,13 +1659,13 @@ func _create_hud() -> void: targeting_hint_back_button = Button.new() targeting_hint_back_button.text = "죽간 거두기" - targeting_hint_back_button.tooltip_text = "군령 선택으로 되돌립니다." + _suppress_local_command_tooltip(targeting_hint_back_button) targeting_hint_back_button.pressed.connect(_on_targeting_back_pressed) targeting_button_row.add_child(targeting_hint_back_button) targeting_hint_cancel_move_button = Button.new() targeting_hint_cancel_move_button.text = "발걸음 거두기" - targeting_hint_cancel_move_button.tooltip_text = "부대를 원래 자리로 되돌립니다." + _suppress_local_command_tooltip(targeting_hint_cancel_move_button) targeting_hint_cancel_move_button.pressed.connect(_on_targeting_cancel_move_pressed) targeting_button_row.add_child(targeting_hint_cancel_move_button) @@ -9485,22 +9491,27 @@ func _update_post_move_menu() -> void: ) if post_move_attack_button != null: var attack_blocked := not _has_basic_attack_target(pending_move_unit_id) + post_move_attack_button.text = "타격 없음" if attack_blocked else "타격령" post_move_attack_button.disabled = attack_blocked - post_move_attack_button.tooltip_text = "사거리 안에 적 부대가 없습니다." if attack_blocked else "이 자리에서 칠 적군을 지목합니다." + _suppress_local_command_tooltip(post_move_attack_button) if post_move_tactic_button != null: var skill_blocked := not _unit_has_usable_skill_target(pending_move_unit_id) + post_move_tactic_button.text = "책략 없음" if skill_blocked else "책략첩" post_move_tactic_button.disabled = skill_blocked - post_move_tactic_button.tooltip_text = "이 자리에서 닿는 책략 대상이 없습니다." if skill_blocked else "군령에 올릴 책략 죽간을 고릅니다." + _suppress_local_command_tooltip(post_move_tactic_button) if post_move_item_button != null: var item_blocked := not _unit_has_usable_item_target(pending_move_unit_id) + post_move_item_button.text = "보급 없음" if item_blocked else "보급첩" post_move_item_button.disabled = item_blocked - post_move_item_button.tooltip_text = "이 자리에서 닿는 보급 대상이 없습니다." if item_blocked else "군령에 올릴 보급 물자를 고릅니다." + _suppress_local_command_tooltip(post_move_item_button) if post_move_wait_button != null: + post_move_wait_button.text = "대기령" post_move_wait_button.disabled = false - post_move_wait_button.tooltip_text = "행군을 확정하고 군령을 봉인합니다." + _suppress_local_command_tooltip(post_move_wait_button) if post_move_cancel_button != null: + post_move_cancel_button.text = "발걸음 거두기" post_move_cancel_button.disabled = false - post_move_cancel_button.tooltip_text = "발걸음을 거두면 원래 자리로 되돌립니다." + _suppress_local_command_tooltip(post_move_cancel_button) func _local_command_panel_position_for_cell(cell: Vector2i, panel_size: Vector2) -> Vector2: @@ -9674,7 +9685,7 @@ func _rebuild_post_move_tactic_picker(selected: Dictionary) -> void: skill_button.text = _format_post_move_tactic_button_text(skill_id, skill, selected) var disabled_reason := _post_move_tactic_disabled_reason(selected, skill_id, skill) skill_button.disabled = not disabled_reason.is_empty() - skill_button.tooltip_text = disabled_reason if not disabled_reason.is_empty() else "이 책략 죽간을 군령에 올립니다." + _suppress_local_command_tooltip(skill_button) _apply_button_style(skill_button) skill_button.pressed.connect(_on_post_move_tactic_option_pressed.bind(skill_id)) post_move_picker_list.add_child(skill_button) @@ -9698,7 +9709,7 @@ func _rebuild_post_move_item_picker(selected: Dictionary) -> void: _apply_item_button_icon(item_button, item) var disabled_reason := _post_move_item_disabled_reason(selected, item_id, count) item_button.disabled = not disabled_reason.is_empty() - item_button.tooltip_text = disabled_reason if not disabled_reason.is_empty() else "이 보급을 군령에 올립니다." + _suppress_local_command_tooltip(item_button) _apply_button_style(item_button) item_button.pressed.connect(_on_post_move_item_option_pressed.bind(item_id)) post_move_picker_list.add_child(item_button) diff --git a/tools/smoke_post_move_action_flow.gd b/tools/smoke_post_move_action_flow.gd index 78070c7..325bd50 100644 --- a/tools/smoke_post_move_action_flow.gd +++ b/tools/smoke_post_move_action_flow.gd @@ -12,6 +12,7 @@ func _init() -> void: _check_scene_post_move_scrolled_view_positioning(failures) _check_scene_post_move_menu_tracks_map_scroll(failures) _check_scene_post_move_text_fit(failures) + _check_scene_post_move_blocked_command_labels(failures) _check_scene_post_move_tactic_picker_flow(failures) _check_scene_post_move_item_picker_flow(failures) _check_scene_enemy_click_auto_attack(failures) @@ -105,6 +106,13 @@ func _check_scene_post_move_menu_flow(failures: Array[String]) -> void: failures.append("post-move action menu should be visible after moving") else: _check_local_panel_position(failures, scene, scene.post_move_menu, Vector2i(2, 3), "post-move action menu") + _check_local_command_button_tooltips_suppressed(failures, [ + scene.post_move_attack_button, + scene.post_move_tactic_button, + scene.post_move_item_button, + scene.post_move_wait_button, + scene.post_move_cancel_button + ], "post-move action menu") if cao_cao.get("pos", Vector2i.ZERO) != Vector2i(2, 3) or not bool(cao_cao.get("moved", false)) or bool(cao_cao.get("acted", false)): failures.append("scene move should be pending with action still available") if scene.state.get_selected_unit().is_empty(): @@ -285,6 +293,12 @@ func _check_scene_post_move_text_fit(failures: Array[String]) -> void: failures.append("post-move picker should expose a fitted detail label") else: _check_fitted_label_font(failures, scene.post_move_picker_detail_label, BattleSceneScript.LOCAL_COMMAND_DETAIL_FONT_SIZE, BattleSceneScript.LOCAL_COMMAND_DETAIL_MIN_FONT_SIZE, "post-move picker detail") + _check_local_command_button_tooltips_suppressed(failures, [ + scene.post_move_picker_back_button, + scene.post_move_picker_cancel_move_button, + scene.targeting_hint_back_button, + scene.targeting_hint_cancel_move_button + ], "local command utility buttons") scene.selected_item_id = "very_long_supply_order_marker_name" scene.selected_skill_id = "" @@ -292,6 +306,8 @@ func _check_scene_post_move_text_fit(failures: Array[String]) -> void: scene._update_targeting_hint_panel() if scene.targeting_hint_panel != null and scene.targeting_hint_panel.visible: failures.append("targeting guidance should stay on the board instead of opening a hint panel") + if scene.targeting_hint_panel != null and scene.targeting_hint_panel.mouse_filter != Control.MOUSE_FILTER_IGNORE: + failures.append("retired targeting hint panel should never block board clicks") if scene.targeting_hint_title_label == null: failures.append("targeting hint should expose a fitted title label") else: @@ -304,6 +320,52 @@ func _check_scene_post_move_text_fit(failures: Array[String]) -> void: scene.free() +func _check_scene_post_move_blocked_command_labels(failures: Array[String]) -> void: + var scene = BattleSceneScript.new() + scene._create_hud() + if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"): + failures.append("could not load opening battle for blocked command labels") + scene.free() + return + scene.battle_started = true + scene.campaign_complete_screen = false + scene.briefing_panel.visible = false + scene.result_panel.visible = false + scene._clear_pending_move_state() + scene.state.set_inventory_snapshot({}) + + var far_cell := Vector2i(scene.state.map_size.x - 2, scene.state.map_size.y - 2) + for unit in scene.state.units: + if unit.get("team", "") == BattleStateScript.TEAM_ENEMY: + unit["pos"] = far_cell + var cao_cao: Dictionary = scene.state.get_unit("cao_cao") + cao_cao["pos"] = Vector2i(1, 3) + cao_cao["mp"] = 0 + + if not scene.state.select_unit("cao_cao"): + failures.append("could not select Cao Cao for blocked command labels") + scene.free() + return + scene._refresh_ranges() + scene._handle_board_click(_screen_for_cell(Vector2i(2, 3))) + if scene.post_move_menu == null or not scene.post_move_menu.visible: + failures.append("blocked command label setup should show the post-move menu") + else: + if scene.post_move_attack_button == null or not scene.post_move_attack_button.disabled or scene.post_move_attack_button.text != "타격 없음": + failures.append("blocked attack command should explain itself through button text") + if scene.post_move_tactic_button == null or not scene.post_move_tactic_button.disabled or scene.post_move_tactic_button.text != "책략 없음": + failures.append("blocked tactic command should explain itself through button text") + if scene.post_move_item_button == null or not scene.post_move_item_button.disabled or scene.post_move_item_button.text != "보급 없음": + failures.append("blocked item command should explain itself through button text") + _check_local_command_button_tooltips_suppressed(failures, [ + scene.post_move_attack_button, + scene.post_move_tactic_button, + scene.post_move_item_button + ], "blocked post-move commands") + + scene.free() + + func _check_scene_post_move_attack_targeting(failures: Array[String]) -> void: var scene = BattleSceneScript.new() scene._create_hud() @@ -346,6 +408,8 @@ func _check_scene_post_move_attack_targeting(failures: Array[String]) -> void: scene._handle_board_click(_screen_for_cell(Vector2i(2, 3))) if not scene._has_pending_move() or scene.post_move_menu == null or not scene.post_move_menu.visible: failures.append("attack targeting setup should leave the post-move menu visible") + if scene.post_move_attack_button == null or scene.post_move_attack_button.disabled or scene.post_move_attack_button.text != "타격령": + failures.append("available attack command should stay compact and enabled") if scene.basic_attack_targeting: failures.append("attack targeting should be off before pressing Attack") if not scene.attack_cells.is_empty(): @@ -537,6 +601,7 @@ func _check_scene_post_move_tactic_picker_flow(failures: Array[String]) -> void: failures.append("post-move action menu should hide while the tactic picker is open") if scene.tactic_menu != null and scene.tactic_menu.visible: failures.append("post-move tactic shortcut should not use the side tactic menu") + _check_post_move_picker_option_tooltips_suppressed(failures, scene, "post-move tactic picker") var escape := InputEventKey.new() escape.keycode = KEY_ESCAPE @@ -645,6 +710,7 @@ func _check_scene_post_move_item_picker_flow(failures: Array[String]) -> void: failures.append("post-move action menu should hide while the item picker is open") if scene.item_menu != null and scene.item_menu.visible: failures.append("post-move item shortcut should not use the side item menu") + _check_post_move_picker_option_tooltips_suppressed(failures, scene, "post-move item picker") scene._on_post_move_item_option_pressed("bean") if scene.selected_item_id != "bean": @@ -713,6 +779,24 @@ func _check_local_panel_position(failures: Array[String], scene, panel: Control, failures.append("%s should not cover the moved unit cell: %s over %s" % [label, str(panel_rect), str(cell_rect)]) +func _check_local_command_button_tooltips_suppressed(failures: Array[String], buttons: Array, label: String) -> void: + for button in buttons: + if button == null: + failures.append("%s should expose local command buttons for tooltip checks" % label) + continue + if not str(button.tooltip_text).is_empty(): + failures.append("%s should keep guidance on the map instead of native tooltips: %s" % [label, str(button.tooltip_text)]) + + +func _check_post_move_picker_option_tooltips_suppressed(failures: Array[String], scene, label: String) -> void: + if scene.post_move_picker_list == null: + failures.append("%s should expose a picker option list" % label) + return + for child in scene.post_move_picker_list.get_children(): + if child is Button and not str(child.tooltip_text).is_empty(): + failures.append("%s option should not rely on native tooltip popups: %s" % [label, str(child.tooltip_text)]) + + func _check_fitted_label_font(failures: Array[String], label: Label, base_size: int, min_size: int, label_name: String) -> void: var font_size := label.get_theme_font_size("font_size") if font_size < min_size or font_size > base_size: